From 9de3b89b2fb2d739357ee7901f2a3ab13af60d2b Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 4 Nov 2021 13:49:26 +0100 Subject: [PATCH 001/407] iio: adc: adrv9009: Support for digital baseband DC offset tracking This patch add support to control the BBDC offset tracking. Signed-off-by: Michael Hennerich --- drivers/iio/adc/adrv9009.c | 59 ++++++++++++++++++++++++++++++++++++++ drivers/iio/adc/adrv9009.h | 1 + 2 files changed, 60 insertions(+) diff --git a/drivers/iio/adc/adrv9009.c b/drivers/iio/adc/adrv9009.c index 936f19345b8aed..366aa31cd05cb5 100644 --- a/drivers/iio/adc/adrv9009.c +++ b/drivers/iio/adc/adrv9009.c @@ -2109,6 +2109,7 @@ static ssize_t adrv9009_phy_rx_write(struct iio_dev *indio_dev, bool enable; int ret = 0; u32 mask; + u8 bbdc_en_mask; if (!phy->is_initialized) return -EBUSY; @@ -2241,6 +2242,37 @@ static ssize_t adrv9009_phy_rx_write(struct iio_dev *indio_dev, ret = -EINVAL; } break; + case RX_BBDC: + + switch (chan->channel) { + case CHAN_RX1: + mask = TAL_DC_OFFSET_RX1; + break; + case CHAN_RX2: + mask = TAL_DC_OFFSET_RX2; + break; + case CHAN_OBS_RX1: + mask = TAL_DC_OFFSET_ORX1; + break; + case CHAN_OBS_RX2: + mask = TAL_DC_OFFSET_ORX1; + break; + default: + ret = -EINVAL; + goto out; + } + + ret = TALISE_getDigDcOffsetEn(phy->talDevice, &bbdc_en_mask); + if (ret) + goto out; + + if (enable) + bbdc_en_mask |= mask; + else + bbdc_en_mask &= ~mask; + + ret = TALISE_setDigDcOffsetEn(phy->talDevice, bbdc_en_mask); + break; default: ret = -EINVAL; } @@ -2266,6 +2298,7 @@ static ssize_t adrv9009_phy_rx_read(struct iio_dev *indio_dev, int ret = 0; u16 dec_pwr_mdb; u32 mask; + u8 bbdc_en_mask; if (!phy->is_initialized) return -EBUSY; @@ -2396,12 +2429,36 @@ static ssize_t adrv9009_phy_rx_read(struct iio_dev *indio_dev, if (ret == 0) ret = sprintf(buf, "%u\n", rxGainCtrlPin.enable); break; + case RX_BBDC: + switch (chan->channel) { + case CHAN_RX1: + mask = TAL_DC_OFFSET_RX1; + break; + case CHAN_RX2: + mask = TAL_DC_OFFSET_RX2; + break; + case CHAN_OBS_RX1: + mask = TAL_DC_OFFSET_ORX1; + break; + case CHAN_OBS_RX2: + mask = TAL_DC_OFFSET_ORX1; + break; + default: + ret = -EINVAL; + goto out; + } + + ret = TALISE_getDigDcOffsetEn(phy->talDevice, &bbdc_en_mask); + if (!ret) + ret = sprintf(buf, "%d\n", !!(mask & bbdc_en_mask)); + break; default: ret = -EINVAL; } +out: mutex_unlock(&indio_dev->mlock); return ret; @@ -2614,6 +2671,7 @@ static const struct iio_chan_spec_ext_info adrv9009_phy_rx_ext_info[] = { IIO_ENUM("gain_control_mode", false, &adrv9009_agc_modes_available), _ADRV9009_EXT_RX_INFO("rssi", RSSI), _ADRV9009_EXT_RX_INFO("quadrature_tracking_en", RX_QEC), + _ADRV9009_EXT_RX_INFO("bb_dc_offset_tracking_en", RX_BBDC), _ADRV9009_EXT_RX_INFO("hd2_tracking_en", RX_HD2), /* 2nd Harmonic Distortion */ _ADRV9009_EXT_RX_INFO("rf_bandwidth", RX_RF_BANDWIDTH), _ADRV9009_EXT_RX_INFO("powerdown", RX_POWERDOWN), @@ -2629,6 +2687,7 @@ static const struct iio_chan_spec_ext_info adrv9009_phy_obs_rx_ext_info[] = { IIO_ENUM_AVAILABLE_SHARED("rf_port_select", 0, &adrv9009_rf_obs_rx_port_available), IIO_ENUM("rf_port_select", false, &adrv9009_rf_obs_rx_port_available), _ADRV9009_EXT_RX_INFO("quadrature_tracking_en", RX_QEC), + _ADRV9009_EXT_RX_INFO("bb_dc_offset_tracking_en", RX_BBDC), _ADRV9009_EXT_RX_INFO("rf_bandwidth", RX_RF_BANDWIDTH), _ADRV9009_EXT_RX_INFO("powerdown", RX_POWERDOWN), { }, diff --git a/drivers/iio/adc/adrv9009.h b/drivers/iio/adc/adrv9009.h index b2b3ca9c000177..c46314a356f400 100644 --- a/drivers/iio/adc/adrv9009.h +++ b/drivers/iio/adc/adrv9009.h @@ -53,6 +53,7 @@ enum adrv9009_bist_mode { enum adrv9009_rx_ext_info { RSSI, RX_QEC, + RX_BBDC, RX_HD2, RX_RF_BANDWIDTH, RX_POWERDOWN, From 68664910d1d251825b2313fc3c76bdfda70e3907 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Fri, 5 Nov 2021 17:46:59 +0200 Subject: [PATCH 002/407] dts: zynqmp-adrv9009-zu11eg-reva-adrv2crr-fmc-reva: Add input for AD9545 Add input node for Ref A (10 Mhz). PLL0 will lock on it if available otherwise will just run based on the Aux. NCO. OUT 0A will give 30.72 Mhz, Signed-off-by: Alexandru Tachici --- ...adrv9009-zu11eg-reva-adrv2crr-fmc-reva.dts | 64 ++++++++++++++----- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva-adrv2crr-fmc-reva.dts b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva-adrv2crr-fmc-reva.dts index 71e71cecfa9852..caac900a2957f9 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva-adrv2crr-fmc-reva.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva-adrv2crr-fmc-reva.dts @@ -49,6 +49,14 @@ #include / { + ref_clk0: ref_clk_0 { + compatible = "fixed-clock"; + #clock-cells = <1>; + + clock-frequency = <10000000>; + clock-output-names = "Ref-A"; + }; + leds { compatible = "gpio-leds"; led0 { @@ -329,13 +337,15 @@ adi,ref-crystal; adi,ref-frequency-hz = <49152000>; + clock-names = "Ref-A"; + clocks = <&ref_clk0 0>; + #clock-cells = <2>; assigned-clocks = <&ad9545_clock AD9545_CLK_NCO AD9545_NCO0>, - <&ad9545_clock AD9545_CLK_PLL AD9545_PLL1>, - <&ad9545_clock AD9545_CLK_OUT AD9545_Q1A>, - <&ad9545_clock AD9545_CLK_OUT AD9545_Q1AA>; - assigned-clock-rates = <10000>, <1875000000>, <156250000>, <156250000>; + <&ad9545_clock AD9545_CLK_PLL AD9545_PLL0>, + <&ad9545_clock AD9545_CLK_OUT AD9545_Q0A>; + assigned-clock-rates = <10000>, <1413120000>, <30720000>; assigned-clock-phases = <0>, <0>, <0>, <180>; aux-nco-clk@AD9545_NCO0 { @@ -344,24 +354,48 @@ adi,phase-lock-threshold-ps = <16000000>; }; - ad9545_apll1: pll-clk@AD9545_PLL1 { - reg = ; - adi,pll-source = <4>; - adi,pll-loop-bandwidth-hz = <200>; + /* Ref A (J4) 10Mhz input */ + ref-input-clk@0 { + reg = <0>; + adi,single-ended-mode = ; + adi,r-divider-ratio = <200>; + adi,ref-dtol-pbb = <10000000>; + adi,ref-monitor-hysteresis-pbb = <87500>; + adi,ref-validation-timer-ms = <1>; + adi,freq-lock-threshold-ps = <0xFFFFFF>; + adi,phase-lock-threshold-ps = <0xFFFFFF>; + adi,freq-lock-fill-rate = <20>; + adi,freq-lock-drain-rate = <20>; + adi,phase-lock-fill-rate = <20>; + adi,phase-lock-drain-rate = <20>; }; - output-clk@AD9545_Q1A { - reg = ; - adi,output-mode = ; - adi,current-source-microamp = <15000>; + ad9545_apll0: pll-clk@AD9545_PLL0 { + reg = ; + + #address-cells = <1>; + #size-cells = <0>; + + profile@0 { + reg = <0>; + adi,pll-source = <4>; + adi,profile-priority = <20>; + adi,pll-loop-bandwidth-uhz = <200000000>; + }; + + profile@1 { + reg = <1>; + adi,pll-source = <0>; + adi,profile-priority = <0>; + adi,pll-loop-bandwidth-uhz = <200000000>; + }; }; - output-clk@AD9545_Q1AA { - reg = ; + output-clk@AD9545_Q0A { + reg = ; adi,output-mode = ; adi,current-source-microamp = <15000>; }; - }; }; From 7e2c494d1d00d78c4f651daac5629b64e068b6b3 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 3 Nov 2021 14:33:12 +0100 Subject: [PATCH 003/407] iio: adc: ad9081: Update API to Version 1.2.0 * Fix DAC Calibration for DAC rates <4GHz to address Noise Floor Issue * Address ADC with 12 Bit resolution * Enable Background Cal when calling JESD 204C Calibration * Allow user to set nyquist Zone per ADC * Added controls for sysref input receiver configuration Signed-off-by: Michael Hennerich --- drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad9081.c | 157 +++-- drivers/iio/adc/ad9081/adi_ad9081.h | 355 +++++++--- drivers/iio/adc/ad9081/adi_ad9081_adc.c | 124 +++- drivers/iio/adc/ad9081/adi_ad9081_config.h | 720 +++++++++++++++++++- drivers/iio/adc/ad9081/adi_ad9081_dac.c | 289 ++++++-- drivers/iio/adc/ad9081/adi_ad9081_device.c | 49 +- drivers/iio/adc/ad9081/adi_ad9081_hal.c | 17 - drivers/iio/adc/ad9081/adi_ad9081_hal.h | 36 +- drivers/iio/adc/ad9081/adi_ad9081_jesd.c | 127 +--- drivers/iio/adc/ad9081/adi_ad9081_sync.c | 401 +++++++++++ drivers/iio/adc/ad9081/adi_cms_api_common.h | 17 +- 12 files changed, 1882 insertions(+), 411 deletions(-) create mode 100644 drivers/iio/adc/ad9081/adi_ad9081_sync.c diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 5a195cea8b987e..5da2d56092c57f 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -52,6 +52,7 @@ ad9081_drv-y := ad9081.o \ ad9081/adi_ad9081_device.o \ ad9081/adi_ad9081_jesd.o \ ad9081/adi_ad9081_hal.o \ + ad9081/adi_ad9081_sync.o \ ad9081/adi_ad9081_dac.o obj-$(CONFIG_AD9081) += ad9081_drv.o diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 3304ec770ac69d..6512837f6073cb 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -171,6 +171,7 @@ struct ad9081_phy { bool nco_sync_direct_sysref_mode_en; u32 sysref_average_cnt_exp; bool sysref_continuous_dis; + bool sysref_coupling_ac_en; bool config_sync_01_swapped; bool config_sync_0a_cmos_en; @@ -205,7 +206,7 @@ struct ad9081_phy { s32 rx_fddc_phase[MAX_NUM_CHANNELIZER]; s32 rx_cddc_phase[MAX_NUM_MAIN_DATAPATHS]; - u32 rx_nyquist_zone; + u32 rx_nyquist_zone[MAX_NUM_MAIN_DATAPATHS]; u8 rx_cddc_c2r[MAX_NUM_MAIN_DATAPATHS]; u8 rx_cddc_gain_6db_en[MAX_NUM_MAIN_DATAPATHS]; u8 rx_fddc_gain_6db_en[MAX_NUM_CHANNELIZER]; @@ -833,48 +834,6 @@ static const struct iio_enum ad9081_testmode_enum = { .get = ad9081_testmode_read, }; -static int ad9081_nyquist_zone_read(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev); - struct ad9081_phy *phy = conv->phy; - - return phy->rx_nyquist_zone; -} - -static int ad9081_nyquist_zone_write(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - unsigned int item) -{ - struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev); - struct ad9081_phy *phy = conv->phy; - int ret; - - mutex_lock(&indio_dev->mlock); - - ret = adi_ad9081_adc_nyquist_zone_set(&phy->ad9081, item); - if (ret != 0) - return ret; - - if (!ret) - phy->rx_nyquist_zone = item; - mutex_unlock(&indio_dev->mlock); - - return ret; -} - -static const char *const ad9081_adc_nyquist_zones[] = { - [AD9081_ADC_NYQUIST_ZONE_ODD] = "odd", - [AD9081_ADC_NYQUIST_ZONE_EVEN] = "even", -}; - -static const struct iio_enum ad9081_nyquist_zone_enum = { - .items = ad9081_adc_nyquist_zones, - .num_items = ARRAY_SIZE(ad9081_adc_nyquist_zones), - .set = ad9081_nyquist_zone_write, - .get = ad9081_nyquist_zone_read, -}; - int ad9081_iio_val_to_str(char *buf, u32 max, int val) { int vals[2]; @@ -952,6 +911,52 @@ static void ad9081_iiochan_to_fddc_cddc(struct ad9081_phy *phy, *fddc_num, *fddc_mask, *cddc_num, *cddc_mask); } +static int ad9081_nyquist_zone_read(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev); + struct ad9081_phy *phy = conv->phy; + u8 cddc_num, cddc_mask, fddc_num, fddc_mask; + + ad9081_iiochan_to_fddc_cddc(phy, chan, &fddc_num, + &fddc_mask, &cddc_num, &cddc_mask); + + return phy->rx_nyquist_zone[cddc_num]; +} + +static int ad9081_nyquist_zone_write(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int item) +{ + struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev); + struct ad9081_phy *phy = conv->phy; + u8 cddc_num, cddc_mask, fddc_num, fddc_mask; + int ret; + + ad9081_iiochan_to_fddc_cddc(phy, chan, &fddc_num, + &fddc_mask, &cddc_num, &cddc_mask); + + mutex_lock(&indio_dev->mlock); + ret = adi_ad9081_adc_nyquist_zone_set(&phy->ad9081, cddc_mask, item); + if (!ret) + phy->rx_nyquist_zone[cddc_num] = item; + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static const char *const ad9081_adc_nyquist_zones[] = { + [AD9081_ADC_NYQUIST_ZONE_ODD] = "odd", + [AD9081_ADC_NYQUIST_ZONE_EVEN] = "even", +}; + +static const struct iio_enum ad9081_nyquist_zone_enum = { + .items = ad9081_adc_nyquist_zones, + .num_items = ARRAY_SIZE(ad9081_adc_nyquist_zones), + .set = ad9081_nyquist_zone_write, + .get = ad9081_nyquist_zone_read, +}; + static ssize_t ad9081_ext_info_read(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, char *buf) @@ -1340,7 +1345,7 @@ static ssize_t ad9081_ext_info_write(struct iio_dev *indio_dev, static struct iio_chan_spec_ext_info rxadc_ext_info[] = { IIO_ENUM("test_mode", IIO_SHARED_BY_TYPE, &ad9081_testmode_enum), IIO_ENUM_AVAILABLE("test_mode", &ad9081_testmode_enum), - IIO_ENUM("nyquist_zone", IIO_SHARED_BY_TYPE, &ad9081_nyquist_zone_enum), + IIO_ENUM("nyquist_zone", IIO_SEPARATE, &ad9081_nyquist_zone_enum), IIO_ENUM_AVAILABLE("nyquist_zone", &ad9081_nyquist_zone_enum), { .name = "main_nco_frequency", @@ -1753,8 +1758,9 @@ static int ad9081_setup(struct spi_device *spi) if (ret != 0) return ret; - /* AC couple SYSREF */ - ret = adi_ad9081_jesd_sysref_input_mode_set(&phy->ad9081, 0); + /* DC couple SYSREF */ + ret = adi_ad9081_jesd_sysref_input_mode_set(&phy->ad9081, 1, 1, + phy->sysref_coupling_ac_en ? COUPLING_AC : COUPLING_DC); if (ret != 0) return ret; @@ -1851,6 +1857,11 @@ static int ad9081_setup(struct spi_device *spi) &phy->ad9081, BIT(i), phy->rx_cddc_gain_6db_en[i]); if (ret != 0) return ret; + + ret = adi_ad9081_adc_nyquist_zone_set(&phy->ad9081, BIT(i), + phy->rx_nyquist_zone[i]); + if (ret != 0) + return ret; } for_each_fddc(i, phy->rx_fddc_select) { @@ -1962,15 +1973,9 @@ static int ad9081_setup(struct spi_device *spi) phy->tx_main_interp * phy->tx_chan_interp); clk_set_rate(phy->clks[TX_SAMPL_CLK], sample_rate); - ret = adi_ad9081_adc_nyquist_zone_set(&phy->ad9081, - phy->rx_nyquist_zone); - if (ret != 0) - return ret; - - for (i = 0; i < ARRAY_SIZE(phy->tx_dac_fsc); i++) { if (phy->tx_dac_fsc[i]) { - ret = adi_ad9081_dac_fsc_set(&phy->ad9081, BIT(i), phy->tx_dac_fsc[i]); + ret = adi_ad9081_dac_fsc_set(&phy->ad9081, BIT(i), phy->tx_dac_fsc[i], 1); if (ret != 0) return ret; } @@ -1995,7 +2000,7 @@ static int ad9081_multichip_sync(struct ad9081_phy *phy, int step) jesd204_fsm_clear_errors(phy->jdev, JESD204_LINKS_ALL); return jesd204_fsm_start(phy->jdev, JESD204_LINKS_ALL); case 20: - return adi_ad9081_jesd_rx_calibrate_204c(&phy->ad9081, 1, 0, 0); + return adi_ad9081_jesd_rx_calibrate_204c(&phy->ad9081, 1, 0, 1); default: return -EINVAL; } @@ -2616,7 +2621,7 @@ static int ad9081_fsc_set(void *arg, const u64 val) return -EINVAL; mutex_lock(&indio_dev->mlock); - ret = adi_ad9081_dac_fsc_set(&phy->ad9081, AD9081_DAC_ALL, val); + ret = adi_ad9081_dac_fsc_set(&phy->ad9081, AD9081_DAC_ALL, val, 1); mutex_unlock(&indio_dev->mlock); return ret; @@ -3559,7 +3564,7 @@ static int ad9081_parse_dt_rx(struct ad9081_phy *phy, struct device_node *np) { struct device_node *of_channels, *of_chan; struct device_node *of_trx_path; - u32 reg; + u32 reg, tmp, nz; int i = 0, ret; /* The 4 ADC Main Datapaths */ @@ -3571,8 +3576,7 @@ static int ad9081_parse_dt_rx(struct ad9081_phy *phy, struct device_node *np) of_property_read_u64(of_trx_path, "adi,adc-frequency-hz", &phy->adc_frequency_hz); - of_property_read_u32(of_trx_path, "adi,nyquist-zone", - &phy->rx_nyquist_zone); + of_property_read_u32(of_trx_path, "adi,nyquist-zone", &nz); /* The 4 DAC Main Datapaths */ @@ -3595,6 +3599,12 @@ static int ad9081_parse_dt_rx(struct ad9081_phy *phy, struct device_node *np) phy->rx_cddc_gain_6db_en[reg] = of_property_read_bool( of_chan, "adi,digital-gain-6db-enable"); phy->rx_cddc_select |= BIT(reg); + ret = of_property_read_u32(of_trx_path, + "adi,nyquist-zone", &tmp); + if (!ret) + phy->rx_nyquist_zone[reg] = tmp; + else + phy->rx_nyquist_zone[reg] = nz; } } @@ -3688,6 +3698,9 @@ static int ad9081_parse_dt(struct ad9081_phy *phy, struct device *dev) of_property_read_u32(np, "adi,sysref-average-cnt-exp", &phy->sysref_average_cnt_exp); + phy->sysref_coupling_ac_en = of_property_read_bool(np, + "adi,sysref-ac-coupling-enable"); + phy->sysref_continuous_dis = of_property_read_bool(np, "adi,continuous-sysref-mode-disable"); @@ -3959,7 +3972,7 @@ static int ad9081_jesd204_clks_enable(struct jesd204_dev *jdev, dev_info(dev, "running jesd_rx_calibrate_204c, LR %lu kbps", phy->jrx_link_tx[0].lane_rate_kbps); - ret = adi_ad9081_jesd_rx_calibrate_204c(&phy->ad9081, 1, 0, 0); + ret = adi_ad9081_jesd_rx_calibrate_204c(&phy->ad9081, 1, 0, 1); if (ret < 0) return ret; @@ -4066,6 +4079,7 @@ static int ad9081_jesd204_setup_stage1(struct jesd204_dev *jdev, struct device *dev = jesd204_dev_to_device(jdev); struct ad9081_jesd204_priv *priv = jesd204_dev_priv(jdev); struct ad9081_phy *phy = priv->phy; + adi_cms_jesd_subclass_e subclass = JESD_SUBCLASS_0; int ret; if (reason != JESD204_STATE_OP_REASON_INIT) @@ -4091,10 +4105,29 @@ static int ad9081_jesd204_setup_stage1(struct jesd204_dev *jdev, if (ret != 0) return ret; - ret = adi_ad9081_jesd_oneshot_sync(&phy->ad9081); + if (phy->jrx_link_tx[0].jesd_param.jesd_subclass || + phy->jtx_link_rx[0].jesd_param.jesd_subclass) + subclass = JESD_SUBCLASS_1; + + + ret = adi_ad9081_jesd_oneshot_sync(&phy->ad9081, subclass); if (ret != 0) return ret; + if (phy->sysref_continuous_dis) { + u8 sync_done; + + ad9081_sysref_ctrl(&phy->ad9081, 1); + + ret = adi_ad9081_jesd_sysref_oneshot_sync_done_get(&phy->ad9081, + &sync_done); + if (ret != 0) + return ret; + + if (sync_done != 1) + return JESD204_STATE_CHANGE_ERROR; + } + ret = adi_ad9081_hal_bf_set(&phy->ad9081, REG_SYNC_DEBUG0_ADDR, BF_AVRG_FLOW_EN_INFO, 0); if (ret != 0) @@ -4253,7 +4286,6 @@ static int ad9081_probe(struct spi_device *spi) phy->ad9081.hal_info.reset_pin_ctrl = ad9081_reset_pin_ctrl; phy->ad9081.hal_info.user_data = conv; phy->ad9081.hal_info.log_write = ad9081_log_write; - phy->ad9081.hal_info.sysref_ctrl = ad9081_sysref_ctrl; phy->ad9081.serdes_info = (adi_ad9081_serdes_settings_t) { .ser_settings = { /* txfe jtx */ @@ -4335,9 +4367,6 @@ static int ad9081_probe(struct spi_device *spi) return -ENODEV; } - if (!conv->reset_gpio) - adi_ad9081_hal_delay_us(&phy->ad9081, 20000); - ret = adi_ad9081_device_chip_id_get(&phy->ad9081, &phy->chip_id); if (ret < 0) { dev_err(&spi->dev, "chip_id failed (%d)\n", ret); diff --git a/drivers/iio/adc/ad9081/adi_ad9081.h b/drivers/iio/adc/ad9081/adi_ad9081.h index eff0c9aacf0038..c78207c58df850 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081.h +++ b/drivers/iio/adc/ad9081/adi_ad9081.h @@ -290,21 +290,6 @@ /*============= ENUMS ==============*/ -/*! - * @brief Enumerates Chip Output Resolution - */ -typedef enum { - AD9081_CHIP_OUT_RES_16BIT = 0x0, /*!< 16Bit */ - AD9081_CHIP_OUT_RES_15BIT = 0x1, /*!< 15Bit */ - AD9081_CHIP_OUT_RES_14BIT = 0x2, /*!< 14Bit */ - AD9081_CHIP_OUT_RES_13BIT = 0x3, /*!< 13Bit */ - AD9081_CHIP_OUT_RES_12BIT = 0x4, /*!< 12Bit */ - AD9081_CHIP_OUT_RES_11BIT = 0x5, /*!< 11Bit */ - AD9081_CHIP_OUT_RES_10BIT = 0x6, /*!< 10Bit */ - AD9081_CHIP_OUT_RES_09BIT = 0x7, /*!< 9Bit */ - AD9081_CHIP_OUT_RES_08BIT = 0x8 /*!< 8Bit */ -} adi_ad9081_chip_output_res_e; - /*! * @brief Enumerates DAC Select */ @@ -318,7 +303,7 @@ typedef enum { } adi_ad9081_dac_select_e; /*! - * @brief Enumerates DAC Channel Select + * @brief Enumerates DAC Channel / Fine DUC Datapath Select */ typedef enum { AD9081_DAC_CH_NONE = 0x00, /*!< No Channel */ @@ -334,27 +319,40 @@ typedef enum { } adi_ad9081_dac_channel_select_e; /*! - * @brief Enumerates DAC Mode Switch Group Select + * @brief Enumerates Main DAC Datapth / Coarse DUC Datapath Select + */ +typedef enum { + AD9081_DAC_DP_NONE = 0x0, /*!< No Coarse DUC /No Main DAC Datapath */ + AD9081_DAC_DP_0 = 0x1, /*!< Coarse DUC 0/ Main DAC0 Datapath */ + AD9081_DAC_DP_1 = 0x2, /*!< Coarse DUC 1/ Main DAC1 Datapath */ + AD9081_DAC_DP_2 = 0x4, /*!< Coarse DUC 2/ Main DAC2 Datapath */ + AD9081_DAC_DP_3 = 0x8, /*!< Coarse DUC 3/ Main DAC3 Datapath */ + AD9081_DAC_DP_ALL = 0x0F /*!< ALL Coarse DUC /ALL Main DAC Datapths */ +} adi_ad9081_dac_dp_select_e; + +/*! + * @brief Enumerates DAC PAIRING for DAC mode Configuration */ typedef enum { - AD9081_DAC_MODE_SWITCH_GROUP_NONE = 0x00, /*!< No Group */ - AD9081_DAC_MODE_SWITCH_GROUP_0 = 0x01, /*!< Group 0 (DAC0 & DAC1) */ - AD9081_DAC_MODE_SWITCH_GROUP_1 = 0x02, /*!< Group 1 (DAC2 & DAC3) */ - AD9081_DAC_MODE_SWITCH_GROUP_ALL = 0x03, /*!< All Groups */ -} adi_ad9081_dac_mode_switch_group_select_e; + AD9081_DAC_PAIR_NONE = 0x00, /*!< No Group */ + AD9081_DAC_PAIR_0_1 = 0x01, /*!< Group 0 (DAC0 & DAC1) */ + AD9081_DAC_PAIR_2_3 = 0x02, /*!< Group 1 (DAC2 & DAC3) */ + AD9081_DAC_PAIR_ALL = 0x03, /*!< All Groups */ +} adi_ad9081_dac_pair_select_e; /*! - * @brief Enumerates DAC Mode Select + * @brief Enumerates DAC PAIR CDUC I/Q Data to DAC Core Modulation Mux Routing modes */ typedef enum { - AD9081_DAC_MODE_0 = 0x00, /*!< I0.Q0 -> DAC0, I1.Q1 -> DAC1 */ - AD9081_DAC_MODE_1 = + AD9081_DAC_MUX_MODE_0 = + 0x00, /*!< I0.Q0 -> DAC0, Complex I1.Q1 -> DAC1 */ + AD9081_DAC_MUX_MODE_1 = 0x01, /*!< (I0 + I1) / 2 -> DAC0, (Q0 + Q1) / 2 -> DAC1, Data Path NCOs Bypassed */ - AD9081_DAC_MODE_2 = + AD9081_DAC_MUX_MODE_2 = 0x02, /*!< I0 -> DAC0, Q0 -> DAC1, Datapath0 NCO Bypassed, Datapath1 Unused */ - AD9081_DAC_MODE_3 = + AD9081_DAC_MUX_MODE_3 = 0x03, /*!< (I0 + I1) / 2 -> DAC0, DAC1 Output Tied To Midscale */ -} adi_ad9081_dac_mode_e; +} adi_ad9081_dac_mod_mux_mode_e; /*! * @brief Enumerates ADC Select @@ -767,7 +765,9 @@ typedef struct { typedef struct { adi_ad9081_ser_lane_settings_t lane_settings[8]; uint8_t invert_mask; - uint8_t lane_mapping[2][8]; + uint8_t lane_mapping + [2] + [8]; /*Deserialise Lane Mapping, Map Virtual Converter to Physical Lane, index is physical, value is logical lane*/ } adi_ad9081_ser_settings_t; /*! @@ -780,7 +780,7 @@ typedef struct { [8]; /*Equaliser CTLE Filter Selection, Range 0 - 4, based on Jesd IL, Pick lower setting for Higher Insertion loss*/ uint8_t lane_mapping [2] - [8]; /*Deserialise Lane Mapping, Map Virtual Converter to Physical Lane*/ + [8]; /*Deserialise Lane Mapping, Map Virtual Converter to Physical Lane, index is logical lane, value is physical lane*/ } adi_ad9081_des_settings_t; /*! @@ -840,8 +840,6 @@ typedef struct { tx_en_pin_ctrl; /*!< Function pointer to hal tx_enable pin control function */ adi_reset_pin_ctrl_t reset_pin_ctrl; /*!< Function pointer to hal reset# pin control function */ - adi_sysref_ctrl_t - sysref_ctrl; /*!< Function pointer to hal sysref control function */ } adi_ad9081_hal_t; /*! @@ -1132,7 +1130,7 @@ int32_t adi_ad9081_device_main_auto_clk_gen_enable(adi_ad9081_device_t *device, /*===== 2 . 0 T R A N S M I T P A T H S E T U P =====*/ /** - * @ingroup tx_setup + * @ingroup tx_data_path_setup * @brief System Top Level API. \n Startup Tx As NCO Test Mode * This API will be called after adi_ad9081_device_clk_config_set(). * @@ -1154,7 +1152,7 @@ adi_ad9081_device_startup_nco_test(adi_ad9081_device_t *device, int64_t chan_shift[8], uint16_t dc_offset); /** - * @ingroup tx_setup + * @ingroup tx_data_path_setup * @brief System Top Level API. \n Startup Tx * This API will be called after adi_ad9081_device_clk_config_set(). * @@ -1176,7 +1174,7 @@ int32_t adi_ad9081_device_startup_tx(adi_ad9081_device_t *device, adi_cms_jesd_param_t *jesd_param); /** - * @ingroup tx_setup + * @ingroup tx_data_path_setup * @brief System Top Level API. \n Set Fine DUC gain * Call after adi_ad9081_device_startup_tx(). * @@ -1190,25 +1188,42 @@ int32_t adi_ad9081_dac_duc_nco_gains_set(adi_ad9081_device_t *device, uint16_t gains[8]); /** - * @ingroup tx_setup - * @brief System Top Level API. \n Set DAC working mode + * @ingroup tx_data_path_setup + * @brief System Top Level API. \n + * Set DAC Data source Mux mode. * Call after adi_ad9081_device_startup_tx() * * @param device Pointer to the device structure - * @param groups Mode switch groups, @see adi_ad9081_dac_mode_switch_group_select_e + * @param dac_pair DAC Pair Select for mode configuration @see adi_ad9081_dac_pair_select_e * @param mode Working mode, @see adi_ad9081_dac_mode_e * * @return API_CMS_ERROR_OK API Completed Successfully * @return <0 Failed. @see adi_cms_error_e for details. */ int32_t -adi_ad9081_dac_mode_set(adi_ad9081_device_t *device, - adi_ad9081_dac_mode_switch_group_select_e groups, - adi_ad9081_dac_mode_e mode); +adi_ad9081_dac_modulation_mux_mode_set(adi_ad9081_device_t *device, + adi_ad9081_dac_pair_select_e dac_pair, + adi_ad9081_dac_mod_mux_mode_e mode); + +/** + * @ingroup tx_data_path_setup + * @brief Set DAC complex modulation enable + * Call after adi_ad9081_device_startup_tx() + * + * @param device Pointer to the device structure + * @param groups Mode switch groups, @see adi_ad9081_dac_pair_select_e + * @param enable 1 to enable complex modulation + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_dac_complex_modulation_enable_set( + adi_ad9081_device_t *device, adi_ad9081_dac_pair_select_e dac_pair, + uint8_t enable); /*===== 2 . 1 T R A N S M I T T X E N =====*/ /** - * @ingroup tx_txen_setup + * @ingroup tx_transmit_en_setup * @brief Set TXEN State Machine Enable * * @param device Pointer to the device structure @@ -1223,7 +1238,7 @@ adi_ad9081_dac_tx_enable_state_machine_enable_set(adi_ad9081_device_t *device, uint8_t dacs, uint8_t enable); /** - * @ingroup tx_txen_setup + * @ingroup tx_transmit_en_setup * @brief Enable SPI as TXEN Control * * @param device Pointer to the device structure @@ -1237,7 +1252,7 @@ int32_t adi_ad9081_dac_spi_as_tx_en_set(adi_ad9081_device_t *device, uint8_t dacs, uint8_t enable); /** - * @ingroup tx_txen_setup + * @ingroup tx_transmit_en_setup * @brief Block Top Level API. \n Set Enable on DAC outputs * Call after adi_ad9081_device_startup_tx(). * @@ -1252,7 +1267,7 @@ int32_t adi_ad9081_dac_tx_enable_set(adi_ad9081_device_t *device, uint8_t dacs, uint8_t enable); /** - * @ingroup tx_txen_setup + * @ingroup tx_transmit_en_setup * @brief Enable/Disable GPIOs Input For Tx Enable Control * * @param device Pointer to the device structure @@ -1289,12 +1304,13 @@ int32_t adi_ad9081_dac_power_up_set(adi_ad9081_device_t *device, uint8_t dacs, * @param device Pointer to the device structure * @param dacs Target DAC Channel to enable data output * @param uA Desired current value in uA + * @param rerun_cal Paramter to rerun dac cals after fsc change (recommended) * * @return API_CMS_ERROR_OK API Completed Successfully * @return <0 Failed. @see adi_cms_error_e for details. */ int32_t adi_ad9081_dac_fsc_set(adi_ad9081_device_t *device, uint8_t dacs, - uint32_t uA); + uint32_t uA, uint8_t rerun_cal); /*===== 2 . 3 T R A N S M I T C H A N N E L I Z E R G A I N =====*/ /** @@ -1331,8 +1347,14 @@ int32_t adi_ad9081_dac_interpolation_set(adi_ad9081_device_t *device, /** * @ingroup tx_dp_setup - * @brief Block Top Level API. \n Set Main DAC to Channel Xbar - * Call after adi_ad9081_device_startup_tx(). + * @brief Block Top Level API. \n + * Manually Set Main DAC to Channel Xbar + * adi_ad9081_device_startup_tx(), Sets the DAC to Channel xbar based on channel interpolation + * For Channel Bypass Modes where CH interpolation is 1, use this + * API to mux IQ data pairs to the DACs + * Refer to 4X4 Cross Bar in SDUG + * Note This mux as a dependancy on channel interpolation, Call this API after + * adi_ad9081_device_startup_tx or adi_ad9081_dac_interpolation_set * * @param device Pointer to the device structure * @param dacs Target DAC Channel Output @@ -1410,22 +1432,6 @@ int32_t adi_ad9081_dac_duc_nco_enable_set(adi_ad9081_device_t *device, uint8_t dacs, uint8_t channels, uint8_t enable); -/** - * @ingroup tx_nco_setup - * @brief Set DAC complex modulation enable - * Call after adi_ad9081_device_startup_tx() - * - * @param device Pointer to the device structure - * @param groups Mode switch groups, @see adi_ad9081_dac_mode_switch_group_select_e - * @param enable 1 to enable complex modulation - * - * @return API_CMS_ERROR_OK API Completed Successfully - * @return <0 Failed. @see adi_cms_error_e for details. - */ -int32_t adi_ad9081_dac_complex_modulation_enable_set( - adi_ad9081_device_t *device, - adi_ad9081_dac_mode_switch_group_select_e groups, uint8_t enable); - /** * @ingroup tx_nco_setup * @brief Reset NCO @@ -2005,16 +2011,24 @@ int32_t adi_ad9081_jesd_tx_fbw_sel_set(adi_ad9081_device_t *device, /** * @ingroup rx_setup - * @brief System Top Level API. \n Set ADC Nyquist Zone + * @brief System Top Level API. \n Set Nyquist Zone operation for each ADC + * Required for correct ADC background Cal operation. See SDUG for more information + * Nyquist Zone = ROUNDDOWN�(fIN/(fADC/2)) + 1 * Call after adi_ad9081_device_startup_rx(). * + * * @param device Pointer to the device structure - * @param zone AD9081_ADC_NYQUIST_ZONE_ODD / AD9081_ADC_NYQUIST_ZONE_EVEN + * @param adc_sel Masked list of ADC, as defined by adi_ad9081_adc_sel_e to be assign nyquist zone as described by zone parameter + * @param zone Desired nyquist zone operation for the adcs specified by adc_sel parameter. + * AD9081_ADC_NYQUIST_ZONE_ODD + * AD9081_ADC_NYQUIST_ZONE_EVEN + * * * @return API_CMS_ERROR_OK API Completed Successfully * @return <0 Failed. @see adi_cms_error_e for details. */ int32_t adi_ad9081_adc_nyquist_zone_set(adi_ad9081_device_t *device, + adi_ad9081_adc_select_e adc_sel, adi_ad9081_adc_nyquist_zone_e zone); /** @@ -3453,6 +3467,25 @@ int32_t adi_ad9081_adc_ddc_coarse_sync_enable_set(adi_ad9081_device_t *device, int32_t adi_ad9081_adc_clk_out_enable_set(adi_ad9081_device_t *device, uint8_t enable); +/** + * @ingroup rx_helper_api + * @brief Set voltage swing level of ADC Clock Output Driver. + * + * @param device Pointer to the device structure + * @param code Input Value ranging -1000 to 1000 mV to estimate voltage swing as: + * code = (993mV - voltage_swing) / 99mV + * (code -> Swing) + * 0 -> 993mV; 1 -> 894mV; 2 -> 795mV; 3 -> 696mV; 4 -> 597mV; 5 -> 498mV; 6 -> 399mV; + * 7 -> 300mV; 8 -> 201mV; 9 -> 102mV; 10 -> 3mV; 11 -> -96mV; 12 -> -195mV; 13 -> -294mV; + * 14 -> -393mV; 15 -> -492mV; 16 -> -591mV; 17 -> -690mV; 18 -> -789mV; 19 -> -888mV; 20 -> -987mV; + * + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_adc_clk_out_voltage_swing_set(adi_ad9081_device_t *device, + int16_t swing_mv); + /** * @ingroup rx_helper_api * @brief Configure mapping between fast detection enable to GPIO @@ -3799,18 +3832,6 @@ int32_t adi_ad9081_adc_nco_master_slave_sync(adi_ad9081_device_t *device, */ int32_t adi_ad9081_jesd_rx_power_down_des(adi_ad9081_device_t *device); -/** - * @ingroup dac_link_setup - * @brief Block Top Level API. \n Start onshot sync - * Call after adi_ad9081_device_startup_rx(). - * - * @param device Pointer to the device structure - * - * @return API_CMS_ERROR_OK API Completed Successfully - * @return <0 Failed. @see adi_cms_error_e for details. - */ -int32_t adi_ad9081_jesd_oneshot_sync(adi_ad9081_device_t *device); - /** * @ingroup dac_link_setup * @brief Read jesd jrx link configuration status @@ -3887,12 +3908,13 @@ int32_t adi_ad9081_jesd_rx_link_select_set(adi_ad9081_device_t *device, /** * @ingroup dac_link_setup - * @brief Configure the JESD Rx lanes cross bar between physical lane and logic lane + * @brief Configure the JESD Rx lanes cross bar between physical lane and logic lane per link * Call after adi_ad9081_device_startup_tx(). * * @param device Pointer to the device structure * @param links Target link - * @param logical_lanes Logical lane index (0~7 for each value) + * @param logical_lanes Logical lane to physical lane mapping array (0~7) + * Where the index is logical lane, value is physical lane * * @return API_CMS_ERROR_OK API Completed Successfully * @return <0 Failed. @see adi_cms_error_e for details. @@ -4349,7 +4371,7 @@ int32_t adi_ad9081_jesd_tx_format_sel_set(adi_ad9081_device_t *device, * * @param device Pointer to the device structure * @param links Target link select - * @param resolution Chip output resolution, @see adi_ad9081_chip_output_res_e + * @param resolution Chip output resolution, Valid Range 8-16 * * @return API_CMS_ERROR_OK API Completed Successfully * @return <0 Failed. @see adi_cms_error_e for details. @@ -4464,6 +4486,22 @@ int32_t adi_ad9081_jesd_tx_synca_onchip_term_enable(adi_ad9081_device_t *device, int32_t adi_ad9081_jesd_tx_syncb_onchip_term_enable(adi_ad9081_device_t *device, uint8_t enable); +/** + * @ingroup adc_link_setup + * @brief Digital reset links + * + * @param device Pointer to the device structure + * @param links Target link + * @param reset Enable or disable link reset + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t +adi_ad9081_jesd_tx_force_digital_reset_set(adi_ad9081_device_t *device, + adi_ad9081_jesd_link_select_e links, + uint8_t reset); + /*===== A P P E N D I X =====*/ /** * @ingroup appendix @@ -4772,6 +4810,23 @@ adi_ad9081_jesd_tx_jtspat_enable_set(adi_ad9081_device_t *device, uint8_t lane_id, uint8_t enable); /*===== A 2 . 0 M U L T I C H I P S Y N C & S U B C L A S S 1 =====*/ +/** + * @ingroup appdx_mcs + * @brief Block Top Level API. \n Start onshot sync + * Call after adi_ad9081_device_startup_rx() & adi_ad9081_device_startup_tx() + * And Prior to links enable + * + * @param device Pointer to the device structure + * @param subclass System JESD Synchronization as per application requirements + * JESD_SUBCLASS_0, + * JESD_SUBCLASS_1 + * @return API_CMS_ERROR_OK api completed successfully + * @return API_CMS_ERROR_JESD_SYNC_NOT_DONE synchronization did not complete + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_jesd_oneshot_sync(adi_ad9081_device_t *device, + adi_cms_jesd_subclass_e subclass); + /** * @ingroup appdx_mcs * @brief Set SYSREF Phase @@ -4951,29 +5006,20 @@ int32_t adi_ad9081_jesd_sysref_enable_set(adi_ad9081_device_t *device, /** * @ingroup appdx_mcs - * @brief Set sysref capture enable - * - * @param device Pointer to the device structure - * @param enable 1:Enable, 0:Disable - * - * @return API_CMS_ERROR_OK API Completed Successfully - * @return <0 Failed. @see adi_cms_error_e for details. - */ -int32_t adi_ad9081_jesd_sysref_spi_enable_set(adi_ad9081_device_t *device, - uint8_t enable); - -/** - * @ingroup appdx_mcs - * @brief Set sysref input mode + * @brief Block Top Level API. \n Set sysref input receiver mode * - * @param device Pointer to the device structure - * @param input_mode 0:AC couple, 1:DC couple + * @param device Pointer to the device structure + * @param enable_receiver 1:Enable, 0:Disable + * @param enable_capture 1:Enable, 0:Disable + * @param adi_cms_signal_coupling_e input_mode Parameter of type adi_cms_signal_coupling_e to set the desired sysref signal type + * COUPLING_AC or COUPLING_DC * * @return API_CMS_ERROR_OK API Completed Successfully * @return <0 Failed. @see adi_cms_error_e for details. */ -int32_t adi_ad9081_jesd_sysref_input_mode_set(adi_ad9081_device_t *device, - uint8_t input_mode); +int32_t adi_ad9081_jesd_sysref_input_mode_set( + adi_ad9081_device_t *device, uint8_t enable_receiver, + uint8_t enable_capture, adi_cms_signal_coupling_e input_mode); /** * @ingroup appdx_mcs @@ -5001,6 +5047,117 @@ int32_t adi_ad9081_adc_sysref_resync_mode_set(adi_ad9081_device_t *device, int32_t adi_ad9081_adc_sysref_rise_edge_enable_set(adi_ad9081_device_t *device, uint8_t enable); +/** + * @ingroup appdx_mcs + * @brief Check if potential setup time violation exists. + * + * @param device Pointer to the device structure + * @param setup_risk_assessment Pointer to number of ones in setup time register value + * @param hold_risk_assessment Pointer to number of ones in hold time register value + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_jesd_sysref_setup_hold_get(adi_ad9081_device_t *device, + uint8_t *setup_risk_assessment, + uint8_t *hold_risk_assessment); + +/** + * @ingroup appdx_mcs + * @brief Enable and set fine and superfine delay on the SYSREF input. + * + * @param device Pointer to the device structure + * @param enable 00:delay is disabled, 01:fine delay enabled, 10:superfine delay enabled, 11:both enabled + * @param fine_delay Fine delay adjustment of the SYSREF input in 1.1 ps steps with max of 56 ps + * @param superfine_delay Super fine delay adjustment of the SYSREF input in ~16 fs steps with max of 4 ps + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_jesd_sysref_fine_superfine_delay_set( + adi_ad9081_device_t *device, uint8_t enable, uint8_t fine_delay, + uint8_t superfine_delay); + +/** + * @ingroup appdx_mcs + * @brief Set Sysref edge count to delay enabling one-shot mode. + * + * @param device Pointer to the device structure + * @param edges Number of rising edges to ignore before sync + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_jesd_sysref_count_set(adi_ad9081_device_t *device, + uint8_t edges); + +/** + * @ingroup appdx_mcs + * @brief Set number of Sysref pulses that are averaged before one-shot mode. + * + * @param device Pointer to the device structure + * @param pulses Number of pulses to be averaged calculated by 2^n + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_jesd_sysref_average_set(adi_ad9081_device_t *device, + uint8_t pulses); + +/** + * @ingroup appdx_mcs + * @brief Get Sysref phase in monitor mode + * + * @param device Pointer to the device structure + * @param sysref_phase Pointer to the sysref phase register + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_jesd_sysref_monitor_phase_get(adi_ad9081_device_t *device, + uint16_t *sysref_phase); + +/** + * @ingroup appdx_mcs + * @brief Get Sysref to lmfc align error in monitor mode + * + * @param device Pointer to the device structure + * @param lmfc_align_err_get Pointer to the lmfc align error value + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t +adi_ad9081_jesd_sysref_monitor_lmfc_align_error_get(adi_ad9081_device_t *device, + uint8_t *lmfc_align_err); + +/** + * @ingroup appdx_mcs + * @brief Set Sysref lmfc align threshold in monitor mode + * + * @param device Pointer to the device structure + * @param sysref_error_window Sysref error window value + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_jesd_sysref_monitor_lmfc_align_threshold_set( + adi_ad9081_device_t *device, uint8_t sysref_error_window); + +/** + * @ingroup appdx_mcs + * @brief Check oneshot sync mode flag if sync is done. + * + * @param device Pointer to the device structure + * @param sync_done Pointer to value of oneshot sync done flag + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t +adi_ad9081_jesd_sysref_oneshot_sync_done_get(adi_ad9081_device_t *device, + uint8_t *sync_done); + /*===== A 3 . 0 I R Q S =====*/ /*===== A 3 . 1 D A C D P I R Q S =====*/ diff --git a/drivers/iio/adc/ad9081/adi_ad9081_adc.c b/drivers/iio/adc/ad9081/adi_ad9081_adc.c index 6760dfae581462..86ce25a1723e8a 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_adc.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_adc.c @@ -66,6 +66,70 @@ int32_t adi_ad9081_adc_core_analog_regs_enable_set(adi_ad9081_device_t *device, return API_CMS_ERROR_OK; } +int32_t +adi_ad9081_adc_analog_input_buffer_set(adi_ad9081_device_t *device, + uint8_t adc_cores, + adi_cms_signal_coupling_e coupling) +{ + int32_t err; + uint8_t enable_adc_core = 3, enable_cmbuf, cmin_input, cmin_out, + cmin_out_pulldown; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + if (adc_cores == 1 && coupling == COUPLING_AC) { + enable_cmbuf = 3; + cmin_input = 14; + cmin_out = 14; + cmin_out_pulldown = 4; + } else if (adc_cores == 1 && coupling == COUPLING_DC) { + enable_cmbuf = 0; + cmin_input = 14; + cmin_out = 4; + cmin_out_pulldown = 7; + } else if (adc_cores == 2 && coupling == COUPLING_AC) { + enable_cmbuf = 2; + cmin_input = 0; + cmin_out = 0; + cmin_out_pulldown = 3; + } else if (adc_cores == 2 && coupling == COUPLING_DC) { + enable_cmbuf = 0; + cmin_input = 0; + cmin_out = 4; + cmin_out_pulldown = 7; + } else { + return API_CMS_ERROR_INVALID_PARAM; + } + err = adi_ad9081_hal_bf_set( + device, 0x2112, 0x0, + 1); /* CAL_FREEZE_GLOBAL freeze calibration for reconfig of common-mode loop*/ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_adc_core_analog_regs_enable_set( + device, adc_cores, + enable_adc_core); /*Global enable of ADC0 and ADC1 SPI access */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, 0x1721, 0x206, + enable_cmbuf); /* Power down CMBUF_PD */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set( + device, 0x1732, 0x400, + cmin_input); /* SPI_CMIN_INPUT_SEL select common mode loop for TxFE or MxFE*/ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set( + device, 0x1733, 0X403, + cmin_out); /* SPI_CMIN_OUT_SEL select common mode loop for TxFE or MxFE*/ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set( + device, 0x1733, 0x300, + cmin_out_pulldown); /* SPI_CMIN_OUT_PULDWN pulls VCMx pin low when common mode buffer is disabled*/ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, 0x2112, 0x0, + 0); /* CAL_FREEZE_GLOBAL */ + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + int32_t adi_ad9081_adc_power_up_set(adi_ad9081_device_t *device, uint8_t adcs, uint8_t enable) { @@ -214,6 +278,32 @@ int32_t adi_ad9081_adc_clk_out_enable_set(adi_ad9081_device_t *device, return API_CMS_ERROR_OK; } +int32_t adi_ad9081_adc_clk_out_voltage_swing_set(adi_ad9081_device_t *device, + int16_t swing_mv) +{ + int32_t err; + uint8_t code; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + if (swing_mv > 1000 || swing_mv < -1000) { + return API_CMS_ERROR_INVALID_PARAM; + } + + code = (993 - swing_mv + (99 / 2)) / 99; + + /* Voltage Swing = 993mV - (code * 99mV). + 0 -> 993mV; 1 -> 894mV; 2 -> 795mV; 3 -> 696mV; 4 -> 597mV; 5 -> 498mV; 6 -> 399mV; + 7 -> 300mV; 8 -> 201mV; 9 -> 102mV; 10 -> 3mV; 11 -> -96mV; 12 -> -195mV; 13 -> -294mV; + 14 -> -393mV; 15 -> -492mV; 16 -> -591mV; 17 -> -690mV; 18 -> -789mV; 19 -> -888mV; 20 -> -987mV; + */ + err = adi_ad9081_hal_bf_set(device, REG_ADC_CLK_CTRL0_ADDR, + BF_ADC_DRIVER_DATA_CTRL_INFO, code); + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + int32_t adi_ad9081_adc_clk_enable_set(adi_ad9081_device_t *device, uint8_t enable) { @@ -2454,10 +2544,13 @@ int32_t adi_ad9081_adc_config(adi_ad9081_device_t *device, uint8_t cddcs, } int32_t adi_ad9081_adc_nyquist_zone_set(adi_ad9081_device_t *device, + adi_ad9081_adc_select_e adc_sel, adi_ad9081_adc_nyquist_zone_e zone) { int32_t err; uint32_t reg_nyquist_zone_addr = 0x2110; + uint8_t nyquist_setting = 0x0; + int i = 0; AD9081_NULL_POINTER_RETURN(device); AD9081_LOG_FUNC(); @@ -2468,19 +2561,28 @@ int32_t adi_ad9081_adc_nyquist_zone_set(adi_ad9081_device_t *device, device->dev_info.dev_rev == 3) { /* r1r/r2 */ reg_nyquist_zone_addr = 0x2110; } + err = adi_ad9081_hal_reg_get(device, reg_nyquist_zone_addr, + &nyquist_setting); + nyquist_setting |= 0x1; /*enable default override*/ if (zone == AD9081_ADC_NYQUIST_ZONE_ODD) { - err = adi_ad9081_hal_reg_set(device, reg_nyquist_zone_addr, - 0x01); - AD9081_ERROR_RETURN(err); + for (i = 0; i < 4; i++) { + if ((1 << i) & adc_sel) { + nyquist_setting &= ~(0x2 << i); + } + } } if (zone == AD9081_ADC_NYQUIST_ZONE_EVEN) { - err = adi_ad9081_hal_reg_set(device, reg_nyquist_zone_addr, - 0x1f); - AD9081_ERROR_RETURN(err); + for (i = 0; i < 4; i++) { + if ((1 << i) & adc_sel) { + nyquist_setting |= (0x2 << i); + } + } } + err = adi_ad9081_hal_reg_set(device, reg_nyquist_zone_addr, + nyquist_setting); err = adi_ad9081_hal_reg_set(device, 0x2100, - 1); /* @user_ctrl_transfer */ + 1); /* Trigger Data Transfer */ AD9081_ERROR_RETURN(err); return API_CMS_ERROR_OK; @@ -2526,16 +2628,12 @@ int32_t adi_ad9081_adc_test_mode_config_set(adi_ad9081_device_t *device, AD9081_LOG_FUNC(); /* set test mode on all converters */ - adi_ad9081_jesd_tx_conv_test_mode_enable_set( + err = adi_ad9081_jesd_tx_conv_test_mode_enable_set( device, links, ((i_mode == AD9081_TMODE_OFF) && (q_mode == AD9081_TMODE_OFF)) ? 0x0000 : 0xffff); - - /* set output as 16bit resolution */ - adi_ad9081_jesd_tx_res_sel_set(device, links, - AD9081_CHIP_OUT_RES_16BIT); - + AD9081_ERROR_RETURN(err); /* set test mode type */ err = adi_ad9081_hal_bf_set(device, REG_TMODE_I_CTRL1_ADDR, BF_TMODE_I_TYPE_SEL_INFO, diff --git a/drivers/iio/adc/ad9081/adi_ad9081_config.h b/drivers/iio/adc/ad9081/adi_ad9081_config.h index 3e4994793c2d01..29d955686cfe31 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_config.h +++ b/drivers/iio/adc/ad9081/adi_ad9081_config.h @@ -40,7 +40,10 @@ #define __FUNCTION_NAME__ __FUNCTION__ #endif -#define AD9081_API_REV 0x00010101 +#define AD9081_API_REV 0x00010200 +#define AD9081_API_HW_RESET_LOW 600000 +#define AD9081_API_RESET_WAIT 500000 +#define AD9081_PLL_LOCK_TRY 75 #define AD9081_PLL_LOCK_WAIT 20000 #define AD9081_JESD_CAL_BOOT_WAIT 250000 #define AD9081_JESD_MAN_CAL_WAIT 200000 @@ -126,120 +129,835 @@ extern "C" { #endif +/** + * \brief Enables or disables on-chip PLL. + * + * If set, the device clocks will be generated from the PLL. Otherwise + * the device clocks will be generated from the reference clock supplied. + * + * \param[in] device Pointer to device handler structure. + * \param[in] pll_en Enable signal for PLL + * 0 – Disable PLL + * 1 – Enable PLL + * + * \returns API_CMS_ERROR_OK returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_clk_pll_enable_set(adi_ad9081_device_t *device, uint8_t pll_en); + +/** + * \brief Configures PLL divider settings. + * + * Set up the on-chip pll dividers which can generate the device + * clocks for dac and adc cores from a provided reference clock. + * + * \param[in] device Pointer to device handler structure. + * \param[in] ref_div Input reference clock divider. Valid range 0-0x3. + * \param[in] m_div PLL M-Divider. + * \param[in] pll_div PLL output divider. Valid range 0-0x3. + * \param[in] fb_div PLL Feedback divider. Valid range 0-0x3F. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_clk_pll_div_set(adi_ad9081_device_t *device, uint8_t ref_div, uint8_t m_div, uint8_t pll_div, uint8_t fb_div); + +/** + * \brief Configures PLL input and output frequencies. + * + * Configure the PLL as per the desired DAC and ADC clock based on the + * supplied reference clock set by ref_clk_hz parameter. + * + * \param[in] device Pointer to device handler structure. + * \param[in] dac_clk_hz Desired DAC Clock Frequency in Hz. Valid Range 1.5GHz to 12GHz. + * \param[in] adc_clk_hz Desired ADC Clock Frequency in Hz. Valid Range 2GHz to 6GHz. + * \param[in] ref_clk_hz Reference Clock Frequecny provided in Hz. Valid Range 100 MHz to 2GHz. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_clk_pll_startup(adi_ad9081_device_t *device, uint64_t dac_clk_hz, uint64_t adc_clk_hz, uint64_t ref_clk_hz); + +/** + * \brief Configures up dividers. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] dac_clk_hz Desired DAC Clock Frequency in Hz. Valid Range 1.5GHz to 12GHz. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_clk_up_div_set(adi_ad9081_device_t *device, uint64_t dac_clk_hz); + +/** + * \brief Gets laminate ID. + * + * Gets laminate ID from register 0x1e0d and puts it where input parameter 'id' points. + * + * \param[in] device Pointer to device handler structure. + * \param[in] id Pointer to where you want to store laminate ID. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_laminate_id_get(adi_ad9081_device_t *device, uint8_t *id); + +/** + * \brief Gets die ID. + * + * Gets die ID from register 0x1e0e and puts it where input parameter 'id' points. + * + * \param[in] device Pointer to device handler structure. + * \param[in] id Pointer to where you want to store die ID. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_die_id_get(adi_ad9081_device_t *device, uint8_t *id); + +/** + * \brief Checks status of power supplies. + * + * Checks power supply status for: DAC, Clock, ADC0, and ADC1. + * + * \param[in] device Pointer to device handler structure. + * + * \returns API_CMS_ERROR_OK is returned if all power supplies are on. Otherwise, a failure code. + */ int32_t adi_ad9081_device_power_status_check(adi_ad9081_device_t *device); + +/** + * \brief Performs 8-bit register read/write test. + * + * Tries writing/reading register REG_PAGEINDX_DAC_CHAN_ADDR (0x0000001C). + * + * \param[in] device Pointer to device handler structure. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_reg8_access_check(adi_ad9081_device_t *device); + +/** + * \brief Performs 32-bit register read/write test. + * + * Tries writing/reading register 0x01001300. + * + * \param[in] device Pointer to device handler structure. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_reg32_access_check(adi_ad9081_device_t *device); + +/** + * \brief Verifies and logs pre-clock boot activity. + * + * Tracks core status through register 0x3472 to ensure boot reaches expected spot in boot_pre_clock(). + * Next, checks that device revision is supported and logs chip ID, laminate ID, and die ID. + * + * \param[in] device Pointer to device handler structure. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_boot_pre_clock(adi_ad9081_device_t *device); + +/** + * \brief Verifies and logs post-clock boot activity. + * + * Checks device revision to determine if the boot loader power up sequence should be bypassed. + * Verifies up_spi_edge_interrupt bit is cleared. Checks that boot is complete. + * Checks that core is waiting to run application code. Verifies that clock switch is done. + * Completes additional writes to ADC SPI enable registers. Finally, logs firmware revision. + * + * \param[in] device Pointer to device handler structure. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_boot_post_clock(adi_ad9081_device_t *device); + +/** + * \brief Control master-slave mode for NCO sync. + * + * \param[in] device Pointer to device handler structure. + * \param[in] mode 0: disable, 1: set as master, 2: set as slave, 3: disable. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_nco_sync_mode_set(adi_ad9081_device_t *device, uint8_t mode); + +/** + * \brief Select which source triggers Master-slave mode for the master device. + * + * \param[in] device Pointer to device handler structure. + * \param[in] source 0: sysref, 1: lmfc rising edge, 2: lmfc falling edge. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_nco_sync_trigger_source_set(adi_ad9081_device_t *device, uint8_t source); + +/** + * \brief Set GPIOs related to NCO sync. + * + * \param[in] device Pointer to device handler structure. + * \param[in] gpio_index GPIO identifier. + * \param[in] output (output > 0): 10 written to bitfield (output < 0): 11 written to bitfield. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_nco_sync_gpio_set(adi_ad9081_device_t *device, uint8_t gpio_index, uint8_t output); + +/** + * \brief In NCO Master-Slave sync mode, set how many extra lmfc cycles to delay before an NCO reset is issued. + * + * Only valid when 'nco_sync_ms_mode'==1 & 'nco_sync_ms_trig_source'!=0. + * + * \param[in] device Pointer to device handler structure. + * \param[in] num Number of extra lmfc. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_nco_sync_extra_lmfc_num_set(adi_ad9081_device_t *device, uint8_t num); + +/** + * \brief Control how RX & TX NCOs are synced by sysref. + * + * \param[in] device Pointer to device handler structure. + * \param[in] mode 0: immediately by sysref, 1: by next lmfc rising edge, 2: by next lmfc falling edge. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_nco_sync_sysref_mode_set(adi_ad9081_device_t *device, uint8_t mode); + +/** + * \brief Resets NCO + * + * Transition low to high triggers an internal NCO reset signal, on the next received SYSREF pulse. + * + * \param[in] device Pointer to device handler structure. + * \param[in] enable 1: reset NCO, 0: clear reset bit. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_nco_sync_reset_via_sysref_set(adi_ad9081_device_t *device, uint8_t enable); + +/** + * \brief Triggers master-slave NCO synchronization. + * + * Self-clearing. + * + * \param[in] device Pointer to device handler structure. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_device_nco_sync_trigger_set(adi_ad9081_device_t *device); +/** + * \brief Enable dual SPI mode + * + * Selecting dual0 will enable access to control registers in ranges 0x180-0x194, 0x60-0x7E, and 0x140-0x178. + * This will only access these registers for DAC0, DAC1, ADC0, and ADC2. Select dual1 for the same ranges on + * the DAC2, DAC3, ADC1, ADC3 side of the device. + * + * \param[in] device Pointer to device handler structure. + * \param[in] duals 0x1: select dual0, 0x2: select dual1, 0x3: select both. + * \param[in] enable 1: enable, 0: disable. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_dac_d2a_dual_spi_enable_set(adi_ad9081_device_t *device, uint8_t duals, uint8_t enable); + +/** + * \brief Starts up specified DACs + * + * Enables DLL clock control, SWD clock control, and mushi decoder/control for each + * specified DAC. Overrides manual DCC code. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] dacs 0bXXXX, set X==1 to start-up corresponding DAC : + * Bit 3: DAC 3 (MSB) + * Bit 2: DAC 2 + * Bit 1: DAC 1 + * Bit 0: DAC 0 (LSB) + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_dac_dll_startup(adi_ad9081_device_t *device, uint8_t dacs); + +/** + * \brief Enables digital logic. + * + * This includes JESD digital, digital clock gen., digital data path. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] enable 1: enable digital logic. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_dac_digital_logic_enable_set(adi_ad9081_device_t *device, uint8_t enable); + +/** + * \brief Sets frequency tuning word for specified DACs and channels. + * + * If DDSM modulus disabled, main datapath NCO frequency = FDAC * (FTW/2^48). + * If DDSM modulus enabled, main datapath NCO frequency = FDAC * (FTW + REG_DDSM_ACC_DELTA/REG_DDSM_ACC_MODULUS) / 2^48. + * + * Note: ACC_DELTA and ACC_MODULUS are set via adi_ad9081_dac_duc_nco_ftw_set call. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] dacs 0bXXXX, set X==1 to specify DACs you wish to affect: + * Bit 3: DAC 3 (MSB) + * Bit 2: DAC 2 + * Bit 1: DAC 1 + * Bit 0: DAC 0 (LSB) + * \param[in] channels 0bXXXXXXXX, (8 bits) set X==1 to specifiy channels you wish to affect: + * Bit 7: Channel 7 (MSB) + * Bit 6: Channel 6 + * ..... + * Bit 0: Channel 0 (LSB) + * \param[in] ftw Frequency tuning word. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_dac_duc_nco_ftw0_set(adi_ad9081_device_t *device, uint8_t dacs, uint8_t channels, uint64_t ftw); + +/** + * \brief Enables soft off gain block for specified DACs. + * + * The ramp up/down process is achieved by data * gain which controls gain up + * and down, so soft off gain block must be enabled to use soft off/on. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] dacs 0bXXXX, set X==1 to specify DACs you wish to affect: + * Bit 3: DAC 3 (MSB) + * Bit 2: DAC 2 + * Bit 1: DAC 1 + * Bit 0: DAC 0 (LSB) + * \param[in] enable 1: enable, 0: disable. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_dac_soft_off_gain_enable_set(adi_ad9081_device_t *device, uint8_t dacs, uint8_t enable); + +/** + * \brief Enables MSB and ISB shuffling. + * + * Enable shuffling (randomly selecting) active MSB & ISB segments for each new DAC sampling cycle. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] dacs 0bXXXX, set X==1 to specify DACs you wish to affect: + * Bit 3: DAC 3 (MSB) + * Bit 2: DAC 2 + * Bit 1: DAC 1 + * Bit 0: DAC 0 (LSB) + * \param[in] enable 1: enable, 0: disable. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_dac_shuffle_enable_set(adi_ad9081_device_t *device, uint8_t dacs, uint8_t enable); + +/** + * \brief Enables both: + * - DAC data scrambling in sync and re-timer block (xor) + * - DAC data de-scramble in decoder (de-xor) + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] dacs 0bXXXX, set X==1 to specify DACs you wish to affect: + * Bit 3: DAC 3 (MSB) + * Bit 2: DAC 2 + * Bit 1: DAC 1 + * Bit 0: DAC 0 (LSB) + * \param[in] enable 1: enable, 0: disable. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_dac_data_xor_set(adi_ad9081_device_t *device, uint8_t dacs, uint8_t enable); +/** + * \brief Selects ADCs to affect with next ADC setting change by updating coarse paging register. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] adcs 0bXXXX, set X==1 to specify ADCs you wish to affect: + * Bit 3: ADC 3 (MSB) + * Bit 2: ADC 2 + * Bit 1: ADC 1 + * Bit 0: ADC 0 (LSB) + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_select_set(adi_ad9081_device_t *device, uint8_t adcs); + +/** + * \brief Enables ADC0 and ADC1 analog register SPI access through the 8bit and 32bit SPI registers. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] adc_cores 0x01: ADC0 enable, 0x02: ADC1 enable, 0x03: both enable. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_core_analog_regs_enable_set(adi_ad9081_device_t *device, uint8_t adc_cores, uint8_t enable); + +/** + * \brief Boots up specified ADC cores. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] adc_cores 0x01: boot ADC0, 0x02: boot ADC1, 0x03: boot both. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_core_setup(adi_ad9081_device_t *device, uint8_t adc_cores); + +/** + * \brief Configures SPI registers for ADC Buffer + * + * \param[in] device Pointer to device handler structure. + * \param[in] adc_cores 0x01: boot ADC0, 0x02: boot ADC1, 0x03: boot both. + * \param[in] coupling AC_COUPLED or DC_COUPLED + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ +int32_t +adi_ad9081_adc_analog_input_buffer_set(adi_ad9081_device_t *device, + uint8_t adc_cores, + adi_cms_signal_coupling_e coupling); + +/** + * \brief Powers up selected ADCs by booting up their respective cores. + * + * Essentially a wrapper for adi_ad9081_adc_core_setup. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] adcs 0bXXXX, set X==1 to specify ADCs you wish to power up: + * Bit 3: ADC 3 (MSB) + * Bit 2: ADC 2 + * Bit 1: ADC 1 + * Bit 0: ADC 0 (LSB) + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_power_up_set(adi_ad9081_device_t *device, uint8_t adcs, uint8_t enable); + +/** + * \brief Decodes ADC coarse DDC decimation values. + * + * + * \param[in] cddc_dcm Value to be decoded. + * + * \param[out] cddc_dcm_value Decoded value. + * + * \returns cddc_dcm_value - Decoded decimation value. + */ uint8_t adi_ad9081_adc_ddc_coarse_dcm_decode(adi_ad9081_adc_coarse_ddc_dcm_e cddc_dcm); + +/** + * \brief Decodes ADC fine DDC decimation values. + * + * + * \param[in] fddc_dcm Value to be decoded. + * + * \param[out] fddc_dcm_value Decoded value. + * + * \returns fddc_dcm_value - Decoded decimation value. + */ uint8_t adi_ad9081_adc_ddc_fine_dcm_decode(adi_ad9081_adc_fine_ddc_dcm_e fddc_dcm); + +/** + * \brief Selects the GPIOs to which PERI_I_SEL21/22 are connected. + * + * PERI_I_SEL21/22 are drive bits 0 and 1, respectively, of a 2-bit selector which + * chooses among four profiles of Programmable Filter/Fractional Delay/Cycle Delay + * (see datasheet). + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] sel0 Map a GPIO to PERI_I_SEL21. + * + * Pin selection: + * + * TxFE GPIO[6] 0x02 + * TxFE GPIO[7] 0x03 + * TxFE GPIO[8] 0x04 + * TxFE GPIO[9] 0x05 + * TxFE GPIO[10] 0x06 + * TxFE SYNCINB1_P 0x07 + * TxFE SYNCINB1_N 0x08 + * + * \param[in] sel1 Map a GPIO to PERI_I_SEL22. Same pin selection as sel0. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_fdelay_cdelay_pfir_sel_to_gpio_mapping_set( adi_ad9081_device_t *device, uint8_t sel0, uint8_t sel1); + +/** + * \brief Enables common, GPIO based frequency hopping for all coarse DDC NCOs. + * + * When enabled while GPIO based hopping is selected, freq. hopping is done at the same time for all the Coarse DDC NCOs, bypassing the profile_pins[5:4]. + * When disabled while GPIO based hopping is selected, freq. hopping is done for the Coarse DDC NCO selected by profile_pins[5:4]. + * + * \param[in] device Pointer to device handler structure. + * \param[in] enable 1: enable, 0: disable. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_common_hop_en_set(adi_ad9081_device_t *device, uint8_t enable); + +/** + * \brief Enables trig NCO reset for specified coarse DDCs. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] cddcs 0bXXXX, set X==1 to specify cddcs you wish to affect: + * Bit 3: cddc 3 (MSB) + * Bit 2: cddc 2 + * Bit 1: cddc 1 + * Bit 0: cddc 0 (LSB) + * \param[in] enable 1: enable, 0: disable. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_ddc_coarse_trig_nco_reset_enable_set( adi_ad9081_device_t *device, uint8_t cddcs, uint8_t enable); + +/** + * \brief Changes Profile Update Mode/ Phase Update Mode for specified coarse DDCs. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] cddcs 0bXXXX, set X==1 to specify cddcs you wish to affect: + * Bit 3: cddc 3 (MSB) + * Bit 2: cddc 2 + * Bit 1: cddc 1 + * Bit 0: cddc 0 (LSB) + * \param[in] mode 0: Instantaneous/Continuous Update. Phase increment and phase offset values are updated immediately. + * 1: Phase increment and phase offset values are updated synchronously either when the chip_transfer + * bit is set high or based on the GPIO (pin ddc_chip_gpio_transfer at nova_dig_dp_top hierarchy) + * pin low to high transition. The chip transfer bit will be cleared once the transfer is complete. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_ddc_coarse_nco_channel_update_mode_set( adi_ad9081_device_t *device, uint8_t cddcs, uint8_t mode); + +/** + * \brief Changes GPIO Chip Transfer Mode for specified coarse DDCs. + * + * Used when ddc0_phase_update_mode is '1'. + * + * \param[in] device Pointer to device handler structure. + * \param[in] cddcs 0bXXXX, set X==1 to specify cddcs you wish to affect: + * Bit 3: cddc 3 (MSB) + * Bit 2: cddc 2 + * Bit 1: cddc 1 + * Bit 0: cddc 0 (LSB) + * \param[in] mode 0: Phase increment and phase offset values are updated synchronously when the chip_transfer bit is set + * high. The chip transfer bit will be cleared once the transfer is complete. + * 1: Phase increment and phase offset values are updated based on the GPIO (pin ddc_chip_gpio_transfer + * at nova_dig_dp_top hierarchy) pin low to high transition. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_ddc_coarse_gpio_chip_xfer_mode_set(adi_ad9081_device_t *device, uint8_t cddcs, uint8_t mode); + +/** + * \brief Enable trig signal frequency hopping for specified coarse DDCs. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] cddcs 0bXXXX, set X==1 to specify cddcs you wish to affect: + * Bit 3: cddc 3 (MSB) + * Bit 2: cddc 2 + * Bit 1: cddc 1 + * Bit 0: cddc 0 (LSB) + * \param[in] enable 0: Frequency hopping is independent of trig signal. + * 1: Trig signal is used for frequency hopping. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_ddc_coarse_trig_hop_en_set(adi_ad9081_device_t *device, uint8_t cddcs, uint8_t enable); + +/** + * \brief Enables amplitude dither and phase dither for specified coarse DDCs. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] cddcs 0bXXXX, set X==1 to specify cddcs you wish to affect: + * Bit 3: cddc 3 (MSB) + * Bit 2: cddc 2 + * Bit 1: cddc 1 + * Bit 0: cddc 0 (LSB) + * \param[in] amp_dither_en 0: enable, 1: disable + * \param[in] phase_dither_en 0: enable, 1: disable + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_ddc_coarse_dither_en_set(adi_ad9081_device_t *device, uint8_t cddcs, uint8_t amp_dither_en, uint8_t phase_dither_en); + +/** + * \brief Sets Profile Select Word (PSW) for specified coarse DDCs. + * + * The PSW specifies the rollover point (in encode samples) for the Profile Select Timer (PST). Whenever the Profile Select Timer + * rolls over to zero, channel selection counter increments when channel selection is through Profile Select Timer. + * + * \param[in] device Pointer to device handler structure. + * \param[in] cddcs 0bXXXX, set X==1 to specify cddcs you wish to affect: + * Bit 3: cddc 3 (MSB) + * Bit 2: cddc 2 + * Bit 1: cddc 1 + * Bit 0: cddc 0 (LSB) + * \param[in] psw Profile Select Word. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_ddc_coarse_psw_set(adi_ad9081_device_t *device, uint8_t cddcs, uint64_t psw); + +/** + * \brief Enables trig NCO reset for specified fine DDCs. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] fddcs 0bXXXXXXXX, (8 bits) set X==1 to specify fddcs you wish to affect: + * Bit 7: fddc 7 (MSB) + * Bit 6: fddc 6 + * ..... + * Bit 0: fddc 0 (LSB) + * \param[in] enable 1: enable, 0: disable. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_ddc_fine_trig_nco_reset_enable_set( adi_ad9081_device_t *device, uint8_t fddcs, uint8_t enable); + +/** + * \brief Changes Profile Update Mode/ Phase Update Mode for specified fine DDCs. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] fddcs 0bXXXXXXXX, (8 bits) set X==1 to specify fddcs you wish to affect: + * Bit 7: fddc 7 (MSB) + * Bit 6: fddc 6 + * ..... + * Bit 0: fddc 0 (LSB) + * \param[in] mode 0: Instantaneous/Continuous Update. Phase increment and phase offset values are updated immediately. + * 1: Phase increment and phase offset values are updated synchronously either when the chip_transfer + * bit is set high or based on the GPIO (pin ddc_chip_gpio_transfer at nova_dig_dp_top hierarchy) + * pin low to high transition. The chip transfer bit will be cleared once the transfer is complete. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_ddc_fine_nco_channel_update_mode_set( adi_ad9081_device_t *device, uint8_t fddcs, uint8_t mode); + +/** + * \brief Changes GPIO Chip Transfer Mode for specified fine DDCs. + * + * Used when ddc0_phase_update_mode is '1'. + * + * \param[in] device Pointer to device handler structure. + * \param[in] fddcs 0bXXXXXXXX, (8 bits) set X==1 to specify fddcs you wish to affect: + * Bit 7: fddc 7 (MSB) + * Bit 6: fddc 6 + * ..... + * Bit 0: fddc 0 (LSB) + * \param[in] mode 0: Phase increment and phase offset values are updated synchronously when the chip_transfer bit is set + * high. The chip transfer bit will be cleared once the transfer is complete. + * 1: Phase increment and phase offset values are updated based on the GPIO (pin ddc_chip_gpio_transfer + * at nova_dig_dp_top hierarchy) pin low to high transition. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_ddc_fine_gpio_chip_xfer_mode_set(adi_ad9081_device_t *device, uint8_t fddcs, uint8_t mode); + +/** + * \brief Enable trig signal frequency hopping for specified fine DDCs. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] fddcs 0bXXXXXXXX, (8 bits) set X==1 to specify fddcs you wish to affect: + * Bit 7: fddc 7 (MSB) + * Bit 6: fddc 6 + * ..... + * Bit 0: fddc 0 (LSB) + * \param[in] enable 0: Frequency hopping is independent of trig signal. + * 1: Trig signal is used for frequency hopping. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_ddc_fine_trig_hop_en_set(adi_ad9081_device_t *device, uint8_t fddcs, uint8_t enable); + +/** + * \brief Enables amplitude dither and phase dither for specified fine DDCs. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] fddcs 0bXXXXXXXX, (8 bits) set X==1 to specify fddcs you wish to affect: + * Bit 7: fddc 7 (MSB) + * Bit 6: fddc 6 + * ..... + * Bit 0: fddc 0 (LSB) + * \param[in] amp_dither_en 0: enable, 1: disable + * \param[in] phase_dither_en 0: enable, 1: disable + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_adc_ddc_fine_dither_en_set(adi_ad9081_device_t *device, uint8_t fddcs, uint8_t amp_dither_en, uint8_t phase_dither_en); +/** + * \brief Sets masking for unused channels. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] links Choose AD9081 link(s) to set mask for: + * 0x1 - AD9081_LINK_0 + * 0x2 - AD9081_LINK_1 + * 0x3 - Both + * \param[in] conv_index Choose converter to set mask for: + * 0x0 - CONV0 + * 0x1 - CONV1 + * 0x2 - CONV2 + * ..... + * 0xF - CONV15 + * \param[in] val 0: unmask, 1: mask. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_jesd_tx_conv_mask_set(adi_ad9081_device_t *device, adi_ad9081_jesd_link_select_e links, uint8_t conv_index, uint8_t val); + +/** + * \brief Sets virtual converters for specified links. + * + * \param[in] device Pointer to device handler structure. + * \param[in] links Choose AD9081 link(s) to set mask for: + * 0x1 - AD9081_LINK_0 + * 0x2 - AD9081_LINK_1 + * 0x3 - Both + * \param[in] jesd_conv_sel jesd_conv_sel[0] - Virtual converter selection struct for AD9081_LINK_0. + * jesd_conv_sel[1] - Virtual converter selection struct for AD9081_LINK_1. + * \param[in] jesd_m jesd_m[0] - Number of used virtual converters for AD9081_LINK_0. + * jesd_m[1] - Number of used virtual converters for AD9081_LINK_1. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_jesd_tx_link_conv_sel_set( adi_ad9081_device_t *device, adi_ad9081_jesd_link_select_e links, adi_ad9081_jtx_conv_sel_t jesd_conv_sel[2], uint8_t jesd_m[2]); + +/** + * \brief Get status of PLL. + * + * \param[in] device Pointer to device handler structure. + * \param[in] pll_locked Pointer to location for storing pll locked status. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_jesd_tx_pll_status_get(adi_ad9081_device_t *device, uint8_t *pll_locked); + +/** + * \brief Startup JESD deserializers. + * + * \param[in] device Pointer to device handler structure. + * \param[in] deser_mode 0: Full rate operation, 1: Half rate operation, 2: Quarter rate operation. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ int32_t adi_ad9081_jesd_rx_startup_des(adi_ad9081_device_t *device, adi_ad9081_deser_mode_e deser_mode); + +/** + * \brief Finds unused DFormat output to assign to unused virtual converters. + * + * \param[in] jesd_conv_sel Pointer to virtual converter selection struct. + * \param[in] jesd_m Number of used virtual converters. + * + * \param[out] df_out Unused DFormat output. + * + * \returns df_out: Unused DFormat output. + */ uint16_t adi_ad9081_jesd_find_dformat_out_nc( adi_ad9081_jtx_conv_sel_t const *jesd_conv_sel, uint8_t jesd_m); + +/** + * \brief Finds the highest common unused DFormat output between both AD9081 links. + * + * \param[in] links 0x1 - Outputs first unused DFormat output for AD9081_LINK_0. + * 0x2 - Outputs first unused DFormat output for AD9081_LINK_1. + * 0x3 - Outputs highest common unused DFormat output between both. + * \param[in] jesd_conv_sel jesd_conv_sel[0] - Virtual converter selection struct for AD9081_LINK_0. + * jesd_conv_sel[1] - Virtual converter selection struct for AD9081_LINK_1. + * \param[in] jesd_m jesd_m[0] - Number of used virtual converters for AD9081_LINK_0. + * jesd_m[1] - Number of used virtual converters for AD9081_LINK_1. + * + * \param[out] nc DFormat output. + * + * \returns nc - DFormat output. + */ uint8_t adi_ad9081_jesd_determine_common_nc(adi_ad9081_jesd_link_select_e links, adi_ad9081_jtx_conv_sel_t jesd_conv_sel[2], uint8_t jesd_m[2]); +/** + * \brief Set d2acenter enable + * + * \param[in] device Pointer to the device structure + * \param[in] enable 1:Enable, 0:Disable + * + * \return API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ +int32_t adi_ad9081_jesd_sysref_d2acenter_enable_set(adi_ad9081_device_t *device, + uint8_t enable); + #if AD9081_USE_FLOATING_TYPE > 0 int32_t adi_ad9081_hal_calc_nco_ftw_f(adi_ad9081_device_t *device, double freq, double nco_shift, uint64_t *ftw, diff --git a/drivers/iio/adc/ad9081/adi_ad9081_dac.c b/drivers/iio/adc/ad9081/adi_ad9081_dac.c index 9cf3f4d401683f..b98dfdb97ba189 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_dac.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_dac.c @@ -16,6 +16,37 @@ /*============= I N C L U D E S ============*/ #include "adi_ad9081_config.h" #include "adi_ad9081_hal.h" +/*============= M A C R O S ====================*/ +#define AD9081_R2R_DAC_CAL_ADDR 0x17 +#define AD9081_R2R_DAC_CAL_CFG 0x4F +#define AD9081_DAC_CAL_RUN_CFG 0x22 +#define AD9081_DAC_CAL_COMP_SPEED 0x1 +#define AD9081_DAC_CAL_THROWAWAY_CURR_CFG 0x11 +/*============= H E L P E R ====================*/ +/** + * @brief Run Startup DAC Cals + * Run After Startup, during startup + * @param device Pointer to the device structure. + * @param dacs Mask of Target DACs, refer to enum adi_ad9081_dac_select_e + + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_dac_run_startup_cal(adi_ad9081_device_t *device, + uint8_t dacs); + +/** + * @brief Run Startup DAC Cals + * Run After Startup, during startup + * @param device Pointer to the device structure. + * @param config Config Setting for R2R Cals, Do Not Modify. Use ADI recommended Setting (0x79) + * @param dacs Mask of Target DACs, refer to enum adi_ad9081_dac_select_e + + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_dac_r2r_cal_config_set(adi_ad9081_device_t *device, + uint8_t config, uint8_t dacs); /*============= C O D E ====================*/ int32_t adi_ad9081_dac_select_set(adi_ad9081_device_t *device, uint8_t dacs) @@ -69,73 +100,82 @@ int32_t adi_ad9081_dac_d2a_dual_spi_enable_set(adi_ad9081_device_t *device, } int32_t adi_ad9081_dac_mode_switch_group_select_set( - adi_ad9081_device_t *device, - adi_ad9081_dac_mode_switch_group_select_e group) + adi_ad9081_device_t *device, adi_ad9081_dac_pair_select_e dac_pair) { AD9081_NULL_POINTER_RETURN(device); AD9081_LOG_FUNC(); return adi_ad9081_hal_bf_set(device, REG_PAGEINDX_DAC_JRX_ADDR, - BF_MODS_MSK_INFO, group); + BF_MODS_MSK_INFO, dac_pair); } int32_t -adi_ad9081_dac_mode_set(adi_ad9081_device_t *device, - adi_ad9081_dac_mode_switch_group_select_e groups, - adi_ad9081_dac_mode_e mode) +adi_ad9081_dac_modulation_mux_mode_set(adi_ad9081_device_t *device, + adi_ad9081_dac_pair_select_e dac_pair, + adi_ad9081_dac_mod_mux_mode_e mode) { int32_t err; AD9081_NULL_POINTER_RETURN(device); AD9081_LOG_FUNC(); - - if ((groups & AD9081_DAC_MODE_SWITCH_GROUP_0) > 0) { - err = adi_ad9081_dac_mode_switch_group_select_set( - device, AD9081_DAC_MODE_SWITCH_GROUP_0); - AD9081_ERROR_RETURN(err); - err = adi_ad9081_hal_bf_set(device, REG_DDSM_DATAPATH_CFG_ADDR, - BF_DDSM_MODE_INFO, - mode); /* paged */ - AD9081_ERROR_RETURN(err); - } - if ((groups & AD9081_DAC_MODE_SWITCH_GROUP_1) > 0) { - err = adi_ad9081_dac_mode_switch_group_select_set( - device, AD9081_DAC_MODE_SWITCH_GROUP_1); - AD9081_ERROR_RETURN(err); - err = adi_ad9081_hal_bf_set(device, REG_DDSM_DATAPATH_CFG_ADDR, - BF_DDSM_MODE_INFO, - mode); /* paged */ - AD9081_ERROR_RETURN(err); - } - + if (((mode > 0x3) || (mode < 0) || (dac_pair == 0))) { + AD9081_INVALID_PARAM_RETURN(1); + }; + err = adi_ad9081_dac_mode_switch_group_select_set(device, dac_pair); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_DDSM_DATAPATH_CFG_ADDR, + BF_DDSM_MODE_INFO, mode); /* paged */ + err = adi_ad9081_dac_mode_switch_group_select_set(device, + AD9081_DAC_PAIR_NONE); + AD9081_ERROR_RETURN(err); +#if 0 + if ((dac_pair & AD9081_DAC_PAIR_0_1) > 0) { + err = adi_ad9081_dac_mode_switch_group_select_set(device, AD9081_DAC_MODE_SWITCH_GROUP_0); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_DDSM_DATAPATH_CFG_ADDR, BF_DDSM_MODE_INFO, mode); /* paged */ + AD9081_ERROR_RETURN(err); + } + if ((dac_pair & AD9081_DAC_PAIR_2_3) > 0) { + err = adi_ad9081_dac_mode_switch_group_select_set(device, AD9081_DAC_MODE_SWITCH_GROUP_1); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_DDSM_DATAPATH_CFG_ADDR, BF_DDSM_MODE_INFO, mode); /* paged */ + AD9081_ERROR_RETURN(err); + } +#endif return API_CMS_ERROR_OK; } int32_t adi_ad9081_dac_complex_modulation_enable_set( - adi_ad9081_device_t *device, - adi_ad9081_dac_mode_switch_group_select_e groups, uint8_t enable) + adi_ad9081_device_t *device, adi_ad9081_dac_pair_select_e dac_pair, + uint8_t enable) { int32_t err; AD9081_NULL_POINTER_RETURN(device); AD9081_LOG_FUNC(); - - if ((groups & AD9081_DAC_MODE_SWITCH_GROUP_0) > 0) { - err = adi_ad9081_dac_mode_switch_group_select_set( - device, AD9081_DAC_MODE_SWITCH_GROUP_0); - AD9081_ERROR_RETURN(err); - err = adi_ad9081_hal_bf_set(device, REG_DDSM_DATAPATH_CFG_ADDR, - BF_EN_CMPLX_MODULATION_INFO, - enable); /* paged */ - AD9081_ERROR_RETURN(err); - } - if ((groups & AD9081_DAC_MODE_SWITCH_GROUP_1) > 0) { - err = adi_ad9081_dac_mode_switch_group_select_set( - device, AD9081_DAC_MODE_SWITCH_GROUP_1); - AD9081_ERROR_RETURN(err); - err = adi_ad9081_hal_bf_set(device, REG_DDSM_DATAPATH_CFG_ADDR, - BF_EN_CMPLX_MODULATION_INFO, - enable); /* paged */ - AD9081_ERROR_RETURN(err); - } - + if (((enable > 1) || (dac_pair == 0x0))) { + AD9081_INVALID_PARAM_RETURN(1); + }; + err = adi_ad9081_dac_mode_switch_group_select_set(device, dac_pair); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_DDSM_DATAPATH_CFG_ADDR, + BF_EN_CMPLX_MODULATION_INFO, + enable); /* paged */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_dac_mode_switch_group_select_set(device, + AD9081_DAC_PAIR_NONE); + AD9081_ERROR_RETURN(err); +#if 0 + if ((dac_pair & AD9081_DAC_MODE_SWITCH_GROUP_0) > 0) { + err = adi_ad9081_dac_mode_switch_group_select_set(device, AD9081_DAC_MODE_SWITCH_GROUP_0); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_DDSM_DATAPATH_CFG_ADDR, BF_EN_CMPLX_MODULATION_INFO, enable); /* paged */ + AD9081_ERROR_RETURN(err); + } + if ((dac_pair & AD9081_DAC_MODE_SWITCH_GROUP_1) > 0) { + err = adi_ad9081_dac_mode_switch_group_select_set(device, AD9081_DAC_MODE_SWITCH_GROUP_1); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_DDSM_DATAPATH_CFG_ADDR, BF_EN_CMPLX_MODULATION_INFO, enable); /* paged */ + AD9081_ERROR_RETURN(err); + } +#endif return API_CMS_ERROR_OK; } @@ -1713,7 +1753,7 @@ int32_t adi_ad9081_dac_duc_main_dsa_set(adi_ad9081_device_t *device, } int32_t adi_ad9081_dac_fsc_set(adi_ad9081_device_t *device, uint8_t dacs, - uint32_t uA) + uint32_t uA, uint8_t rerun_cal) { int32_t err; uint8_t i, dac, min_code; @@ -1721,12 +1761,15 @@ int32_t adi_ad9081_dac_fsc_set(adi_ad9081_device_t *device, uint8_t dacs, uint32_t min_fsc, cf, ff; AD9081_NULL_POINTER_RETURN(device); AD9081_LOG_FUNC(); - if (uA > 40000) + if (uA > 40000) { AD9081_LOG_WARN( "full-scale current beyond design recommendation (7mA - 40mA)"); + } if (uA < 7000) AD9081_LOG_WARN( "full-scale current beyond design recommendation (7mA - 40mA)"); + if (rerun_cal > 1) + AD9081_INVALID_PARAM_RETURN(device); for (i = 0; i < 4; i++) { dac = dacs & (AD9081_DAC_0 << i); @@ -1778,6 +1821,10 @@ int32_t adi_ad9081_dac_fsc_set(adi_ad9081_device_t *device, uint8_t dacs, AD9081_ERROR_RETURN(err); } } + if (rerun_cal) { + err = adi_ad9081_dac_run_startup_cal(device, dacs); + } + AD9081_ERROR_RETURN(err); return API_CMS_ERROR_OK; } @@ -1883,8 +1930,8 @@ int32_t adi_ad9081_dac_nco_sync_set(adi_ad9081_device_t *device, AD9081_INVALID_PARAM_RETURN(align_source > 4); if (align_source == 0) { /* oneshot */ - err = adi_ad9081_jesd_oneshot_sync(device); - AD9081_ERROR_RETURN(err); + /*err = adi_ad9081_jesd_oneshot_sync(device); + AD9081_ERROR_RETURN(err);*/ } else if (align_source == 1) { /* spi */ err = adi_ad9081_dac_nco_reset_set(device); AD9081_ERROR_RETURN(err); @@ -1948,4 +1995,142 @@ int32_t adi_ad9081_dac_nco_master_slave_sync(adi_ad9081_device_t *device, return API_CMS_ERROR_OK; } +int32_t adi_ad9081_dac_r2r_cal_config_set(adi_ad9081_device_t *device, + uint8_t config, uint8_t dacs) +{ + int32_t err; + uint8_t i = 0; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + /*Page Target Dacs*/ + err = adi_ad9081_dac_select_set(device, dacs); + AD9081_ERROR_RETURN(err); + + /*set cal config*/ + err = adi_ad9081_hal_bf_set(device, REG_CAL_DEBUG0_ADDR, 0x00000103, 0); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_CAL_DEBUG0_ADDR, 0x00000102, 1); + AD9081_ERROR_RETURN(err); + + /*Set R2R Cal Config*/ + for (i = 0; i < 8; i++) { + err = adi_ad9081_hal_bf_set(device, (0x00000111), 0x00000600, + AD9081_R2R_DAC_CAL_ADDR + i); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, (0x00000112), 0x00000700, + config); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, (REG_CAL_CTRL_ADDR), + 0x00000103, 1); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_delay_us(device, 1000); + err = adi_ad9081_hal_bf_set(device, (REG_CAL_CTRL_ADDR), + 0x00000103, 0); + AD9081_ERROR_RETURN(err); + } + + /*set cal config*/ + err = adi_ad9081_hal_bf_set(device, REG_CAL_DEBUG0_ADDR, 0x00000103, 1); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_CAL_DEBUG0_ADDR, 0x00000102, 0); + AD9081_ERROR_RETURN(err); + return API_CMS_ERROR_OK; +} +int32_t adi_ad9081_dac_run_startup_cal(adi_ad9081_device_t *device, + uint8_t dacs) +{ + int32_t err; + uint8_t i = 0, reg_val = 0x00, dac = 0; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + /*Page Target Dacs*/ + err = adi_ad9081_dac_select_set(device, dacs); + + /*Setup Calibration Clocks*/ + /*Power Up CAL CLKS for target DACs*/ + err = adi_ad9081_hal_reg_get(device, REG_CLK_CTRL2_ADDR, ®_val); + AD9081_ERROR_RETURN(err); + reg_val &= ~0x0F; + reg_val |= dacs; + err = adi_ad9081_hal_reg_set(device, REG_CLK_CTRL2_ADDR, reg_val); + + /*Set Cal Div*/ + err = adi_ad9081_hal_bf_set(device, 0x0000010E, 0x00000400, 0x8); + AD9081_ERROR_RETURN(err); + + /*Disable Ring Osc Set CAL CLK source to be DAC CLK*/ + err = adi_ad9081_hal_bf_set(device, REG_RING_OSC_ADDR, + BF_RINGOSC_EN_INFO, 0); + AD9081_ERROR_RETURN(err); + + err = adi_ad9081_hal_reg_get(device, 0x0000019C, ®_val); + AD9081_ERROR_RETURN(err); + reg_val &= ~0x0F; + for (i = 0; i < 4; i++) { + dac = dacs & (AD9081_DAC_0 << i); + if (dac > 0) { + reg_val |= ~(AD9081_DAC_0 << i); + } + } + err = adi_ad9081_hal_reg_set(device, 0x0000019C, reg_val); + AD9081_ERROR_RETURN(err); + + /*Reset CAL Status*/ + err = adi_ad9081_hal_bf_set(device, REG_CAL_CTRL_ADDR, + BF_CAL_RESETB_INFO, 0); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_CAL_CTRL_ADDR, + BF_CAL_RESETB_INFO, 1); + AD9081_ERROR_RETURN(err); + + /*Set Calibration Config: cal settings*/ + err = adi_ad9081_hal_bf_set(device, REG_CAL_DEBUG0_ADDR, 0x00000106, 1); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_CAL_DEBUG0_ADDR, 0x00000103, 1); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_CAL_DEBUG0_ADDR, + BF_CAL_EN_G_INFO, 1); + AD9081_ERROR_RETURN(err); + /*CAL_MODE to GMode(0x1)*/ + err = adi_ad9081_hal_bf_set(device, REG_CAL_CTRL_ADDR, BF_CAL_MODE_INFO, + 1); + AD9081_ERROR_RETURN(err); + + /*Set Calibration Config: cal run settings with ADI Recommended Settings*/ + err = adi_ad9081_hal_reg_set(device, 0x0000011D, + AD9081_DAC_CAL_RUN_CFG); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, 0x00000127, 0x00000200, + AD9081_DAC_CAL_COMP_SPEED); + AD9081_ERROR_RETURN(err); + + /*Set Throwaway Currents*/ + for (i = 0; i < 7; i++) { + err = adi_ad9081_hal_reg_set(device, 0x00000128 + i, + AD9081_DAC_CAL_THROWAWAY_CURR_CFG); + AD9081_ERROR_RETURN(err); + } + err = adi_ad9081_hal_reg_set(device, 0x00000128 + i, 0x01); + AD9081_ERROR_RETURN(err); + + /*Trigger Cal Start*/ + err = adi_ad9081_hal_bf_set(device, REG_CAL_CTRL_ADDR, + BF_CAL_START_INFO, 0x1); + AD9081_ERROR_RETURN(err); + + /*Delay*/ + err = adi_ad9081_hal_delay_us(device, 1000); + AD9081_ERROR_RETURN(err); + + for (i = 0; i < 4; i++) { + dac = dacs & (AD9081_DAC_0 << i); + if (dac > 0) { + err = adi_ad9081_dac_r2r_cal_config_set(device, 79, + dac); + AD9081_ERROR_RETURN(err); + } + } + return API_CMS_ERROR_OK; +} /*! @} */ \ No newline at end of file diff --git a/drivers/iio/adc/ad9081/adi_ad9081_device.c b/drivers/iio/adc/ad9081/adi_ad9081_device.c index 22a4ae58855767..b5481e39da460e 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_device.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_device.c @@ -17,6 +17,7 @@ #include "adi_ad9081_config.h" #include "adi_ad9081_hal.h" +#define DEFAULT_DAC_FULLSCALE_CURRENT 26000 /*26mA*/ /*============= C O D E ====================*/ int32_t adi_ad9081_device_boot_pre_clock(adi_ad9081_device_t *device) { @@ -40,22 +41,21 @@ int32_t adi_ad9081_device_boot_pre_clock(adi_ad9081_device_t *device) } if (core_status < 0x71) { /* boot has some problem */ + AD9081_LOG_ERR("Pre Clock Boot Sequence Error"); AD9081_LOG_ERR( - "Boot did not reach expected spot in boot_pre_clock()"); + "Please check power supplies (no open, no short, no big glitches)"); + AD9081_LOG_ERR("Ensure Clocks are available"); /* log msg regs when error happens */ err = adi_ad9081_hal_reg_get(device, 0x3740, &core_status); /* @msg0 */ - AD9081_ERROR_RETURN(err); err = adi_ad9081_hal_reg_get(device, 0x3741, &core_status); /* @msg1 */ - AD9081_ERROR_RETURN(err); err = adi_ad9081_hal_reg_get(device, 0x3742, &core_status); /* @msg2 */ - AD9081_ERROR_RETURN(err); err = adi_ad9081_hal_reg_get(device, 0x3743, &core_status); /* @msg3 */ - AD9081_ERROR_RETURN(err); + AD9081_ERROR_RETURN(API_CMS_ERROR_INIT_SEQ_FAIL); } /* log chip id */ @@ -172,16 +172,19 @@ int32_t adi_ad9081_device_boot_post_clock(adi_ad9081_device_t *device) /* check core status */ err = adi_ad9081_hal_reg_get(device, 0x3742, &core_status); /* @msg2 */ AD9081_ERROR_RETURN(err); - if (core_status < 0xF0) + if (core_status < 0xF0) { AD9081_LOG_ERR( "Boot did not reach spot where it waits for application code"); - + AD9081_ERROR_RETURN(API_CMS_ERROR_INIT_SEQ_FAIL); + } /* verify clock switch is done */ err = adi_ad9081_hal_bf_get(device, 0x3740, 0x0103, &clk_switch_done, 1); /* @msg0 */ AD9081_ERROR_RETURN(err); - if (clk_switch_done == 0x0) + if (clk_switch_done == 0x0) { AD9081_LOG_ERR("Clock switch not done"); + AD9081_ERROR_RETURN(API_CMS_ERROR_INIT_SEQ_FAIL); + } /* additional write, AD9081API-680 */ err = adi_ad9081_hal_reg_set(device, 0x2112, 0x01); @@ -333,7 +336,7 @@ int32_t adi_ad9081_device_clk_pll_div_set(adi_ad9081_device_t *device, AD9081_ERROR_RETURN(err); /* check pll lock status */ - for (i = 0; i < 50; i++) { + for (i = 0; i < AD9081_PLL_LOCK_TRY; i++) { err = adi_ad9081_hal_delay_us(device, AD9081_PLL_LOCK_WAIT); AD9081_ERROR_RETURN(err); err = adi_ad9081_device_clk_pll_lock_status_get(device, @@ -838,7 +841,7 @@ int32_t adi_ad9081_device_init(adi_ad9081_device_t *device) "api v%d.%d.%d commit %s for ad%x ", (AD9081_API_REV & 0xff0000) >> 16, (AD9081_API_REV & 0xff00) >> 8, - (AD9081_API_REV & 0xff), "dd0c993", + (AD9081_API_REV & 0xff), "e1ac8d2", AD9081_ID); AD9081_ERROR_RETURN(err); @@ -979,13 +982,13 @@ int32_t adi_ad9081_device_reset(adi_ad9081_device_t *device, (operation == AD9081_HARD_RESET_AND_INIT)) { err = adi_ad9081_hal_reset_pin_ctrl(device, 0); AD9081_ERROR_RETURN(err); - err = adi_ad9081_hal_delay_us(device, 100000); + err = adi_ad9081_hal_delay_us(device, AD9081_API_HW_RESET_LOW); AD9081_ERROR_RETURN(err); err = adi_ad9081_hal_reset_pin_ctrl(device, 1); AD9081_ERROR_RETURN(err); - err = adi_ad9081_hal_delay_us(device, 100000); - AD9081_ERROR_RETURN(err); } + err = adi_ad9081_hal_delay_us(device, AD9081_API_RESET_WAIT); + AD9081_ERROR_RETURN(err); /* do init */ if ((operation == AD9081_SOFT_RESET_AND_INIT) || @@ -1306,7 +1309,8 @@ int32_t adi_ad9081_device_startup_tx_or_nco_test( AD9081_ERROR_RETURN(err); /* set default current */ - err = adi_ad9081_dac_fsc_set(device, used_dacs, 26000); + err = adi_ad9081_dac_fsc_set(device, used_dacs, + DEFAULT_DAC_FULLSCALE_CURRENT, 1); AD9081_ERROR_RETURN(err); /* setup interpolation */ @@ -1323,9 +1327,6 @@ int32_t adi_ad9081_device_startup_tx_or_nco_test( AD9081_ERROR_RETURN(err); err = adi_ad9081_jesd_rx_bring_up(device, links, 0xff); AD9081_ERROR_RETURN(err); - err = adi_ad9081_jesd_sysref_enable_set( - device, jesd_param->jesd_subclass > 0 ? 1 : 0); - AD9081_ERROR_RETURN(err); } /* set xbar (used channels by each DAC) */ @@ -1374,10 +1375,6 @@ int32_t adi_ad9081_device_startup_tx_or_nco_test( err = adi_ad9081_dac_irqs_enable_set(device, 0x0030cccc00); AD9081_ERROR_RETURN(err); - /* one shot sync */ - err = adi_ad9081_jesd_oneshot_sync(device); - AD9081_ERROR_RETURN(err); - return API_CMS_ERROR_OK; } @@ -1482,19 +1479,19 @@ int32_t adi_ad9081_device_startup_rx(adi_ad9081_device_t *device, uint8_t cddcs, fc2r_en); AD9081_ERROR_RETURN(err); - /* configure jtx links */ links = jesd_param[0].jesd_duallink > 0 ? AD9081_LINK_ALL : AD9081_LINK_0; + /* Configure ADC o/P Resolution*/ + err = adi_ad9081_jesd_tx_res_sel_set(device, links, + jesd_param[0].jesd_n); + AD9081_ERROR_RETURN(err); + /* configure jtx links */ err = adi_ad9081_jesd_tx_link_conv_sel_set(device, links, jesd_conv_sel, jesd_m); AD9081_ERROR_RETURN(err); err = adi_ad9081_jesd_tx_link_config_set(device, links, &jesd_param[0]); AD9081_ERROR_RETURN(err); - /* one shot sync */ - err = adi_ad9081_jesd_oneshot_sync(device); - AD9081_ERROR_RETURN(err); - return API_CMS_ERROR_OK; } diff --git a/drivers/iio/adc/ad9081/adi_ad9081_hal.c b/drivers/iio/adc/ad9081/adi_ad9081_hal.c index ea303df49e365f..dfbeaaab4d6a3f 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_hal.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_hal.c @@ -66,23 +66,6 @@ int32_t adi_ad9081_hal_reset_pin_ctrl(adi_ad9081_device_t *device, return API_CMS_ERROR_OK; } -int32_t adi_ad9081_hal_sysref_ctrl(adi_ad9081_device_t *device, - uint8_t enable) -{ - AD9081_NULL_POINTER_RETURN(device); - - /* Optional callback */ - if (!device->hal_info.sysref_ctrl) - return API_CMS_ERROR_OK; - - if (device->hal_info.sysref_ctrl(device->hal_info.user_data, enable) - != API_CMS_ERROR_OK) { - return API_CMS_ERROR_ERROR; - } - - return API_CMS_ERROR_OK; -} - int32_t adi_ad9081_hal_log_write(adi_ad9081_device_t *device, adi_cms_log_type_e log_type, const char *comment, ...) diff --git a/drivers/iio/adc/ad9081/adi_ad9081_hal.h b/drivers/iio/adc/ad9081/adi_ad9081_hal.h index 0b44ca8703c86a..da1a64410575cc 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_hal.h +++ b/drivers/iio/adc/ad9081/adi_ad9081_hal.h @@ -26,13 +26,45 @@ extern "C" { #endif +/** + * \brief Open and initialize resources and peripherals required for the TxFE device. + * + * \param[in] device Pointer to device handler structure. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, API_CMS_ERROR_HW_OPEN failure code. + */ int32_t adi_ad9081_hal_hw_open(adi_ad9081_device_t *device); + +/** + * \brief Shutdown and close any resources opened by adi_aegir_hal_hw_open. + * + * \param[in] device Pointer to device handler structure. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, API_CMS_ERROR_HW_CLOSE failure code. + */ int32_t adi_ad9081_hal_hw_close(adi_ad9081_device_t *device); + +/** + * \brief Perform a wait/thread sleep in units of microseconds. + * + * \param[in] device Pointer to device handler structure. + * \param[in] us Delay duration in microseconds. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, API_CMS_ERROR_DELAY_US failure code. + */ int32_t adi_ad9081_hal_delay_us(adi_ad9081_device_t *device, uint32_t us); + +/** + * \brief Set ADI device RESETB pin high or low. + * + * \param[in] device Pointer to device handler structure. + * \param[in] enable 0: set RESETB pin low, 1: set RESETB pin high. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, API_CMS_ERROR_RESET_PIN_CTRL failure code. + */ int32_t adi_ad9081_hal_reset_pin_ctrl(adi_ad9081_device_t *device, uint8_t enable); -int32_t adi_ad9081_hal_sysref_ctrl(adi_ad9081_device_t *device, - uint8_t enable); + int32_t adi_ad9081_hal_log_write(adi_ad9081_device_t *device, adi_cms_log_type_e type, const char *comment, ...); diff --git a/drivers/iio/adc/ad9081/adi_ad9081_jesd.c b/drivers/iio/adc/ad9081/adi_ad9081_jesd.c index 70e58574a9cc78..10398632723eaa 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_jesd.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_jesd.c @@ -3071,16 +3071,20 @@ int32_t adi_ad9081_jesd_tx_res_sel_set(adi_ad9081_device_t *device, uint8_t resolution) { int32_t err; + uint8_t res_setting = 0; AD9081_NULL_POINTER_RETURN(device); AD9081_LOG_FUNC(); + if (resolution > 16 || resolution < 8) + AD9081_INVALID_PARAM_RETURN(device); if ((links & AD9081_LINK_0) > 0) { err = adi_ad9081_jesd_tx_link_select_set(device, AD9081_LINK_0); AD9081_ERROR_RETURN(err); /* 0: 16bit, 1: 15bit, 2: 14bit, 3: 13bit, 4: 12bit, ..., 8: 8bit */ + res_setting = 16 - resolution; err = adi_ad9081_hal_bf_set(device, REG_OUT_RES_ADDR, BF_DFORMAT_RES_INFO, - resolution); /* paged */ + res_setting); /* paged */ AD9081_ERROR_RETURN(err); } if ((links & AD9081_LINK_1) > 0) { @@ -3088,7 +3092,7 @@ int32_t adi_ad9081_jesd_tx_res_sel_set(adi_ad9081_device_t *device, AD9081_ERROR_RETURN(err); err = adi_ad9081_hal_bf_set(device, REG_OUT_RES_ADDR, BF_DFORMAT_RES_INFO, - resolution); /* paged */ + res_setting); /* paged */ AD9081_ERROR_RETURN(err); } @@ -4062,53 +4066,6 @@ adi_ad9081_jesd_tx_jtspat_enable_set(adi_ad9081_device_t *device, return API_CMS_ERROR_OK; } -int32_t adi_ad9081_jesd_sysref_enable_set(adi_ad9081_device_t *device, - uint8_t enable) -{ - int32_t err; - AD9081_NULL_POINTER_RETURN(device); - AD9081_LOG_FUNC(); - - /* Power down the sysref receiver and sync circuitry. */ - err = adi_ad9081_hal_bf_set(device, REG_SYSREF_CTRL_ADDR, - BF_SYSREF_PD_INFO, !enable); /* not paged */ - AD9081_ERROR_RETURN(err); - - return API_CMS_ERROR_OK; -} - -int32_t adi_ad9081_jesd_sysref_spi_enable_set(adi_ad9081_device_t *device, - uint8_t enable) -{ - int32_t err; - AD9081_NULL_POINTER_RETURN(device); - AD9081_LOG_FUNC(); - - /* enables sysref capture */ - err = adi_ad9081_hal_bf_set( - device, 0x0fb0, 0x0103, - enable); /* not paged, spi_sysref_en@sysref_control */ - AD9081_ERROR_RETURN(err); - - return API_CMS_ERROR_OK; -} - -int32_t adi_ad9081_jesd_sysref_input_mode_set(adi_ad9081_device_t *device, - uint8_t input_mode) -{ - int32_t err; - AD9081_NULL_POINTER_RETURN(device); - AD9081_LOG_FUNC(); - - /* 0: AC couple, 1: DC couple */ - err = adi_ad9081_hal_bf_set(device, REG_SYSREF_CTRL_ADDR, - BF_SYSREF_INPUTMODE_INFO, - input_mode); /* not paged */ - AD9081_ERROR_RETURN(err); - - return API_CMS_ERROR_OK; -} - int32_t adi_ad9081_jesd_pll_lock_status_get(adi_ad9081_device_t *device, uint8_t *jesd_pll_status) { @@ -4138,78 +4095,6 @@ int32_t adi_ad9081_jesd_loopback_mode_set(adi_ad9081_device_t *device, return API_CMS_ERROR_OK; } -int32_t adi_ad9081_jesd_oneshot_sync(adi_ad9081_device_t *device) -{ - int32_t err; - uint8_t pd_fdacby4, sync_done; - AD9081_NULL_POINTER_RETURN(device); - AD9081_LOG_FUNC(); - - err = adi_ad9081_hal_bf_get(device, REG_CLK_CTRL1_ADDR, 0x00000102, - &pd_fdacby4, 1); /* not paged */ - AD9081_ERROR_RETURN(err); - err = adi_ad9081_hal_bf_set(device, REG_CLK_CTRL1_ADDR, 0x00000102, - 0); /* not paged */ - AD9081_ERROR_RETURN(err); - err = adi_ad9081_hal_bf_set(device, REG_ROTATION_MODE_ADDR, - BF_ROTATION_MODE_INFO, 1); /* not paged */ - AD9081_ERROR_RETURN(err); - - if (device->dev_info.dev_rev == 3) { /* r2 */ - err = adi_ad9081_hal_bf_set(device, REG_ACLK_CTRL_ADDR, - BF_PD_TXDIGCLK_INFO, - 1); /* not paged */ - AD9081_ERROR_RETURN(err); - err = adi_ad9081_hal_bf_set(device, REG_ADC_DIVIDER_CTRL_ADDR, - 0x00000107, 0); /* not paged */ - AD9081_ERROR_RETURN(err); - } - - err = adi_ad9081_hal_bf_set(device, REG_SYSREF_MODE_ADDR, - BF_SYSREF_MODE_ONESHOT_INFO, - 0); /* not paged */ - AD9081_ERROR_RETURN(err); - err = adi_ad9081_hal_bf_set(device, REG_SYSREF_MODE_ADDR, - BF_SYSREF_MODE_ONESHOT_INFO, - 1); /* not paged */ - AD9081_ERROR_RETURN(err); - - err = adi_ad9081_hal_sysref_ctrl(device, 1); - AD9081_ERROR_RETURN(err); - - if (err = adi_ad9081_hal_bf_wait_to_clear( - device, REG_SYSREF_MODE_ADDR, - BF_SYSREF_MODE_ONESHOT_INFO), /* not paged */ - err != API_CMS_ERROR_OK) { - AD9081_LOG_ERR("sysref_mode_oneshot bit never cleared."); - } - err = adi_ad9081_hal_bf_get(device, REG_SYSREF_MODE_ADDR, - BF_ONESHOT_SYNC_DONE_INFO, &sync_done, - 1); /* not paged */ - AD9081_ERROR_RETURN(err); - if (sync_done != 1) { - AD9081_LOG_ERR("oneshot sync not finished."); - } - - err = adi_ad9081_hal_sysref_ctrl(device, 0); - AD9081_ERROR_RETURN(err); - - if (device->dev_info.dev_rev == 3) { /* r2 */ - err = adi_ad9081_hal_bf_set(device, REG_ADC_DIVIDER_CTRL_ADDR, - 0x00000107, 1); /* not paged */ - AD9081_ERROR_RETURN(err); - err = adi_ad9081_hal_bf_set(device, REG_ACLK_CTRL_ADDR, - BF_PD_TXDIGCLK_INFO, - 0); /* not paged */ - AD9081_ERROR_RETURN(err); - } - err = adi_ad9081_hal_bf_set(device, REG_CLK_CTRL1_ADDR, 0x00000102, - pd_fdacby4); /* not paged */ - AD9081_ERROR_RETURN(err); - - return API_CMS_ERROR_OK; -} - uint16_t adi_ad9081_jesd_find_dformat_out_nc( adi_ad9081_jtx_conv_sel_t const *jesd_conv_sel, uint8_t jesd_m) { diff --git a/drivers/iio/adc/ad9081/adi_ad9081_sync.c b/drivers/iio/adc/ad9081/adi_ad9081_sync.c new file mode 100644 index 00000000000000..b8009235d59906 --- /dev/null +++ b/drivers/iio/adc/ad9081/adi_ad9081_sync.c @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: GPL-2.0 +/*! + * @brief APIs for SYSREF configuration and control + * + * @copyright copyright(c) 2018 analog devices, inc. all rights reserved. + * This software is proprietary to Analog Devices, Inc. and its + * licensor. By using this software you agree to the terms of the + * associated analog devices software license agreement. + */ + +/*! + * @addtogroup AD9081_SYSREF_API + * @{ + */ + +/*============= I N C L U D E S ============*/ +#include "adi_ad9081_config.h" +#include "adi_ad9081_hal.h" + +/*============= C O D E ====================*/ + +int32_t adi_ad9081_jesd_sysref_enable_set(adi_ad9081_device_t *device, + uint8_t enable) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + /* Power down the sysref receiver and sync circuitry. */ + err = adi_ad9081_hal_bf_set(device, REG_SYSREF_CTRL_ADDR, + BF_SYSREF_PD_INFO, !enable); /* not paged */ + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_jesd_sysref_d2acenter_enable_set(adi_ad9081_device_t *device, + uint8_t enable) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + err = adi_ad9081_hal_bf_set(device, REG_SPI_ENABLE_DAC_ADDR, + BF_SPI_EN_D2ACENTER_INFO, enable); + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_jesd_sysref_input_mode_set( + adi_ad9081_device_t *device, uint8_t enable_receiver, + uint8_t enable_capture, adi_cms_signal_coupling_e input_mode) +{ + int32_t err; + AD9081_LOG_FUNC(); + AD9081_NULL_POINTER_RETURN(device); + if ((input_mode >= COUPLING_UNKNOWN) || (input_mode < 0)) { + return API_CMS_ERROR_INVALID_PARAM; + } + + adi_ad9081_jesd_sysref_d2acenter_enable_set(device, 1); + + /* 1: AC couple, 0: DC couple */ + err = adi_ad9081_hal_bf_set( + device, REG_SYSREF_CTRL_ADDR, BF_SYSREF_INPUTMODE_INFO, + ((input_mode == COUPLING_AC) ? 1 : 0)); /* not paged */ + AD9081_ERROR_RETURN(err); + + /* Power down the sysref receiver and sync circuitry. */ + err = adi_ad9081_hal_bf_set(device, REG_SYSREF_CTRL_ADDR, + BF_SYSREF_PD_INFO, + !enable_receiver); /* not paged */ + AD9081_ERROR_RETURN(err); + + /* enables sysref capture */ + err = adi_ad9081_hal_bf_set( + device, 0x0fb0, 0x0103, + enable_capture); /* not paged, spi_sysref_en@sysref_control */ + AD9081_ERROR_RETURN(err); + + adi_ad9081_jesd_sysref_d2acenter_enable_set(device, 0); + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_jesd_oneshot_sync(adi_ad9081_device_t *device, + adi_cms_jesd_subclass_e subclass) +{ + int32_t err; + uint8_t pd_fdacby4, sync_done; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + if (subclass == JESD_SUBCLASS_0) { + adi_ad9081_jesd_tx_force_digital_reset_set( + device, AD9081_LINK_ALL, + 1); /* FORCE_LINK_RESET if subclass 0 */ + } + + err = adi_ad9081_hal_bf_get(device, REG_CLK_CTRL1_ADDR, 0x00000102, + &pd_fdacby4, 1); /* not paged */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_CLK_CTRL1_ADDR, 0x00000102, + 0); /* not paged */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_ROTATION_MODE_ADDR, + BF_ROTATION_MODE_INFO, 1); /* not paged */ + AD9081_ERROR_RETURN(err); + + //d2a0, d2a1, anacenter + err = adi_ad9081_dac_d2a_dual_spi_enable_set(device, AD9081_LINK_ALL, + 1); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_SPI_ENABLE_DAC_ADDR, + BF_SPI_EN_ANACENTER_INFO, 1); + AD9081_ERROR_RETURN(err); + + if (device->dev_info.dev_rev == 3) { /* r2 */ + err = adi_ad9081_hal_bf_set(device, REG_ACLK_CTRL_ADDR, + BF_PD_TXDIGCLK_INFO, + 1); /* not paged */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_ADC_DIVIDER_CTRL_ADDR, + 0x00000107, 0); /* not paged */ + AD9081_ERROR_RETURN(err); + } + + err = adi_ad9081_hal_bf_set(device, REG_SYSREF_MODE_ADDR, + BF_SYSREF_MODE_ONESHOT_INFO, + 0); /* not paged */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_SYSREF_MODE_ADDR, + BF_SYSREF_MODE_ONESHOT_INFO, + 1); /* not paged */ + AD9081_ERROR_RETURN(err); + if (err = adi_ad9081_hal_bf_wait_to_clear( + device, REG_SYSREF_MODE_ADDR, + BF_SYSREF_MODE_ONESHOT_INFO), /* not paged */ + err != API_CMS_ERROR_OK) { + AD9081_LOG_WARN("sysref_mode_oneshot bit never cleared."); + } + err = adi_ad9081_hal_bf_get(device, REG_SYSREF_MODE_ADDR, + BF_ONESHOT_SYNC_DONE_INFO, &sync_done, + 1); /* not paged */ + AD9081_ERROR_RETURN(err); + if (sync_done != 1) { + AD9081_LOG_WARN("oneshot sync not finished."); + } + + if (device->dev_info.dev_rev == 3) { /* r2 */ + err = adi_ad9081_hal_bf_set(device, REG_ADC_DIVIDER_CTRL_ADDR, + 0x00000107, 1); /* not paged */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_ACLK_CTRL_ADDR, + BF_PD_TXDIGCLK_INFO, + 0); /* not paged */ + AD9081_ERROR_RETURN(err); + } + err = adi_ad9081_hal_bf_set(device, REG_CLK_CTRL1_ADDR, 0x00000102, + pd_fdacby4); /* not paged */ + AD9081_ERROR_RETURN(err); + + if (subclass == JESD_SUBCLASS_0) { + adi_ad9081_jesd_tx_force_digital_reset_set( + device, AD9081_LINK_ALL, + 0); /* FORCE_LINK_RESET if subclass 0 */ + if (sync_done != 1) { + return API_CMS_ERROR_JESD_SYNC_NOT_DONE; + } + } + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_jesd_sysref_setup_hold_get(adi_ad9081_device_t *device, + uint8_t *setup_risk_violation, + uint8_t *hold_risk_violation) +{ + int32_t err; + uint8_t i = 0; + uint8_t scount = 0, snum, hcount = 0, hnum; + AD9081_NULL_POINTER_RETURN(device); + AD9081_NULL_POINTER_RETURN(setup_risk_violation); + AD9081_NULL_POINTER_RETURN(hold_risk_violation); + AD9081_LOG_FUNC(); + + err = adi_ad9081_hal_bf_get(device, 0x0fb7, 0x800, setup_risk_violation, + sizeof(uint8_t)); /* SYSREF_SETUP */ + AD9081_ERROR_RETURN(err); + + err = adi_ad9081_hal_bf_get(device, 0x0fb8, 0x800, hold_risk_violation, + sizeof(uint8_t)); /* SYSREF_HOLD */ + AD9081_ERROR_RETURN(err); + + /* Number of 1s in setup time register */ + snum = *setup_risk_violation; + + for (i = 0; i < 8; i++) { + if (1 & snum) { + scount++; + snum = snum >> 1; + } + } + *setup_risk_violation = scount; + + /* Number of 1s in hold time register */ + hnum = *hold_risk_violation; + + for (i = 0; i < 8; i++) { + if (1 & hnum) { + hcount++; + hnum = hnum >> 1; + } + } + *hold_risk_violation = hcount; + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_jesd_sysref_fine_superfine_delay_set( + adi_ad9081_device_t *device, uint8_t enable, uint8_t fine_delay, + uint8_t superfine_delay) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + if (enable > 3) { + return API_CMS_ERROR_INVALID_PARAM; + } + + /*Enable Fine and Super fine delay on the SYSREF input + 00: SYSREF delay disabled + 01: Fine delay + 10: Super fine delay + 11: both Fine and Superfine Delay*/ + + err = adi_ad9081_hal_bf_set(device, 0x0fb1, 0x200, enable); + AD9081_ERROR_RETURN(err); + if (enable == 1 || enable == 3) { + err = adi_ad9081_hal_bf_set( + device, 0x0fb2, 0x800, + fine_delay); /* maximum effective setting is 0x2F */ + AD9081_ERROR_RETURN(err); + } + if (enable == 2 || enable == 3) { + err = adi_ad9081_hal_bf_set( + device, 0xfb3, 0x800, + superfine_delay); /* maximum is approx. 4ps (255 x 16 fs) */ + AD9081_ERROR_RETURN(err); + } + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_jesd_sysref_count_set(adi_ad9081_device_t *device, + uint8_t edges) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + err = adi_ad9081_hal_bf_set(device, REG_SYSREF_COUNT_ADDR, + BF_SYSREF_COUNT_INFO, edges); + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_jesd_sysref_average_set(adi_ad9081_device_t *device, + uint8_t pulses) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + if (pulses > 0x7) { + return API_CMS_ERROR_INVALID_PARAM; + } + + err = adi_ad9081_hal_bf_set(device, REG_SYSREF_AVERAGE_ADDR, + BF_SYSREF_AVERAGE_INFO, pulses); + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_jesd_sysref_monitor_phase_get(adi_ad9081_device_t *device, + uint16_t *sysref_phase) +{ + int32_t err; + uint8_t phase0_val; + uint8_t phase1_val; + + AD9081_NULL_POINTER_RETURN(device); + AD9081_NULL_POINTER_RETURN(sysref_phase); + AD9081_LOG_FUNC(); + + err = adi_ad9081_hal_bf_get(device, REG_SYSREF_PHASE0_ADDR, 0x800, + &phase0_val, sizeof(uint8_t)); + err = adi_ad9081_hal_bf_get(device, REG_SYSREF_PHASE1_ADDR, 0x400, + &phase1_val, sizeof(uint8_t)); + + *sysref_phase = (phase0_val << 8) + phase1_val; + + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t +adi_ad9081_jesd_sysref_monitor_lmfc_align_error_get(adi_ad9081_device_t *device, + uint8_t *lmfc_align_err) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_NULL_POINTER_RETURN(lmfc_align_err); + AD9081_LOG_FUNC(); + + err = adi_ad9081_hal_bf_get(device, REG_SYSREF_ERR_WINDOW_ADDR, + BF_SYSREF_WITHIN_LMFC_ERRWINDOW_INFO, + lmfc_align_err, sizeof(uint8_t)); + + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_jesd_sysref_monitor_lmfc_align_threshold_set( + adi_ad9081_device_t *device, uint8_t sysref_error_window) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + if (sysref_error_window > 0x7F) { + return API_CMS_ERROR_INVALID_PARAM; + } + + err = adi_ad9081_hal_bf_set(device, REG_SYSREF_ERR_WINDOW_ADDR, + BF_SYSREF_ERR_WINDOW_INFO, + sysref_error_window); + + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_jesd_sysref_irq_enable_set(adi_ad9081_device_t *device, + uint8_t enable) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + err = adi_ad9081_hal_bf_set(device, REG_IRQ_ENABLE_0_ADDR, + BF_EN_SYSREF_IRQ_INFO, enable); + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_jesd_sysref_irq_jitter_mux_set(adi_ad9081_device_t *device, + uint8_t pin) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + if (pin != 0 || pin != 1) { + return API_CMS_ERROR_INVALID_PARAM; + } + + err = adi_ad9081_hal_bf_set(device, REG_IRQ_OUTPUT_MUX_0_ADDR, + BF_MUX_SYSREF_JITTER_INFO, pin); + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t +adi_ad9081_jesd_sysref_oneshot_sync_done_get(adi_ad9081_device_t *device, + uint8_t *sync_done) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_NULL_POINTER_RETURN(sync_done); + AD9081_LOG_FUNC(); + + err = adi_ad9081_hal_bf_get(device, REG_SYSREF_MODE_ADDR, + BF_ONESHOT_SYNC_DONE_INFO, sync_done, + 1); /* not paged */ + AD9081_ERROR_RETURN(err); + + if (*sync_done != 1) { + AD9081_LOG_ERR("oneshot sync not finished."); + } + + return API_CMS_ERROR_OK; +} \ No newline at end of file diff --git a/drivers/iio/adc/ad9081/adi_cms_api_common.h b/drivers/iio/adc/ad9081/adi_cms_api_common.h index 2b367a4495eb13..88a7bfb9cc0500 100644 --- a/drivers/iio/adc/ad9081/adi_cms_api_common.h +++ b/drivers/iio/adc/ad9081/adi_cms_api_common.h @@ -54,6 +54,7 @@ typedef enum { API_CMS_ERROR_DLL_NOT_LOCKED = -22, /*!< DLL is not locked */ API_CMS_ERROR_MODE_NOT_IN_TABLE = -23, /*!< JESD Mode not in table */ API_CMS_ERROR_JESD_PLL_NOT_LOCKED = -24, /*!< PD STBY function error */ + API_CMS_ERROR_JESD_SYNC_NOT_DONE = -25, /*!< JESD_SYNC_NOT_DONE */ API_CMS_ERROR_FTW_LOAD_ACK = -30, /*!< FTW acknowledge not received */ API_CMS_ERROR_NCO_NOT_ENABLED = -31, /*!< The NCO is not enabled */ API_CMS_ERROR_INIT_SEQ_FAIL = @@ -400,22 +401,6 @@ typedef int32_t (*adi_pd_stby_pin_ctrl_t)(void *user_data, uint8_t enable); */ typedef int32_t (*adi_reset_pin_ctrl_t)(void *user_data, uint8_t enable); -/** - * @brief sysref control function - * - * @param user_data A void pointer to a client defined structure containing - * any parameters/settings that may be required by the - * function to control the hardware sysref control. - * @param enable A uint8_t value indicating the desired enable/disable - * condition. - * A value of 1 indicates SYSREF n-shot/continuous enable - * A value of 0 disables SYSREF pulses - * - * @return 0 for success - * @return Any non-zero value indicates an error - */ -typedef int32_t (*adi_sysref_ctrl_t)(void *user_data, uint8_t enable); - /** * @brief Control function for GPIO write. * From 6dcbfe4680b81ea350dd10031223715525be0664 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 5 Nov 2021 14:47:48 +0100 Subject: [PATCH 004/407] iio: adc: ad9081: Support for direct ADC->DAC loopback mode This patch adds support for direct ADC->DAC loopback mode. Note ADC sample rate must be same as DAC sample rate to get this loopback mode working. The default mapping: ADC0->DAC0, ADC1->DAC1, ADC0->DAC2, ADC1->DAC3 can either be modified via the adi,direct-loopback-mode-dac-adc-mapping device tree attribute or during run-time using the adi,direct-loopback-mode-dac-adc-mapping debugfs attribute. After writing the debugfs attribute, the new value needs to be latched by writing the loopback_mode iio attribute again. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 47 +++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 6512837f6073cb..825104f68fadba 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -228,6 +228,7 @@ struct ad9081_phy { struct ad9081_debugfs_entry debugfs_entry[10]; u32 ad9081_debugfs_entry_index; + u8 direct_lb_map; }; static int adi_ad9081_adc_nco_sync(adi_ad9081_device_t *device, @@ -2132,13 +2133,38 @@ static ssize_t ad9081_phy_store(struct device *dev, } ret = kstrtoul(buf, 0, &res); - if (ret || res > 2) { - ret = -EINVAL; + + /* setup mxfe loopback mode */ + switch (res) { + case 0: + adi_ad9081_jesd_loopback_mode_set(&phy->ad9081, 0); + adi_ad9081_device_direct_loopback_set(&phy->ad9081, + 0, phy->direct_lb_map); + break; + case 1: + adi_ad9081_device_direct_loopback_set(&phy->ad9081, + 0, phy->direct_lb_map); + adi_ad9081_jesd_loopback_mode_set(&phy->ad9081, 1); + break; + case 2: + case 3: + if (phy->adc_frequency_hz != phy->dac_frequency_hz) { + dev_err(&phy->spi->dev, + "ADC and DAC frequency doesn't match!\n"); + ret = -EOPNOTSUPP; + break; + } + + adi_ad9081_jesd_loopback_mode_set(&phy->ad9081, 0); + adi_ad9081_device_direct_loopback_set(&phy->ad9081, + (res == 2) ? 1 : 3, phy->direct_lb_map); break; + default: + ret = -EINVAL; } - /* setup txfe loopback mode */ - adi_ad9081_jesd_loopback_mode_set(&phy->ad9081, res); - phy->device_cache.loopback_mode = res; + + if (!ret) + phy->device_cache.loopback_mode = res; break; case AD9081_ADC_CLK_PWDN: ret = strtobool(buf, &bres); @@ -2395,6 +2421,8 @@ static IIO_DEVICE_ATTR(loopback_mode, S_IRUGO | S_IWUSR, ad9081_phy_store, AD9081_LOOPBACK_MODE); +static IIO_CONST_ATTR(loopback_mode_available, "0 1 2 3"); + static IIO_DEVICE_ATTR(adc_clk_powerdown, S_IRUGO | S_IWUSR, ad9081_phy_show, ad9081_phy_store, @@ -2450,6 +2478,7 @@ static IIO_DEVICE_ATTR(jesd204_fsm_ctrl, 0644, static struct attribute *ad9081_phy_attributes[] = { &iio_dev_attr_loopback_mode.dev_attr.attr, + &iio_const_attr_loopback_mode_available.dev_attr.attr, &iio_dev_attr_adc_clk_powerdown.dev_attr.attr, &iio_dev_attr_multichip_sync.dev_attr.attr, &iio_dev_attr_out_voltage_main_ffh_frequency.dev_attr.attr, @@ -3273,6 +3302,10 @@ static int ad9081_post_iio_register(struct iio_dev *indio_dev) debugfs_create_file_unsafe("dac-full-scale-current-ua", 0200, iio_get_debugfs_dentry(indio_dev), indio_dev, &ad9081_fsc_fops); + + debugfs_create_u8("adi,direct-loopback-mode-dac-adc-mapping", + 0644, iio_get_debugfs_dentry(indio_dev), + &phy->direct_lb_map); } sysfs_bin_attr_init(&phy->bin); @@ -3705,6 +3738,10 @@ static int ad9081_parse_dt(struct ad9081_phy *phy, struct device *dev) of_property_read_bool(np, "adi,continuous-sysref-mode-disable"); + phy->direct_lb_map = 0x44; + of_property_read_u8(np, "adi,direct-loopback-mode-dac-adc-mapping", + &phy->direct_lb_map); + ret = ad9081_parse_dt_tx(phy, np); if (ret < 0) { dev_err(&phy->spi->dev, "failed to parse devicetree"); From c17a05c4356f84b089066ce362f18d4eb2a7fd0f Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 10 Nov 2021 10:52:51 +0100 Subject: [PATCH 005/407] iio: adc: ad9081: Fix pointer parameter for ad9081_sysref_ctrl() This fixes an invalid pointer deference. fixes: 7e2c494d1d00 ("iio: adc: ad9081: Update API to Version 1.2.0") Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 825104f68fadba..f6c33dfaf7b5f5 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -432,11 +432,8 @@ static int ad9081_reset_pin_ctrl(void *user_data, u8 enable) return gpiod_direction_output(conv->reset_gpio, enable); } -static int ad9081_sysref_ctrl(void *user_data, u8 enable) +static int ad9081_sysref_ctrl(struct ad9081_phy *phy, u8 enable) { - struct axiadc_converter *conv = user_data; - struct ad9081_phy *phy = conv->phy; - if (phy->jdev && enable) return jesd204_sysref_async_force(phy->jdev); @@ -4146,7 +4143,6 @@ static int ad9081_jesd204_setup_stage1(struct jesd204_dev *jdev, phy->jtx_link_rx[0].jesd_param.jesd_subclass) subclass = JESD_SUBCLASS_1; - ret = adi_ad9081_jesd_oneshot_sync(&phy->ad9081, subclass); if (ret != 0) return ret; @@ -4154,7 +4150,7 @@ static int ad9081_jesd204_setup_stage1(struct jesd204_dev *jdev, if (phy->sysref_continuous_dis) { u8 sync_done; - ad9081_sysref_ctrl(&phy->ad9081, 1); + ad9081_sysref_ctrl(phy, 1); ret = adi_ad9081_jesd_sysref_oneshot_sync_done_get(&phy->ad9081, &sync_done); From e24580136963037a5f2d223146732004c7d54a1e Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 9 Nov 2021 17:13:04 +0200 Subject: [PATCH 006/407] dt-bindings:admv1014: misc fixes Add 0 to the det-prog enum since it is a valid value. Fix typo in the bb-amp-gain-ctrl property. Fixes: 77dd8d6b42da2c3be0f1ad6ec9acd0b9c66816c8 (dt:bindings:iio:frequency:add admv1014 doc) Signed-off-by: Antoniu Miclaus --- .../devicetree/bindings/iio/frequency/adi,admv1014.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml index 636e80c4748d14..be45b1a9b3ec0f 100644 --- a/Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml +++ b/Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml @@ -106,9 +106,9 @@ properties: description: Digital Rx Detector Program. $ref: /schemas/types.yaml#/definitions/uint32 - enum: [1, 2, 4, 8, 16, 32, 64] + enum: [0, 1, 2, 4, 8, 16, 32, 64] - adi,adi,bb-amp-gain-ctrl: + adi,bb-amp-gain-ctrl: description: Baseband Amp Gain control. $ref: /schemas/types.yaml#/definitions/uint32 From ff6c6d527d39bb7e7ea8efa8cd75413f7daa724a Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 9 Nov 2021 16:07:16 +0200 Subject: [PATCH 007/407] iio:admv1013: fix comparison for quad filters Fix comparison when applying quad filters based on the input clock. Fixes: 0538776f05eeb32902f122013868fdd662d3763c(iio:frequency:admv1013: add support for ADMV1013) Signed-off-by: Antoniu Miclaus --- drivers/iio/frequency/admv1013.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c index 59dd27166cb3f9..c11781a2a6a8e6 100644 --- a/drivers/iio/frequency/admv1013.c +++ b/drivers/iio/frequency/admv1013.c @@ -289,11 +289,11 @@ static int admv1013_update_quad_filters(struct admv1013_dev *dev) { unsigned int filt_raw; - if (dev->clkin_freq <= 5400000000 && dev->clkin_freq <= 7000000000) + if (dev->clkin_freq >= 5400000000 && dev->clkin_freq <= 7000000000) filt_raw = 15; - else if (dev->clkin_freq <= 5400000000 && dev->clkin_freq <= 8000000000) + else if (dev->clkin_freq >= 5400000000 && dev->clkin_freq <= 8000000000) filt_raw = 10; - else if (dev->clkin_freq <= 6600000000 && dev->clkin_freq <= 9200000000) + else if (dev->clkin_freq >= 6600000000 && dev->clkin_freq <= 9200000000) filt_raw = 5; else filt_raw = 0; From 6ab802223a55ad692d537df442f98eb856332f62 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 11 Nov 2021 11:38:41 +0200 Subject: [PATCH 008/407] iio: accel: Add driver support for ADXL355 ADXL355 is a 3-axis MEMS Accelerometer. It offers low noise density, low 0g offset drift, low power with selectable measurement ranges. It also features programmable high-pass and low-pass filters. Datasheet: https://www.analog.com/en/products/adxl355.html Signed-off-by: Puranjay Mohan Signed-off-by: Antoniu Miclaus --- MAINTAINERS | 10 + drivers/iio/accel/Kconfig | 33 ++ drivers/iio/accel/Makefile | 3 + drivers/iio/accel/adxl355.h | 21 + drivers/iio/accel/adxl355_core.c | 765 +++++++++++++++++++++++++++++++ drivers/iio/accel/adxl355_i2c.c | 62 +++ drivers/iio/accel/adxl355_spi.c | 65 +++ 7 files changed, 959 insertions(+) create mode 100644 drivers/iio/accel/adxl355.h create mode 100644 drivers/iio/accel/adxl355_core.c create mode 100644 drivers/iio/accel/adxl355_i2c.c create mode 100644 drivers/iio/accel/adxl355_spi.c diff --git a/MAINTAINERS b/MAINTAINERS index a59eaadc1a8cdd..ce2259b84b5334 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -578,6 +578,16 @@ W: http://ez.analog.com/community/linux-device-drivers F: Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml F: drivers/input/misc/adxl34x.c +ADXL355 THREE-AXIS DIGITAL ACCELEROMETER DRIVER +M: Puranjay Mohan +L: linux-iio@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml +F: drivers/iio/accel/adxl355.h +F: drivers/iio/accel/adxl355_core.c +F: drivers/iio/accel/adxl355_i2c.c +F: drivers/iio/accel/adxl355_spi.c + ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER M: Michael Hennerich S: Supported diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 2e0c62c3915508..46641ae499f7ed 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -61,6 +61,39 @@ config ADXL345_SPI will be called adxl345_spi and you will also get adxl345_core for the core module. +config ADXL355 + tristate + +config ADXL355_I2C + tristate "Analog Devices ADXL355 3-Axis Digital Accelerometer I2C Driver" + depends on I2C + select ADXL355 + select REGMAP_I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say Y here if you want to build i2c support for the Analog Devices + ADXL355 3-axis digital accelerometer. + + To compile this driver as a module, choose M here: the module + will be called adxl355_i2c and you will also get adxl355_core + for the core module. + +config ADXL355_SPI + tristate "Analog Devices ADXL355 3-Axis Digital Accelerometer SPI Driver" + depends on SPI + select ADXL355 + select REGMAP_SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say Y here if you want to build spi support for the Analog Devices + ADXL355 3-axis digital accelerometer. + + To compile this driver as a module, choose M here: the module + will be called adxl355_spi and you will also get adxl355_core + for the core module. + config ADXL372 tristate select IIO_BUFFER diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 4f6c1ebe13b0fc..9cafe4f7a647d8 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -9,6 +9,9 @@ obj-$(CONFIG_ADIS16209) += adis16209.o obj-$(CONFIG_ADXL345) += adxl345_core.o obj-$(CONFIG_ADXL345_I2C) += adxl345_i2c.o obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o +obj-$(CONFIG_ADXL355) += adxl355_core.o +obj-$(CONFIG_ADXL355_I2C) += adxl355_i2c.o +obj-$(CONFIG_ADXL355_SPI) += adxl355_spi.o obj-$(CONFIG_ADXL372) += adxl372.o obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o diff --git a/drivers/iio/accel/adxl355.h b/drivers/iio/accel/adxl355.h new file mode 100644 index 00000000000000..6dd49b13e4fd07 --- /dev/null +++ b/drivers/iio/accel/adxl355.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * ADXL355 3-Axis Digital Accelerometer + * + * Copyright (c) 2021 Puranjay Mohan + */ + +#ifndef _ADXL355_H_ +#define _ADXL355_H_ + +#include + +struct device; + +extern const struct regmap_access_table adxl355_readable_regs_tbl; +extern const struct regmap_access_table adxl355_writeable_regs_tbl; + +int adxl355_core_probe(struct device *dev, struct regmap *regmap, + const char *name); + +#endif /* _ADXL355_H_ */ diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c new file mode 100644 index 00000000000000..f97675b364996a --- /dev/null +++ b/drivers/iio/accel/adxl355_core.c @@ -0,0 +1,765 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADXL355 3-Axis Digital Accelerometer IIO core driver + * + * Copyright (c) 2021 Puranjay Mohan + * + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/adxl354_adxl355.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adxl355.h" + +/* ADXL355 Register Definitions */ +#define ADXL355_DEVID_AD_REG 0x00 +#define ADXL355_DEVID_MST_REG 0x01 +#define ADXL355_PARTID_REG 0x02 +#define ADXL355_STATUS_REG 0x04 +#define ADXL355_FIFO_ENTRIES_REG 0x05 +#define ADXL355_TEMP2_REG 0x06 +#define ADXL355_XDATA3_REG 0x08 +#define ADXL355_YDATA3_REG 0x0B +#define ADXL355_ZDATA3_REG 0x0E +#define ADXL355_FIFO_DATA_REG 0x11 +#define ADXL355_OFFSET_X_H_REG 0x1E +#define ADXL355_OFFSET_Y_H_REG 0x20 +#define ADXL355_OFFSET_Z_H_REG 0x22 +#define ADXL355_ACT_EN_REG 0x24 +#define ADXL355_ACT_THRESH_H_REG 0x25 +#define ADXL355_ACT_THRESH_L_REG 0x26 +#define ADXL355_ACT_COUNT_REG 0x27 +#define ADXL355_FILTER_REG 0x28 +#define ADXL355_FILTER_ODR_MSK GENMASK(3, 0) +#define ADXL355_FILTER_HPF_MSK GENMASK(6, 4) +#define ADXL355_FIFO_SAMPLES_REG 0x29 +#define ADXL355_INT_MAP_REG 0x2A +#define ADXL355_SYNC_REG 0x2B +#define ADXL355_RANGE_REG 0x2C +#define ADXL355_POWER_CTL_REG 0x2D +#define ADXL355_POWER_CTL_MODE_MSK GENMASK(1, 0) +#define ADXL355_POWER_CTL_DRDY_MSK BIT(2) +#define ADXL355_SELF_TEST_REG 0x2E +#define ADXL355_RESET_REG 0x2F + +#define ADXL355_DEVID_AD_VAL 0xAD +#define ADXL355_DEVID_MST_VAL 0x1D +#define ADXL355_PARTID_VAL 0xED +#define ADXL355_RESET_CODE 0x52 + +#define MEGA 1000000UL +#define TERA 1000000000000ULL + +static const struct regmap_range adxl355_read_reg_range[] = { + regmap_reg_range(ADXL355_DEVID_AD_REG, ADXL355_FIFO_DATA_REG), + regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_SELF_TEST_REG), +}; + +const struct regmap_access_table adxl355_readable_regs_tbl = { + .yes_ranges = adxl355_read_reg_range, + .n_yes_ranges = ARRAY_SIZE(adxl355_read_reg_range), +}; +EXPORT_SYMBOL_GPL(adxl355_readable_regs_tbl); + +static const struct regmap_range adxl355_write_reg_range[] = { + regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_RESET_REG), +}; + +const struct regmap_access_table adxl355_writeable_regs_tbl = { + .yes_ranges = adxl355_write_reg_range, + .n_yes_ranges = ARRAY_SIZE(adxl355_write_reg_range), +}; +EXPORT_SYMBOL_GPL(adxl355_writeable_regs_tbl); + +enum adxl355_op_mode { + ADXL355_MEASUREMENT, + ADXL355_STANDBY, + ADXL355_TEMP_OFF, +}; + +enum adxl355_odr { + ADXL355_ODR_4000HZ, + ADXL355_ODR_2000HZ, + ADXL355_ODR_1000HZ, + ADXL355_ODR_500HZ, + ADXL355_ODR_250HZ, + ADXL355_ODR_125HZ, + ADXL355_ODR_62_5HZ, + ADXL355_ODR_31_25HZ, + ADXL355_ODR_15_625HZ, + ADXL355_ODR_7_813HZ, + ADXL355_ODR_3_906HZ, +}; + +enum adxl355_hpf_3db { + ADXL355_HPF_OFF, + ADXL355_HPF_24_7, + ADXL355_HPF_6_2084, + ADXL355_HPF_1_5545, + ADXL355_HPF_0_3862, + ADXL355_HPF_0_0954, + ADXL355_HPF_0_0238, +}; + +static const int adxl355_odr_table[][2] = { + [0] = {4000, 0}, + [1] = {2000, 0}, + [2] = {1000, 0}, + [3] = {500, 0}, + [4] = {250, 0}, + [5] = {125, 0}, + [6] = {62, 500000}, + [7] = {31, 250000}, + [8] = {15, 625000}, + [9] = {7, 813000}, + [10] = {3, 906000}, +}; + +static const int adxl355_hpf_3db_multipliers[] = { + 0, + 247000, + 62084, + 15545, + 3862, + 954, + 238, +}; + +enum adxl355_chans { + chan_x, chan_y, chan_z, +}; + +struct adxl355_chan_info { + u8 data_reg; + u8 offset_reg; +}; + +static const struct adxl355_chan_info adxl355_chans[] = { + [chan_x] = { + .data_reg = ADXL355_XDATA3_REG, + .offset_reg = ADXL355_OFFSET_X_H_REG + }, + [chan_y] = { + .data_reg = ADXL355_YDATA3_REG, + .offset_reg = ADXL355_OFFSET_Y_H_REG + }, + [chan_z] = { + .data_reg = ADXL355_ZDATA3_REG, + .offset_reg = ADXL355_OFFSET_Z_H_REG + }, +}; + +struct adxl355_data { + struct regmap *regmap; + struct device *dev; + struct mutex lock; /* lock to protect op_mode */ + enum adxl355_op_mode op_mode; + enum adxl355_odr odr; + enum adxl355_hpf_3db hpf_3db; + int calibbias[3]; + int adxl355_hpf_3db_table[7][2]; + struct iio_trigger *dready_trig; + union { + u8 transf_buf[3]; + struct { + u8 buf[14]; + s64 ts; + } buffer; + } ____cacheline_aligned; +}; + +static int adxl355_set_op_mode(struct adxl355_data *data, + enum adxl355_op_mode op_mode) +{ + int ret; + + if (data->op_mode == op_mode) + return 0; + + ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG, + ADXL355_POWER_CTL_MODE_MSK, op_mode); + if (ret) + return ret; + + data->op_mode = op_mode; + + return ret; +} + +static int adxl355_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct adxl355_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->lock); + ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG, + ADXL355_POWER_CTL_DRDY_MSK, + FIELD_PREP(ADXL355_POWER_CTL_DRDY_MSK, + state ? 0 : 1)); + mutex_unlock(&data->lock); + + return ret; +} + +static void adxl355_fill_3db_frequency_table(struct adxl355_data *data) +{ + u32 multiplier; + u64 div, rem; + u64 odr; + int i; + + odr = mul_u64_u32_shr(adxl355_odr_table[data->odr][0], MEGA, 0) + + adxl355_odr_table[data->odr][1]; + + for (i = 0; i < ARRAY_SIZE(adxl355_hpf_3db_multipliers); i++) { + multiplier = adxl355_hpf_3db_multipliers[i]; + div = div64_u64_rem(mul_u64_u32_shr(odr, multiplier, 0), + TERA * 100, &rem); + + data->adxl355_hpf_3db_table[i][0] = div; + data->adxl355_hpf_3db_table[i][1] = div_u64(rem, MEGA * 100); + } +} + +static int adxl355_setup(struct adxl355_data *data) +{ + unsigned int regval; + int ret; + + ret = regmap_read(data->regmap, ADXL355_DEVID_AD_REG, ®val); + if (ret) + return ret; + + if (regval != ADXL355_DEVID_AD_VAL) { + dev_err(data->dev, "Invalid ADI ID 0x%02x\n", regval); + return -ENODEV; + } + + ret = regmap_read(data->regmap, ADXL355_DEVID_MST_REG, ®val); + if (ret) + return ret; + + if (regval != ADXL355_DEVID_MST_VAL) { + dev_err(data->dev, "Invalid MEMS ID 0x%02x\n", regval); + return -ENODEV; + } + + ret = regmap_read(data->regmap, ADXL355_PARTID_REG, ®val); + if (ret) + return ret; + + if (regval != ADXL355_PARTID_VAL) { + dev_err(data->dev, "Invalid DEV ID 0x%02x\n", regval); + return -ENODEV; + } + + /* + * Perform a software reset to make sure the device is in a consistent + * state after start-up. + */ + ret = regmap_write(data->regmap, ADXL355_RESET_REG, ADXL355_RESET_CODE); + if (ret) + return ret; + + ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG, + ADXL355_POWER_CTL_DRDY_MSK, + FIELD_PREP(ADXL355_POWER_CTL_DRDY_MSK, 1)); + if (ret) + return ret; + + adxl355_fill_3db_frequency_table(data); + + return adxl355_set_op_mode(data, ADXL355_MEASUREMENT); +} + +static int adxl355_get_temp_data(struct adxl355_data *data, u8 addr) +{ + return regmap_bulk_read(data->regmap, addr, data->transf_buf, 2); +} + +static int adxl355_read_axis(struct adxl355_data *data, u8 addr) +{ + int ret; + + ret = regmap_bulk_read(data->regmap, addr, data->transf_buf, + ARRAY_SIZE(data->transf_buf)); + if (ret) + return ret; + + return get_unaligned_be24(data->transf_buf); +} + +static int adxl355_find_match(const int (*freq_tbl)[2], const int n, + const int val, const int val2) +{ + int i; + + for (i = 0; i < n; i++) { + if (freq_tbl[i][0] == val && freq_tbl[i][1] == val2) + return i; + } + + return -EINVAL; +} + +static int adxl355_set_odr(struct adxl355_data *data, + enum adxl355_odr odr) +{ + int ret; + + mutex_lock(&data->lock); + + if (data->odr == odr) { + mutex_unlock(&data->lock); + return 0; + } + + ret = adxl355_set_op_mode(data, ADXL355_STANDBY); + if (ret) + goto err_unlock; + + ret = regmap_update_bits(data->regmap, ADXL355_FILTER_REG, + ADXL355_FILTER_ODR_MSK, + FIELD_PREP(ADXL355_FILTER_ODR_MSK, odr)); + if (ret) + goto err_set_opmode; + + data->odr = odr; + adxl355_fill_3db_frequency_table(data); + + ret = adxl355_set_op_mode(data, ADXL355_MEASUREMENT); + if (ret) + goto err_set_opmode; + + mutex_unlock(&data->lock); + return 0; + +err_set_opmode: + adxl355_set_op_mode(data, ADXL355_MEASUREMENT); +err_unlock: + mutex_unlock(&data->lock); + return ret; +} + +static int adxl355_set_hpf_3db(struct adxl355_data *data, + enum adxl355_hpf_3db hpf) +{ + int ret; + + mutex_lock(&data->lock); + + if (data->hpf_3db == hpf) { + mutex_unlock(&data->lock); + return 0; + } + + ret = adxl355_set_op_mode(data, ADXL355_STANDBY); + if (ret) + goto err_unlock; + + ret = regmap_update_bits(data->regmap, ADXL355_FILTER_REG, + ADXL355_FILTER_HPF_MSK, + FIELD_PREP(ADXL355_FILTER_HPF_MSK, hpf)); + if (ret) + goto err_set_opmode; + + data->hpf_3db = hpf; + + ret = adxl355_set_op_mode(data, ADXL355_MEASUREMENT); + if (ret) + goto err_set_opmode; + + mutex_unlock(&data->lock); + return 0; + +err_set_opmode: + adxl355_set_op_mode(data, ADXL355_MEASUREMENT); +err_unlock: + mutex_unlock(&data->lock); + return ret; +} + +static int adxl355_set_calibbias(struct adxl355_data *data, + enum adxl355_chans chan, int calibbias) +{ + int ret; + + mutex_lock(&data->lock); + + ret = adxl355_set_op_mode(data, ADXL355_STANDBY); + if (ret) + goto err_unlock; + + put_unaligned_be16(calibbias, data->transf_buf); + ret = regmap_bulk_write(data->regmap, + adxl355_chans[chan].offset_reg, + data->transf_buf, 2); + if (ret) + goto err_set_opmode; + + data->calibbias[chan] = calibbias; + + ret = adxl355_set_op_mode(data, ADXL355_MEASUREMENT); + if (ret) + goto err_set_opmode; + + mutex_unlock(&data->lock); + return 0; + +err_set_opmode: + adxl355_set_op_mode(data, ADXL355_MEASUREMENT); +err_unlock: + mutex_unlock(&data->lock); + return ret; +} + +static int adxl355_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct adxl355_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_TEMP: + ret = adxl355_get_temp_data(data, chan->address); + if (ret < 0) + return ret; + *val = get_unaligned_be16(data->transf_buf); + + return IIO_VAL_INT; + case IIO_ACCEL: + ret = adxl355_read_axis(data, adxl355_chans + [chan->address].data_reg); + if (ret < 0) + return ret; + *val = sign_extend32(ret >> chan->scan_type.shift, + chan->scan_type.realbits - 1); + return IIO_VAL_INT; + default: + return -EINVAL; + } + + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + /* + * The datasheet defines an intercept of 1885 LSB at 25 degC + * and a slope of -9.05 LSB/C. The following formula can be used + * to find the temperature: + * Temp = ((RAW - 1885)/(-9.05)) + 25 but this doesn't follow + * the format of the IIO which is Temp = (RAW + OFFSET) * SCALE. + * Hence using some rearranging we get the scale as -110.497238 + * and offset as -2111.25. + */ + case IIO_TEMP: + *val = -110; + *val2 = 497238; + return IIO_VAL_INT_PLUS_MICRO; + /* + * At +/- 2g with 20-bit resolution, scale is given in datasheet + * as 3.9ug/LSB = 0.0000039 * 9.80665 = 0.00003824593 m/s^2. + */ + case IIO_ACCEL: + *val = 0; + *val2 = 38245; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + *val = -2111; + *val2 = 250000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_CALIBBIAS: + *val = sign_extend32(data->calibbias[chan->address], 15); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = adxl355_odr_table[data->odr][0]; + *val2 = adxl355_odr_table[data->odr][1]; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: + *val = data->adxl355_hpf_3db_table[data->hpf_3db][0]; + *val2 = data->adxl355_hpf_3db_table[data->hpf_3db][1]; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int adxl355_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct adxl355_data *data = iio_priv(indio_dev); + int odr_idx, hpf_idx, calibbias; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + odr_idx = adxl355_find_match(adxl355_odr_table, + ARRAY_SIZE(adxl355_odr_table), + val, val2); + if (odr_idx < 0) + return odr_idx; + + return adxl355_set_odr(data, odr_idx); + case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: + hpf_idx = adxl355_find_match(data->adxl355_hpf_3db_table, + ARRAY_SIZE(data->adxl355_hpf_3db_table), + val, val2); + if (hpf_idx < 0) + return hpf_idx; + + return adxl355_set_hpf_3db(data, hpf_idx); + case IIO_CHAN_INFO_CALIBBIAS: + calibbias = clamp_t(int, val, S16_MIN, S16_MAX); + + return adxl355_set_calibbias(data, chan->address, calibbias); + default: + return -EINVAL; + } +} + +static int adxl355_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct adxl355_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = (const int *)adxl355_odr_table; + *type = IIO_VAL_INT_PLUS_MICRO; + /* Values are stored in a 2D matrix */ + *length = ARRAY_SIZE(adxl355_odr_table) * 2; + + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: + *vals = (const int *)data->adxl355_hpf_3db_table; + *type = IIO_VAL_INT_PLUS_MICRO; + /* Values are stored in a 2D matrix */ + *length = ARRAY_SIZE(data->adxl355_hpf_3db_table) * 2; + + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static const unsigned long adxl355_avail_scan_masks[] = { + GENMASK(3, 0), + 0 +}; + +static const struct iio_info adxl355_info = { + .read_raw = adxl355_read_raw, + .write_raw = adxl355_write_raw, + .read_avail = &adxl355_read_avail, +}; + +static const struct iio_trigger_ops adxl355_trigger_ops = { + .set_trigger_state = &adxl355_data_rdy_trigger_set_state, + .validate_device = &iio_trigger_validate_own_device, +}; + +static irqreturn_t adxl355_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct adxl355_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->lock); + + /* + * data->buffer is used both for triggered buffer support + * and read/write_raw(), hence, it has to be zeroed here before usage. + */ + data->buffer.buf[0] = 0; + + /* + * The acceleration data is 24 bits and big endian. It has to be saved + * in 32 bits, hence, it is saved in the 2nd byte of the 4 byte buffer. + * The buf array is 14 bytes as it includes 3x4=12 bytes for + * accelaration data of x, y, and z axis. It also includes 2 bytes for + * temperature data. + */ + ret = regmap_bulk_read(data->regmap, ADXL355_XDATA3_REG, + &data->buffer.buf[1], 3); + if (ret) + goto out_unlock_notify; + + ret = regmap_bulk_read(data->regmap, ADXL355_YDATA3_REG, + &data->buffer.buf[5], 3); + if (ret) + goto out_unlock_notify; + + ret = regmap_bulk_read(data->regmap, ADXL355_ZDATA3_REG, + &data->buffer.buf[9], 3); + if (ret) + goto out_unlock_notify; + + ret = regmap_bulk_read(data->regmap, ADXL355_TEMP2_REG, + &data->buffer.buf[12], 2); + if (ret) + goto out_unlock_notify; + + iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, + pf->timestamp); + +out_unlock_notify: + mutex_unlock(&data->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +#define ADXL355_ACCEL_CHANNEL(index, reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 20, \ + .storagebits = 32, \ + .shift = 4, \ + .endianness = IIO_BE, \ + } \ +} + +static const struct iio_chan_spec adxl355_channels[] = { + ADXL355_ACCEL_CHANNEL(0, chan_x, X), + ADXL355_ACCEL_CHANNEL(1, chan_y, Y), + ADXL355_ACCEL_CHANNEL(2, chan_z, Z), + { + .type = IIO_TEMP, + .address = ADXL355_TEMP2_REG, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 3, + .scan_type = { + .sign = 's', + .realbits = 12, + .storagebits = 16, + .endianness = IIO_BE, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static int adxl355_probe_trigger(struct iio_dev *indio_dev, int irq) +{ + struct adxl355_data *data = iio_priv(indio_dev); + int ret; + + data->dready_trig = devm_iio_trigger_alloc(data->dev, "%s-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->dready_trig) + return -ENOMEM; + + data->dready_trig->ops = &adxl355_trigger_ops; + iio_trigger_set_drvdata(data->dready_trig, indio_dev); + + ret = devm_request_irq(data->dev, irq, + &iio_trigger_generic_data_rdy_poll, + IRQF_ONESHOT, "adxl355_irq", data->dready_trig); + if (ret) + return dev_err_probe(data->dev, ret, "request irq %d failed\n", + irq); + + ret = devm_iio_trigger_register(data->dev, data->dready_trig); + if (ret) { + dev_err(data->dev, "iio trigger register failed\n"); + return ret; + } + + indio_dev->trig = iio_trigger_get(data->dready_trig); + + return 0; +} + +int adxl355_core_probe(struct device *dev, struct regmap *regmap, + const char *name) +{ + struct adxl355_data *data; + struct iio_dev *indio_dev; + int ret; + int irq; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->regmap = regmap; + data->dev = dev; + data->op_mode = ADXL355_STANDBY; + mutex_init(&data->lock); + + indio_dev->name = name; + indio_dev->info = &adxl355_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adxl355_channels; + indio_dev->num_channels = ARRAY_SIZE(adxl355_channels); + indio_dev->available_scan_masks = adxl355_avail_scan_masks; + + ret = adxl355_setup(data); + if (ret) { + dev_err(dev, "ADXL355 setup failed\n"); + return ret; + } + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, + &adxl355_trigger_handler, NULL); + if (ret) { + dev_err(dev, "iio triggered buffer setup failed\n"); + return ret; + } + + /* + * TODO: Would be good to move it to the generic version. + */ + irq = of_irq_get_byname(dev->of_node, "DRDY"); + if (irq > 0) { + ret = adxl355_probe_trigger(indio_dev, irq); + if (ret) + return ret; + } + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_GPL(adxl355_core_probe); + +MODULE_AUTHOR("Puranjay Mohan "); +MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c new file mode 100644 index 00000000000000..5a987bda906063 --- /dev/null +++ b/drivers/iio/accel/adxl355_i2c.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADXL355 3-Axis Digital Accelerometer I2C driver + * + * Copyright (c) 2021 Puranjay Mohan + */ + +#include +#include +#include +#include + +#include "adxl355.h" + +static const struct regmap_config adxl355_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x2F, + .rd_table = &adxl355_readable_regs_tbl, + .wr_table = &adxl355_writeable_regs_tbl, +}; + +static int adxl355_i2c_probe(struct i2c_client *client) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, &adxl355_i2c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Error initializing i2c regmap: %ld\n", + PTR_ERR(regmap)); + + return PTR_ERR(regmap); + } + + return adxl355_core_probe(&client->dev, regmap, client->name); +} + +static const struct i2c_device_id adxl355_i2c_id[] = { + { "adxl355", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adxl355_i2c_id); + +static const struct of_device_id adxl355_of_match[] = { + { .compatible = "adi,adxl355" }, + { } +}; +MODULE_DEVICE_TABLE(of, adxl355_of_match); + +static struct i2c_driver adxl355_i2c_driver = { + .driver = { + .name = "adxl355_i2c", + .of_match_table = adxl355_of_match, + }, + .probe_new = adxl355_i2c_probe, + .id_table = adxl355_i2c_id, +}; +module_i2c_driver(adxl355_i2c_driver); + +MODULE_AUTHOR("Puranjay Mohan "); +MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer I2C driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c new file mode 100644 index 00000000000000..fb225aeb56e313 --- /dev/null +++ b/drivers/iio/accel/adxl355_spi.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADXL355 3-Axis Digital Accelerometer SPI driver + * + * Copyright (c) 2021 Puranjay Mohan + */ + +#include +#include +#include +#include + +#include "adxl355.h" + +static const struct regmap_config adxl355_spi_regmap_config = { + .reg_bits = 7, + .pad_bits = 1, + .val_bits = 8, + .read_flag_mask = BIT(0), + .max_register = 0x2F, + .rd_table = &adxl355_readable_regs_tbl, + .wr_table = &adxl355_writeable_regs_tbl, +}; + +static int adxl355_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &adxl355_spi_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Error initializing spi regmap: %ld\n", + PTR_ERR(regmap)); + + return PTR_ERR(regmap); + } + + return adxl355_core_probe(&spi->dev, regmap, id->name); +} + +static const struct spi_device_id adxl355_spi_id[] = { + { "adxl355", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, adxl355_spi_id); + +static const struct of_device_id adxl355_of_match[] = { + { .compatible = "adi,adxl355" }, + { } +}; +MODULE_DEVICE_TABLE(of, adxl355_of_match); + +static struct spi_driver adxl355_spi_driver = { + .driver = { + .name = "adxl355_spi", + .of_match_table = adxl355_of_match, + }, + .probe = adxl355_spi_probe, + .id_table = adxl355_spi_id, +}; +module_spi_driver(adxl355_spi_driver); + +MODULE_AUTHOR("Puranjay Mohan "); +MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer SPI driver"); +MODULE_LICENSE("GPL v2"); From 53a946e79add6a770f4f01faa40aac4022ddbef2 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 11 Nov 2021 11:42:08 +0200 Subject: [PATCH 009/407] dt-bindings:iio:accel: Add doc for ADXL355 Add devicetree binding document for ADXL355, a 3-Axis MEMS Accelerometer. Signed-off-by: Puranjay Mohan Signed-off-by: Antoniu Miclaus --- .../bindings/iio/accel/adi,adxl355.yaml | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml new file mode 100644 index 00000000000000..ba54d6998f2ee7 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/accel/adi,adxl355.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADXL355 3-Axis, Low noise MEMS Accelerometer + +maintainers: + - Puranjay Mohan + +description: | + Analog Devices ADXL355 3-Axis, Low noise MEMS Accelerometer that supports + both I2C & SPI interfaces + https://www.analog.com/en/products/adxl355.html + +properties: + compatible: + enum: + - adi,adxl355 + + reg: + maxItems: 1 + + interrupts: + minItems: 1 + maxItems: 3 + description: | + Type for DRDY should be IRQ_TYPE_EDGE_RISING. + Three configurable interrupt lines exist. + + interrupt-names: + description: Specify which interrupt line is in use. + items: + enum: + - INT1 + - INT2 + - DRDY + minItems: 1 + maxItems: 3 + + vdd-supply: + description: Regulator that provides power to the sensor + + vddio-supply: + description: Regulator that provides power to the bus + + spi-max-frequency: true + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + /* Example for a I2C device node */ + accelerometer@1d { + compatible = "adi,adxl355"; + reg = <0x1d>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "DRDY"; + }; + }; + - | + #include + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + + accelerometer@0 { + compatible = "adi,adxl355"; + reg = <0>; + spi-max-frequency = <1000000>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "DRDY"; + }; + }; From 06279753c9941a694f3017c264e1bc21fabe7b3f Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 11 Nov 2021 11:47:45 +0200 Subject: [PATCH 010/407] iio: Kconfig.adi: Add ADXL355 Add ADXL355 to the IIO_ALL_ADI_DRIVERS kconfig option. Signed-off-by: Antoniu Miclaus --- drivers/iio/Kconfig.adi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/Kconfig.adi b/drivers/iio/Kconfig.adi index 24c3a8ecc6a8ba..014433c05f47b6 100644 --- a/drivers/iio/Kconfig.adi +++ b/drivers/iio/Kconfig.adi @@ -25,6 +25,8 @@ config IIO_ALL_ADI_DRIVERS select ADIS16209 select ADXL345_I2C if I2C select ADXL345_SPI if SPI + select ADXL355_I2C if I2C + select ADXL355_SPI if SPI select ADXL372_I2C if I2C select ADXL372_SPI if SPI select AD400X From 895d821503f6dcf7cc481381faa1a9f75fe66e5d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 11 Nov 2021 17:08:41 +0100 Subject: [PATCH 011/407] dts: Fix node name for SPI buses should be 'spi' This fixes some devitree warnings where: node name for SPI buses should be 'spi' Signed-off-by: Michael Hennerich --- arch/arm/boot/dts/zynq-pluto-sdr-revc.dts | 2 +- arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts | 4 ++-- arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmclidar1.dts | 4 ++-- arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi | 2 +- arch/microblaze/boot/dts/adi-fmcomms1.dtsi | 2 +- arch/microblaze/boot/dts/kc705.dtsi | 2 +- arch/microblaze/boot/dts/kcu105.dtsi | 2 +- arch/microblaze/boot/dts/vc707.dtsi | 2 +- arch/microblaze/boot/dts/vcu118.dtsi | 2 +- arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi | 4 ++-- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm/boot/dts/zynq-pluto-sdr-revc.dts b/arch/arm/boot/dts/zynq-pluto-sdr-revc.dts index 7aff4e197d0f9a..9c9a0c9dbf9c81 100644 --- a/arch/arm/boot/dts/zynq-pluto-sdr-revc.dts +++ b/arch/arm/boot/dts/zynq-pluto-sdr-revc.dts @@ -33,7 +33,7 @@ }; &amba { - axi_spi: axi_quad_spi@7C430000 { + axi_spi: spi@7C430000 { #address-cells = <1>; #size-cells = <0>; bits-per-word = <8>; diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts index 51769b317fae76..043aa76a70c150 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts @@ -33,7 +33,7 @@ }; &fpga_axi { - axi_spi_vco: axi_quad_spi@7c500000 { + axi_spi_vco: spi@7c500000 { reg = <0x7c500000 0x10000>; compatible = "xlnx,xps-spi-2.00.a"; bits-per-word = <8>; @@ -50,7 +50,7 @@ #size-cells = <0>; }; - axi_spi_afe_adc: axi_quad_spi@7c600000 { + axi_spi_afe_adc: spi@7c600000 { reg = <0x7c600000 0x10000>; compatible = "xlnx,xps-spi-2.00.a"; bits-per-word = <8>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmclidar1.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmclidar1.dts index abc38ea69eccfc..2c9fbaac4d1f09 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmclidar1.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmclidar1.dts @@ -43,7 +43,7 @@ #size-cells = <0x1>; ranges = <0 0 0 0xffffffff>; - axi_spi_vco: axi_quad_spi@9c500000 { + axi_spi_vco: spi@9c500000 { reg = <0x9c500000 0x10000>; compatible = "xlnx,xps-spi-2.00.a"; bits-per-word = <8>; @@ -60,7 +60,7 @@ #size-cells = <0>; }; - axi_spi_afe_adc: axi_quad_spi@9c600000 { + axi_spi_afe_adc: spi@9c600000 { reg = <0x9c600000 0x10000>; compatible = "xlnx,xps-spi-2.00.a"; bits-per-word = <8>; diff --git a/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi b/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi index 7d0d54df855ea4..9714c7b0396313 100644 --- a/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi +++ b/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi @@ -16,7 +16,7 @@ }; &fmc_spi { - spi_fmcjesdadc1: spi-fmcjesdadc1@0 { + spi_fmcjesdadc1: spi@0 { #address-cells = <1>; #size-cells = <0>; compatible = "adi,spi-ad9250"; diff --git a/arch/microblaze/boot/dts/adi-fmcomms1.dtsi b/arch/microblaze/boot/dts/adi-fmcomms1.dtsi index ee0000e1b2ed18..e4b9d3e11f859d 100644 --- a/arch/microblaze/boot/dts/adi-fmcomms1.dtsi +++ b/arch/microblaze/boot/dts/adi-fmcomms1.dtsi @@ -1,6 +1,6 @@ &fmc_i2c { - spi_xcomm0: spi_xcomm0@58 { + spi_xcomm0: spi@58 { #size-cells = <0>; #address-cells = <1>; compatible = "spi-xcomm"; diff --git a/arch/microblaze/boot/dts/kc705.dtsi b/arch/microblaze/boot/dts/kc705.dtsi index 448af33cfeed9b..a555c2a3448233 100644 --- a/arch/microblaze/boot/dts/kc705.dtsi +++ b/arch/microblaze/boot/dts/kc705.dtsi @@ -403,7 +403,7 @@ reg = <0x01440000 0xBC0000>; }; }; - axi_spi: axi_quad_spi@44a70000 { + axi_spi: spi@44a70000 { #address-cells = <1>; #size-cells = <0>; bits-per-word = <8>; diff --git a/arch/microblaze/boot/dts/kcu105.dtsi b/arch/microblaze/boot/dts/kcu105.dtsi index 531992118d84ca..526b764d921d91 100644 --- a/arch/microblaze/boot/dts/kcu105.dtsi +++ b/arch/microblaze/boot/dts/kcu105.dtsi @@ -312,7 +312,7 @@ xlnx,kind-of-intr = <0x410>; xlnx,num-intr-inputs = <0x10>; }; - axi_spi: axi_quad_spi@44a70000 { + axi_spi: spi@44a70000 { #address-cells = <1>; #size-cells = <0>; bits-per-word = <8>; diff --git a/arch/microblaze/boot/dts/vc707.dtsi b/arch/microblaze/boot/dts/vc707.dtsi index b22ef81bdfeebe..aca50a16ab6397 100644 --- a/arch/microblaze/boot/dts/vc707.dtsi +++ b/arch/microblaze/boot/dts/vc707.dtsi @@ -437,7 +437,7 @@ reg = <0x01440000 0xBC0000>; }; }; - axi_spi: axi_quad_spi@44a70000 { + axi_spi: spi@44a70000 { #address-cells = <1>; #size-cells = <0>; bits-per-word = <8>; diff --git a/arch/microblaze/boot/dts/vcu118.dtsi b/arch/microblaze/boot/dts/vcu118.dtsi index 86c798cd5caa6d..f3a48305617159 100644 --- a/arch/microblaze/boot/dts/vcu118.dtsi +++ b/arch/microblaze/boot/dts/vcu118.dtsi @@ -346,7 +346,7 @@ xlnx,kind-of-intr = <0x35f8>; xlnx,num-intr-inputs = <0x10>; }; - axi_spi: axi_quad_spi@44a70000 { + axi_spi: spi@44a70000 { #address-cells = <1>; #size-cells = <0>; bits-per-word = <8>; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi b/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi index e4c806e60d269a..85565d849de8f2 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi @@ -36,7 +36,7 @@ }; &amba_pl { - axi_spi2: axi_quad_spi@44a80000 { + axi_spi2: spi@44a80000 { #address-cells = <1>; #size-cells = <0>; bits-per-word = <8>; @@ -50,7 +50,7 @@ xlnx,spi-mode = <0>; }; - axi_spi3: axi_quad_spi@44B80000 { + axi_spi3: spi@44B80000 { #address-cells = <1>; #size-cells = <0>; bits-per-word = <8>; From 3bba72c5d0d69da027d0857b2dd445ae393d8916 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 11 Nov 2021 17:31:00 +0100 Subject: [PATCH 012/407] microblaze: dts: Fix axi_ethernet kernel boot warnings This fixes a bunch of warnings emitted during axi_ethernet probing. Signed-off-by: Michael Hennerich --- arch/microblaze/boot/dts/kcu105.dtsi | 2 +- arch/microblaze/boot/dts/vc707.dtsi | 2 +- arch/microblaze/boot/dts/vcu118.dtsi | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/microblaze/boot/dts/kcu105.dtsi b/arch/microblaze/boot/dts/kcu105.dtsi index 526b764d921d91..dfefa61b7688b1 100644 --- a/arch/microblaze/boot/dts/kcu105.dtsi +++ b/arch/microblaze/boot/dts/kcu105.dtsi @@ -193,6 +193,7 @@ axistream-connected = <&axi_ethernet_dma>; axistream-control-connected = <&axi_ethernet_dma>; clock-frequency = <100000000>; + clocks = <&clk_bus_0>; compatible = "xlnx,axi-ethernet-7.2", "xlnx,axi-ethernet-1.00.a"; device_type = "network"; interrupt-names = "interrupt"; @@ -213,7 +214,6 @@ xlnx,gtrefclksrc = <0x0>; xlnx,include-dre ; xlnx,instantiatebitslice0 = <0x0>; - xlnx,phy-type = <0x4>; xlnx,phyaddr = <0x1>; xlnx,phyrst-board-interface-dummy-port = <0x0>; xlnx,rable = <0x0>; diff --git a/arch/microblaze/boot/dts/vc707.dtsi b/arch/microblaze/boot/dts/vc707.dtsi index aca50a16ab6397..2e8ba300d967e0 100644 --- a/arch/microblaze/boot/dts/vc707.dtsi +++ b/arch/microblaze/boot/dts/vc707.dtsi @@ -191,6 +191,7 @@ axistream-connected = <&axi_ethernet_dma>; axistream-control-connected = <&axi_ethernet_dma>; clock-frequency = <100000000>; + clocks = <&clk_bus_0>; compatible = "xlnx,axi-ethernet-7.2", "xlnx,axi-ethernet-1.00.a"; device_type = "network"; interrupt-names = "interrupt"; @@ -211,7 +212,6 @@ xlnx,gtrefclksrc = <0x0>; xlnx,include-dre ; xlnx,instantiatebitslice0 = <0x0>; - xlnx,phy-type = <0x4>; xlnx,phyaddr = <0x1>; xlnx,phyrst-board-interface-dummy-port = <0x0>; xlnx,rable = <0x0>; diff --git a/arch/microblaze/boot/dts/vcu118.dtsi b/arch/microblaze/boot/dts/vcu118.dtsi index f3a48305617159..c0bb26b04b04e0 100644 --- a/arch/microblaze/boot/dts/vcu118.dtsi +++ b/arch/microblaze/boot/dts/vcu118.dtsi @@ -193,6 +193,7 @@ axistream-connected = <&axi_ethernet_dma>; axistream-control-connected = <&axi_ethernet_dma>; clock-frequency = <100000000>; + clocks = <&clk_bus_0>; compatible = "xlnx,axi-ethernet-7.2", "xlnx,axi-ethernet-1.00.a"; device_type = "network"; interrupt-names = "interrupt"; @@ -213,7 +214,6 @@ xlnx,gtrefclksrc = <0x0>; xlnx,include-dre ; xlnx,instantiatebitslice0 = <0x0>; - xlnx,phy-type = <0x4>; xlnx,phyaddr = <0x1>; xlnx,phyrst-board-interface-dummy-port = <0x0>; xlnx,rable = <0x0>; From 2c6e60e77b3b9b20d6fdb2ce0429fb47ae9da504 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 11 Nov 2021 14:36:05 +0200 Subject: [PATCH 013/407] ci: add --strict option for checkpatch The `--strict` option is mandatory when sending a patch upstream. This patch aims to minimize the number of upstream resubmissions due to styling issues. Signed-off-by: Antoniu Miclaus --- ci/travis/run-build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index 8ee98e8fc4eaaa..a267e443131593 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -234,6 +234,7 @@ build_checkpatch() { __update_git_ref "${ref_branch}" "${ref_branch}" scripts/checkpatch.pl --git "${ref_branch}.." \ + --strict \ --ignore FILE_PATH_CHANGES \ --ignore LONG_LINE \ --ignore LONG_LINE_STRING \ From f4907e198b4cc14729f3f51bb5348b5ec5e7af92 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Fri, 12 Nov 2021 10:42:48 +0200 Subject: [PATCH 014/407] ci: ignore paranthesis alignment This check is included in the recently added `--strict` option. Ignore the check for a more flexible checkpatch build. Signed-off-by: Antoniu Miclaus --- ci/travis/run-build.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index a267e443131593..5d315f616a4f5a 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -238,7 +238,8 @@ build_checkpatch() { --ignore FILE_PATH_CHANGES \ --ignore LONG_LINE \ --ignore LONG_LINE_STRING \ - --ignore LONG_LINE_COMMENT + --ignore LONG_LINE_COMMENT \ + --ignore PARENTHESIS_ALIGNMENT } build_dtb_build_test() { From a320769f5d31f2778ad917571838aafc5117c955 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Fri, 12 Nov 2021 14:53:11 +0200 Subject: [PATCH 015/407] iio:frequency:admv1013 vcm range fix Make sure that the margins for the two common-mode voltage ranges are included in the checks. Signed-off-by: Antoniu Miclaus --- drivers/iio/frequency/admv1013.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c index c11781a2a6a8e6..f7df5a4d83045a 100644 --- a/drivers/iio/frequency/admv1013.c +++ b/drivers/iio/frequency/admv1013.c @@ -309,9 +309,9 @@ static int admv1013_update_mixer_vgate(struct admv1013_dev *dev) vcm = regulator_get_voltage(dev->reg); - if (vcm >= 0 && vcm < 1800000) + if (vcm >= 0 && vcm <= 1800000) mixer_vgate = (2389 * vcm / 1000000 + 8100) / 100; - else if (vcm > 1800000 && vcm < 2600000) + else if (vcm > 1800000 && vcm <= 2600000) mixer_vgate = (2375 * vcm / 1000000 + 125) / 100; else return -EINVAL; From d1852993f0376e6e7e86f67e05b6982c997e01e6 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 15 Nov 2021 11:11:44 +0100 Subject: [PATCH 016/407] iio: adc: ad9361: TX QUAD Cal support for clktf=2*clkrf In situations where the TX path FIR interpolation is 1 and the RX path FIR is configured for decimate by 2, the NCO frequencies need to be adjusted appropriately. This patch adds support for this. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9361.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad9361.c b/drivers/iio/adc/ad9361.c index 64178ec31fe808..c9bd0805c3fc2a 100644 --- a/drivers/iio/adc/ad9361.c +++ b/drivers/iio/adc/ad9361.c @@ -2864,8 +2864,30 @@ static int ad9361_tx_quad_calib(struct ad9361_rf_phy *phy, __rx_phase = 0x1A; break; } + } else if (clktf == (2 * clkrf)) { + __rx_phase = -2; + switch (txnco_word) { + case 0: + rxnco_word = 1; + break; + case 1: + case 2: + case 3: + txnco_word = 1; + rxnco_word = 3; + break; + } + } else if (clktf == (4 * clkrf)) { + __rx_phase = -2; + txnco_word = 0; + rxnco_word = 3; + } else if (clkrf == (4 * clktf)) { + __rx_phase = -2; + txnco_word = 3; + rxnco_word = 0; } else - dev_err(dev, "Unhandled case in %s line %d clkrf %lu clktf %lu\n", + dev_err(dev, + "Unhandled case in %s line %d clkrf %lu clktf %lu\n", __func__, __LINE__, clkrf, clktf); if (rx_phase >= 0) From 776c7abeb35a7751bb9ad39e8dd07edfca6a204b Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Mon, 15 Nov 2021 11:52:55 +0200 Subject: [PATCH 017/407] iio:beamformer:adar300x: Check GPIO driver ready If adar300x driver is probed before GPIO return "-EPROBE_DEFER" so that it tries again later Signed-off-by: Cristian Pop --- drivers/iio/beamformer/adar300x.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/iio/beamformer/adar300x.c b/drivers/iio/beamformer/adar300x.c index b064aae490b975..9d12f87d3920cc 100644 --- a/drivers/iio/beamformer/adar300x.c +++ b/drivers/iio/beamformer/adar300x.c @@ -1568,8 +1568,19 @@ static int adar300x_probe(struct spi_device *spi, const struct attribute_group * return PTR_ERR(regmap); } - gpio_reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW); - if (!IS_ERR(gpio_reset)) + gpio_reset = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); + /* + * Test for EBUSY to check if other ADAR300x devices are defined on the same reset line, + * this is a valid case + */ + if (IS_ERR(gpio_reset) && PTR_ERR(gpio_reset) != -EBUSY) + return PTR_ERR(gpio_reset); + + /* + * Only one reset is needed for all devices connected on the same reset line, so check for + * EBUSY to determine if GPIO was allready got and used before + */ + if (gpio_reset && PTR_ERR(gpio_reset) != -EBUSY) ad300x_reset(gpio_reset); for_each_available_child_of_node(np, child) { From a8967e12523e4c9bf5e2f9eb4cae9dda92a12b21 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Fri, 8 Oct 2021 16:17:38 +0300 Subject: [PATCH 018/407] arch: arm64: dts: longs-peack: Add ad9081 support This is necessary for converting beamformer data. Signed-off-by: Cristian Pop --- .../dts/xilinx/adi-adar3002-longs-peack.dts | 33 +++++++++++++------ .../dts/xilinx/adi-adar3003-longs-peack.dts | 33 +++++++++++++------ 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peack.dts b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peack.dts index 3a8d36e3913f7e..0e15098e15f1f4 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peack.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peack.dts @@ -5,7 +5,7 @@ * Copyright (C) 2018-2019 Analog Devices Inc. */ -#include "zynqmp-zcu102-rev1.0.dts" +#include "zynqmp-zcu102-rev10-ad9081-m8-l4.dts" / { long_peack_control@0 { @@ -13,7 +13,7 @@ #address-cells = <1>; #size-cells = <0>; // 78 offset - out-gpios = <&gpio 110 0>, <&gpio 112 0>, <&gpio 113 0>; + out-gpios = <&gpio 138 0>, <&gpio 140 0>, <&gpio 141 0>; label = "long_peack_control"; channel@0 { @@ -31,10 +31,23 @@ }; }; -&spi0 { - status = "okay"; - num-cs = <8>; - is-decoded-cs = <1>; +&fpga_axi { + axi_spi_pmod: spi@84000000 { + #address-cells = <1>; + #size-cells = <0>; + bits-per-word = <8>; + compatible = "xlnx,xps-spi-2.00.a"; + fifo-size = <16>; + // 3 + 121 - 32 + interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>; + num-cs = <0x8>; + reg = <0x84000000 0x10000>; + xlnx,num-ss-bits = <0x8>; + xlnx,spi-mode = <0>; + }; +}; + +&axi_spi_pmod { adar3002_T0: adar3002_0@0 { compatible = "adi,adar3002"; reg = <0>; @@ -42,7 +55,7 @@ label = "adar3002_T0"; #address-cells = <1>; #size-cells = <0>; - reset-gpios = <&gpio 111 0>; + reset-gpios = <&gpio 139 0>; adar3002_0@0 { reg = <0>; @@ -120,7 +133,7 @@ label = "adar3002_T1"; #address-cells = <1>; #size-cells = <0>; - reset-gpios = <&gpio 111 0>; + reset-gpios = <&gpio 139 0>; adar3002_0@0 { reg = <0>; @@ -198,7 +211,7 @@ label = "adar3002_T2"; #address-cells = <1>; #size-cells = <0>; - reset-gpios = <&gpio 111 0>; + reset-gpios = <&gpio 139 0>; adar3002_0@0 { reg = <0>; @@ -276,7 +289,7 @@ label = "adar3002_T3"; #address-cells = <1>; #size-cells = <0>; - reset-gpios = <&gpio 111 0>; + reset-gpios = <&gpio 139 0>; adar3002_0@0 { reg = <0>; diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peack.dts b/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peack.dts index 48f27224bffea4..db63f843bdd5de 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peack.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peack.dts @@ -5,7 +5,7 @@ * Copyright (C) 2018-2019 Analog Devices Inc. */ -#include "zynqmp-zcu102-rev1.0.dts" +#include "zynqmp-zcu102-rev10-ad9081-m8-l4.dts" / { long_peack_control@0 { @@ -13,7 +13,7 @@ #address-cells = <1>; #size-cells = <0>; // 78 offset - out-gpios = <&gpio 110 0>, <&gpio 112 0>, <&gpio 113 0>; + out-gpios = <&gpio 138 0>, <&gpio 140 0>, <&gpio 141 0>; label = "long_peack_control"; channel@0 { @@ -31,10 +31,23 @@ }; }; -&spi0 { - status = "okay"; - num-cs = <8>; - is-decoded-cs = <1>; +&fpga_axi { + axi_spi_pmod: spi@84000000 { + #address-cells = <1>; + #size-cells = <0>; + bits-per-word = <8>; + compatible = "xlnx,xps-spi-2.00.a"; + fifo-size = <16>; + // 3 + 121 - 32 + interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>; + num-cs = <0x8>; + reg = <0x84000000 0x10000>; + xlnx,num-ss-bits = <0x8>; + xlnx,spi-mode = <0>; + }; +}; + +&axi_spi_pmod { adar3003_T0: adar3003_0@0 { compatible = "adi,adar3003"; reg = <0>; @@ -42,7 +55,7 @@ label = "adar3003_T0"; #address-cells = <1>; #size-cells = <0>; - reset-gpios = <&gpio 111 0>; + reset-gpios = <&gpio 139 0>; adar3003_0@0 { reg = <0>; @@ -120,7 +133,7 @@ label = "adar3003_T1"; #address-cells = <1>; #size-cells = <0>; - reset-gpios = <&gpio 111 0>; + reset-gpios = <&gpio 139 0>; adar3003_0@0 { reg = <0>; @@ -198,7 +211,7 @@ label = "adar3003_T2"; #address-cells = <1>; #size-cells = <0>; - reset-gpios = <&gpio 111 0>; + reset-gpios = <&gpio 139 0>; adar3003_0@0 { reg = <0>; @@ -276,7 +289,7 @@ label = "adar3003_T3"; #address-cells = <1>; #size-cells = <0>; - reset-gpios = <&gpio 111 0>; + reset-gpios = <&gpio 139 0>; adar3003_0@0 { reg = <0>; From 32b7bcd9010e126fc02a542facc9199b67b6b207 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Mon, 11 Oct 2021 14:24:50 +0300 Subject: [PATCH 019/407] arch: arm64: dts: longs-peack: Add support for rx back plane. Configure auxiliary chips into the receive data path: sc18is602, ad5760, adrf5720, adl5240. Signed-off-by: Cristian Pop --- .../dts/xilinx/adi-adar3002-longs-peack.dts | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peack.dts b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peack.dts index 0e15098e15f1f4..8eb265387d1bf9 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peack.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peack.dts @@ -8,6 +8,22 @@ #include "zynqmp-zcu102-rev10-ad9081-m8-l4.dts" / { + dac_vss: fixedregulator@1 { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + }; + + dac_vdd: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + }; + long_peack_control@0 { compatible = "adi,one-bit-adc-dac"; #address-cells = <1>; @@ -45,6 +61,78 @@ xlnx,num-ss-bits = <0x8>; xlnx,spi-mode = <0>; }; + axi_i2c_pmod: i2c@84500000 { + #address-cells = <1>; + #size-cells = <0>; + clock-names = "s_axi_aclk"; + clocks = <&zynqmp_clk 71>; + compatible = "xlnx,axi-iic-2.0", "xlnx,xps-iic-2.00.a"; + interrupt-names = "iic2intc_irpt"; + interrupts = <0 93 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x84500000 0x1000>; + }; +}; + +&axi_i2c_pmod { + #address-cells = <1>; + #size-cells = <0>; + i2c_to_spi_1: spi@28 { + compatible = "nxp,sc18is602"; + reg = <0x28>; + }; + + i2c_to_spi_2: spi@29 { + compatible = "nxp,sc18is602"; + reg = <0x29>; + }; +}; + +&i2c_to_spi_1 { + #address-cells = <1>; + #size-cells = <0>; + ad5760@0 { + compatible = "adi,ad5760"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpha; + vss-supply = <&dac_vss>; + vdd-supply = <&dac_vdd>; + }; + ad5760@1 { + compatible = "adi,ad5760"; + reg = <1>; + spi-max-frequency = <5000000>; + spi-cpha; + vss-supply = <&dac_vss>; + vdd-supply = <&dac_vdd>; + }; +}; + +&i2c_to_spi_2 { + #address-cells = <1>; + #size-cells = <0>; + adrf5720@0 { + compatible = "adi,adrf5720"; + reg = <0>; + spi-max-frequency = <10000000>; + }; + adrf5720@1 { + compatible = "adi,adrf5720"; + reg = <1>; + spi-max-frequency = <10000000>; + }; + adl5240@2 { + compatible = "adi,adl5240"; + reg = <2>; + spi-3wire; + spi-max-frequency = <10000000>; + }; + adl5240@3 { + compatible = "adi,adl5240"; + reg = <3>; + spi-3wire; + spi-max-frequency = <10000000>; + }; }; &axi_spi_pmod { From 05939468a423108f8089264677c42d9722efe8a6 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Tue, 12 Oct 2021 12:18:09 +0300 Subject: [PATCH 020/407] arch: arm64: dts: adar3003-longs-peack: Add EEPROM support Add I2C EEPROM. Signed-off-by: Cristian Pop --- .../dts/xilinx/adi-adar3003-longs-peack.dts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peack.dts b/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peack.dts index db63f843bdd5de..6ec6e0b545f40e 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peack.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peack.dts @@ -45,6 +45,31 @@ xlnx,num-ss-bits = <0x8>; xlnx,spi-mode = <0>; }; + axi_i2c_pmod: i2c@84500000 { + #address-cells = <1>; + #size-cells = <0>; + clock-names = "s_axi_aclk"; + clocks = <&zynqmp_clk 71>; + compatible = "xlnx,axi-iic-2.0", "xlnx,xps-iic-2.00.a"; + interrupt-names = "iic2intc_irpt"; + interrupts = <0 93 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x84500000 0x1000>; + }; +}; + +&axi_i2c_pmod { + #address-cells = <1>; + #size-cells = <0>; + i2c_eeprom1: eeprom@50 { + compatible = "atmel,24c32"; + reg = <0x50>; + pagesize = <32>; + }; + i2c_eeprom2: eeprom@51 { + compatible = "atmel,24c32"; + reg = <0x51>; + pagesize = <32>; + }; }; &axi_spi_pmod { From 2a728b914d6e10315f27d43f1c67bbd67c02440f Mon Sep 17 00:00:00 2001 From: Mihail Chindris Date: Thu, 7 Oct 2021 08:00:34 +0000 Subject: [PATCH 021/407] drivers: iio: dac: ad5766: Fix dt property name In the documentation the name for the property is output-range-microvolts which is a standard name, therefore this name must be used. Fixes: fd9373e41b9ba ("iio: dac: ad5766: add driver support for AD5766") Signed-off-by: Mihail Chindris Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20211007080035.2531-5-mihail.chindris@analog.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5766.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/dac/ad5766.c b/drivers/iio/dac/ad5766.c index ef1618ea6a20c6..015cb3ea94532b 100644 --- a/drivers/iio/dac/ad5766.c +++ b/drivers/iio/dac/ad5766.c @@ -503,13 +503,13 @@ static int ad5766_get_output_range(struct ad5766_state *st) int i, ret, min, max, tmp[2]; ret = device_property_read_u32_array(&st->spi->dev, - "output-range-voltage", + "output-range-microvolts", tmp, 2); if (ret) return ret; - min = tmp[0] / 1000; - max = tmp[1] / 1000; + min = tmp[0] / 1000000; + max = tmp[1] / 1000000; for (i = 0; i < ARRAY_SIZE(ad5766_span_tbl); i++) { if (ad5766_span_tbl[i].min != min || ad5766_span_tbl[i].max != max) From 8980137f03c2ded30fac336d6be775c68d3d7a36 Mon Sep 17 00:00:00 2001 From: Mihail Chindris Date: Thu, 7 Oct 2021 08:00:36 +0000 Subject: [PATCH 022/407] Documentation:devicetree:bindings:iio:dac: Fix val A correct value for output-range-microvolts is -5 to 5 Volts not -5 to 5 milivolts Fixes: e904cc899293f ("dt-bindings: iio: dac: AD5766 yaml documentation") Signed-off-by: Mihail Chindris Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20211007080035.2531-6-mihail.chindris@analog.com Cc: Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml index d5c54813ce872f..a8f7720d1e3e20 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml @@ -54,7 +54,7 @@ examples: ad5766@0 { compatible = "adi,ad5766"; - output-range-microvolts = <(-5000) 5000>; + output-range-microvolts = <(-5000000) 5000000>; reg = <0>; spi-cpol; spi-max-frequency = <1000000>; From 94d344afa9910e7a064dedb697eee31ab5818f91 Mon Sep 17 00:00:00 2001 From: Mihail Chindris Date: Thu, 7 Oct 2021 08:00:37 +0000 Subject: [PATCH 023/407] drivers:iio:dac:ad5766.c: Add trigger buffer This chip is able to generate waveform and using an with the output trigger buffer will be easy to generate one. Signed-off-by: Mihail Chindris Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20211007080035.2531-7-mihail.chindris@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5766.c | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/iio/dac/ad5766.c b/drivers/iio/dac/ad5766.c index 015cb3ea94532b..cbe2235652ea6b 100644 --- a/drivers/iio/dac/ad5766.c +++ b/drivers/iio/dac/ad5766.c @@ -5,10 +5,14 @@ * Copyright 2019-2020 Analog Devices Inc. */ #include +#include #include #include #include #include +#include +#include +#include #include #include #include @@ -455,6 +459,7 @@ static const struct iio_chan_spec_ext_info ad5766_ext_info[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | \ BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = (_chan), \ .scan_type = { \ .sign = 'u', \ .realbits = (_bits), \ @@ -576,6 +581,35 @@ static int ad5766_default_setup(struct ad5766_state *st) return __ad5766_spi_write(st, AD5766_CMD_SPAN_REG, st->crt_range); } +static irqreturn_t ad5766_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct iio_buffer *buffer = indio_dev->buffer; + struct ad5766_state *st = iio_priv(indio_dev); + int ret, ch, i; + u16 data[ARRAY_SIZE(ad5766_channels)]; + + ret = iio_buffer_remove_sample(buffer, (u8 *)data); + if (ret) + goto done; + + i = 0; + mutex_lock(&st->lock); + for_each_set_bit(ch, indio_dev->active_scan_mask, + st->chip_info->num_channels - 1) + __ad5766_spi_write(st, AD5766_CMD_WR_IN_REG(ch), data[i++]); + + __ad5766_spi_write(st, AD5766_CMD_SW_LDAC, + *indio_dev->active_scan_mask); + mutex_unlock(&st->lock); + +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static int ad5766_probe(struct spi_device *spi) { enum ad5766_type type; @@ -601,6 +635,7 @@ static int ad5766_probe(struct spi_device *spi) indio_dev->dev.of_node = spi->dev.of_node; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->direction = IIO_DEVICE_DIRECTION_OUT; st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", GPIOD_OUT_LOW); @@ -611,6 +646,12 @@ static int ad5766_probe(struct spi_device *spi) if (ret) return ret; + /* Configure trigger buffer */ + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + ad5766_trigger_handler, NULL); + if (ret) + return ret; + return devm_iio_device_register(&spi->dev, indio_dev); } From 31c99761aec28b1d9bbadf90a1220655a2fef23f Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 17 Nov 2021 09:06:31 +0100 Subject: [PATCH 024/407] dts: zynqmp-adrv9009-zu11eg-reva-adrv2crr-fmc-reva: Add FRU at 0x52 This adds the FRU eeprom found on the FMCOMMS8 Signed-off-by: Michael Hennerich --- .../zynqmp-adrv9009-zu11eg-reva-adrv2crr-fmc-reva.dts | 2 +- ...drv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8.dts | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva-adrv2crr-fmc-reva.dts b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva-adrv2crr-fmc-reva.dts index caac900a2957f9..65c26f93658bf6 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva-adrv2crr-fmc-reva.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva-adrv2crr-fmc-reva.dts @@ -428,7 +428,7 @@ }; }; - i2c@5 { /* FMC HPC */ + i2c_fmc: i2c@5 { /* FMC HPC */ #address-cells = <1>; #size-cells = <0>; reg = <5>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8.dts b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8.dts index febc489ad2a16c..ba5290e7e9d1bc 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8.dts @@ -13,6 +13,13 @@ */ #include "zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb.dts" +&i2c_fmc { /* FMC */ + eeprom@52 { + compatible = "at24,24c02"; + reg = <0x52>; + }; +}; + &trx0_adrv9009 { compatible = "adrv9009-x4"; }; From 5143b291c3ba674bb04ef5c276eefa667224946a Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Thu, 18 Nov 2021 11:06:11 +0200 Subject: [PATCH 025/407] arch: arm64: dts: stingray: Update GPIO pinouts This fixes xud control. Signed-off-by: Cristian Pop --- .../xilinx/zynqmp-zcu102-rev10-stingray.dts | 57 ++++++++++++++++++- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts index 4655d9919d7faf..e5e244c4cd674d 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts @@ -75,9 +75,50 @@ #address-cells = <1>; #size-cells = <0>; - out-gpios = <&gpio 145 0>, <&gpio 150 0>, <&gpio 154 0>; + out-gpios = <&gpio 145 0>, <&gpio 146 0>, <&gpio 147 0>, + <&gpio 148 0>, <&gpio 149 0>, <&gpio 150 0>; label = "xud_control"; + channel@0 { + reg = <0>; + label = "RX_GAIN_MODE"; + }; + + channel@1 { + reg = <1>; + label = "TXRX0"; + }; + + channel@2 { + reg = <2>; + label = "TXRX1"; + }; + + channel@3 { + reg = <3>; + label = "TXRX2"; + }; + + channel@4 { + reg = <4>; + label = "TXRX3"; + }; + + channel@5 { + reg = <5>; + label = "PLL_OUTPUT_SEL"; + }; + }; + + imu_control@2 { + compatible = "adi,one-bit-adc-dac"; + #address-cells = <1>; + #size-cells = <0>; + + out-gpios = <&gpio 151 0>, <&gpio 152 0>, <&gpio 153 0>, + <&gpio 154 0>, <&gpio 155 0>; + label = "imu_control"; + channel@0 { reg = <0>; label = "GPIO0"; @@ -85,12 +126,22 @@ channel@1 { reg = <1>; - label = "GPIO5"; + label = "GPIO1"; }; channel@2 { reg = <2>; - label = "IMU_GPIO3"; + label = "GPIO2"; + }; + + channel@3 { + reg = <3>; + label = "GPIO3"; + }; + + channel@4 { + reg = <4>; + label = "RST"; }; }; }; From 3a9cae08453e80e64e2a16b917f56259f71849a3 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Thu, 18 Nov 2021 12:49:20 +0200 Subject: [PATCH 026/407] arch/arm64/boot/dts/xilinx/adar: Rename files Fix typo Signed-off-by: Cristian Pop --- .../{adi-adar3002-longs-peack.dts => adi-adar3002-longs-peak.dts} | 0 .../{adi-adar3003-longs-peack.dts => adi-adar3003-longs-peak.dts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename arch/arm64/boot/dts/xilinx/{adi-adar3002-longs-peack.dts => adi-adar3002-longs-peak.dts} (100%) rename arch/arm64/boot/dts/xilinx/{adi-adar3003-longs-peack.dts => adi-adar3003-longs-peak.dts} (100%) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peack.dts b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts similarity index 100% rename from arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peack.dts rename to arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peack.dts b/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peak.dts similarity index 100% rename from arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peack.dts rename to arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peak.dts From 265b604d522765e37c515fadd1e20a6cadc08143 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Thu, 18 Nov 2021 12:50:43 +0200 Subject: [PATCH 027/407] arch/arm64/boot/dts/xilinx/adar3000: Fix typos Rename label and device. Signed-off-by: Cristian Pop --- arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts | 4 ++-- arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peak.dts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts index 8eb265387d1bf9..1f4280604bf282 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts @@ -24,13 +24,13 @@ regulator-boot-on; }; - long_peack_control@0 { + long_peak_control@0 { compatible = "adi,one-bit-adc-dac"; #address-cells = <1>; #size-cells = <0>; // 78 offset out-gpios = <&gpio 138 0>, <&gpio 140 0>, <&gpio 141 0>; - label = "long_peack_control"; + label = "long_peak_control"; channel@0 { reg = <0>; diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peak.dts b/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peak.dts index 6ec6e0b545f40e..6326f66aef3b97 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peak.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3003-longs-peak.dts @@ -8,13 +8,13 @@ #include "zynqmp-zcu102-rev10-ad9081-m8-l4.dts" / { - long_peack_control@0 { + long_peak_control@0 { compatible = "adi,one-bit-adc-dac"; #address-cells = <1>; #size-cells = <0>; // 78 offset out-gpios = <&gpio 138 0>, <&gpio 140 0>, <&gpio 141 0>; - label = "long_peack_control"; + label = "long_peak_control"; channel@0 { reg = <0>; From 7345c1ac54793ea86c52c83583381e8713285c77 Mon Sep 17 00:00:00 2001 From: "Liviu.Adace" Date: Thu, 18 Nov 2021 12:40:02 +0000 Subject: [PATCH 028/407] nios2: adi_defconfig: Fix CONFIG_NIOS2_DTB_SOURCE value Using newer Linux kernel versions, "arch/nios2/boot/dts/" is automatically appended to CONFIG_NIOS2_DTB_SOURCE. Otherwise: "make[2]: *** No rule to make target `arch/nios2/boot/dts/arch/nios2/boot/devicetree.dtb.o', needed by `arch/nios2/boot/dts/built-in.a'. Stop." Signed-off-by: Liviu.Adace --- arch/nios2/configs/adi_nios2_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/nios2/configs/adi_nios2_defconfig b/arch/nios2/configs/adi_nios2_defconfig index b171afa570c67d..2abcf842f802ec 100644 --- a/arch/nios2/configs/adi_nios2_defconfig +++ b/arch/nios2/configs/adi_nios2_defconfig @@ -14,7 +14,7 @@ CONFIG_SYSCTL_SYSCALL=y CONFIG_EMBEDDED=y CONFIG_SLAB=y CONFIG_NIOS2_DTB_SOURCE_BOOL=y -CONFIG_NIOS2_DTB_SOURCE="arch/nios2/boot/devicetree.dts" +CONFIG_NIOS2_DTB_SOURCE="devicetree.dts" CONFIG_NIOS2_HW_MUL_SUPPORT=y CONFIG_CUSTOM_CACHE_SETTINGS=y CONFIG_NIOS2_DCACHE_SIZE=0x8000 From fd253c673f18da56766fe833dd4f46e4a8141faf Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Wed, 17 Nov 2021 08:34:05 +0200 Subject: [PATCH 029/407] arm64: dts: xilinx: Add support for ADALM-PLUTO-NG The ADALM-PLUTO-NG Active Learning Module is an easy to use tool available from Analog Devices, Inc. (ADI) that can be used to introduce fundamentals of Software Defined Radio (SDR) or Radio Frequency (RF) or Communications as advanced topics in electrical engineering in a self or instructor lead setting. Signed-off-by: Dragos Bogdan --- .../arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts | 560 ++++++++++++++++++ 1 file changed, 560 insertions(+) create mode 100644 arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts b/arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts new file mode 100644 index 00000000000000..b9d51dc4218a21 --- /dev/null +++ b/arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts @@ -0,0 +1,560 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * dts file for Analog Devices, Inc. Pluto NG + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2021 Analog Devices Inc. + */ + +/dts-v1/; + +#include "zynqmp.dtsi" +#include "zynqmp-clk-ccf.dtsi" +#include +#include +#include +#include +#include + +/ { + model = "Analog Devices, Inc. Pluto NG"; + compatible = "xlnx,zynqmp"; + + aliases { + ethernet0 = &gem3; + mmc0 = &sdhci1; + rtc0 = &rtc; + serial0 = &uart1; + i2c0 = &i2c1; + spi0 = &spi0; + }; + + chosen { + bootargs = "earlycon"; + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x80000000>; + }; + + psgtr_ref0: ad9542_out0_b { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + }; + + psgtr_ref1: ad9542_out0_a { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <108000000>; + }; + + psgtr_ref2: ad9542_out1_b { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <150000000>; + }; +}; + +&psgtr { + status = "okay"; + clocks = <&psgtr_ref0>, <&psgtr_ref1>, <&psgtr_ref2>; + clock-names = "ref0", "ref1", "ref2"; +}; + +&pinctrl0 { + status = "okay"; + + pinctrl_uart1_default: uart1-default { + mux { + groups = "uart1_4_grp"; + function = "uart1"; + }; + + conf { + groups = "uart1_4_grp"; + slew-rate = ; + io-standard = ; + }; + + conf-rx { + pins = "MIO17"; + bias-high-impedance; + }; + + conf-tx { + pins = "MIO16"; + bias-disable; + }; + }; + + pinctrl_gem3_default: gem3-default { + mux { + function = "ethernet3"; + groups = "ethernet3_0_grp"; + }; + + conf { + groups = "ethernet3_0_grp"; + slew-rate = ; + io-standard = ; + }; + + conf-rx { + pins = "MIO70", "MIO71", "MIO72", + "MIO73", "MIO74", "MIO75"; + bias-high-impedance; + low-power-disable; + }; + + conf-tx { + pins = "MIO64", "MIO65", "MIO66", + "MIO67", "MIO68", "MIO69"; + bias-disable; + low-power-enable; + }; + + mux-mdio { + function = "mdio3"; + groups = "mdio3_0_grp"; + }; + + conf-mdio { + groups = "mdio3_0_grp"; + slew-rate = ; + io-standard = ; + bias-disable; + }; + }; + + pinctrl_sdhci1_default: sdhci1-default { + mux { + groups = "sdio1_0_grp"; + function = "sdio1"; + }; + + conf { + groups = "sdio1_0_grp"; + slew-rate = ; + io-standard = ; + bias-disable; + }; + + mux-cd { + groups = "sdio1_cd_0_grp"; + function = "sdio1_cd"; + }; + + conf-cd { + groups = "sdio1_cd_0_grp"; + bias-high-impedance; + bias-pull-up; + slew-rate = ; + io-standard = ; + }; + + mux-wp { + groups = "sdio1_wp_0_grp"; + function = "sdio1_wp"; + }; + + conf-wp { + groups = "sdio1_wp_0_grp"; + bias-high-impedance; + bias-pull-up; + slew-rate = ; + io-standard = ; + }; + }; + + pinctrl_i2c1_default: i2c1-default { + mux { + groups = "i2c1_8_grp"; + function = "i2c1"; + }; + + conf { + groups = "i2c1_8_grp"; + bias-pull-up; + slew-rate = ; + io-standard = ; + }; + }; + + pinctrl_usb0_default: usb0-default { + mux { + groups = "usb0_0_grp"; + function = "usb0"; + }; + + conf { + groups = "usb0_0_grp"; + slew-rate = ; + io-standard = ; + }; + + conf-rx { + pins = "MIO52", "MIO53", "MIO55"; + bias-high-impedance; + }; + + conf-tx { + pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59", + "MIO60", "MIO61", "MIO62", "MIO63"; + bias-disable; + }; + }; +}; + +&uart1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1_default>; +}; + +&gem3 { + status = "okay"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gem3_default>; + + phy0: phy@f { + reg = <0xf>; + }; +}; + +&sdhci1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdhci1_default>; + xlnx,mio_bank = <1>; +}; + +&i2c1 { + status = "okay"; + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1_default>; + + ltc2945@6a { + compatible = "adi,ltc2945"; + reg = <0x6a>; + }; +}; + +&zynqmp_dpsub { + status = "okay"; + phy-names = "dp-phy0"; + phys = <&psgtr 1 PHY_TYPE_DP 0 1>; +}; + +&zynqmp_dp_snd_codec0 { + status = "okay"; +}; + +&zynqmp_dp_snd_pcm0 { + status = "okay"; +}; + +&zynqmp_dp_snd_pcm1 { + status = "okay"; +}; + +&zynqmp_dp_snd_card0 { + status = "okay"; +}; + +&zynqmp_dpdma { + status = "okay"; +}; + +&sata { + status = "okay"; + ceva,p0-cominit-params = /bits/ 8 <0x18 0x40 0x18 0x28>; + ceva,p0-comwake-params = /bits/ 8 <0x06 0x14 0x08 0x0E>; + ceva,p0-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>; + ceva,p0-retry-params = /bits/ 16 <0x96A4 0x3FFC>; + ceva,p1-cominit-params = /bits/ 8 <0x18 0x40 0x18 0x28>; + ceva,p1-comwake-params = /bits/ 8 <0x06 0x14 0x08 0x0E>; + ceva,p1-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>; + ceva,p1-retry-params = /bits/ 16 <0x96A4 0x3FFC>; + phy-names = "sata-phy"; + phys = <&psgtr 3 PHY_TYPE_SATA 1 2>; +}; + +&usb0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb0_default>; +}; + +&dwc3_0 { + status = "okay"; + dr_mode = "otg"; + phy-names = "usb3-phy"; + phys = <&psgtr 0 PHY_TYPE_USB3 0 0>; + maximum-speed = "super-speed"; +}; + +&gpio { + status = "okay"; + + usb_reset { + gpio-hog; + gpios = <13 0>; + output-high; + line-name = "usb-reset"; + }; + + adrv9002_clksrc { + gpio-hog; + gpios = <79 0>; + output-high; + line-name = "adrv9002-clksrc"; + }; + + rf_rx1a_mux_ctl { + gpio-hog; + gpios = <86 0>; + output-high; + line-name = "rf_rx1a_mux_ctl"; + }; + rf_rx1b_mux_ctl { + gpio-hog; + gpios = <87 0>; + output-high; + line-name = "rf_rx1b_mux_ctl"; + }; + rf_rx2a_mux_ctl { + gpio-hog; + gpios = <88 0>; + output-high; + line-name = "rf_rx2a_mux_ctl"; + }; + rf_rx2b_mux_ctl { + gpio-hog; + gpios = <89 0>; + output-high; + line-name = "rf_rx2b_mux_ctl"; + }; + rf_tx1_mux_ctl1 { + gpio-hog; + gpios = <90 0>; + output-high; + line-name = "rf_tx1_mux_ctl1"; + }; + rf_tx1_mux_ctl2 { + gpio-hog; + gpios = <91 0>; + output-low; + line-name = "rf_tx1_mux_ctl2"; + }; + rf_tx2_mux_ctl1 { + gpio-hog; + gpios = <92 0>; + output-low; + line-name = "rf_tx2_mux_ctl1"; + }; + rf_tx2_mux_ctl2 { + gpio-hog; + gpios = <93 0>; + output-high; + line-name = "rf_tx2_mux_ctl2"; + }; +}; + +&spi0 { + status = "okay"; +}; + +&watchdog0 { + status = "okay"; +}; + +&xilinx_ams { + status = "okay"; +}; + +&ams_ps { + status = "okay"; +}; + +&ams_pl { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +/ { + fpga_axi { + interrupt-parent = <&gic>; + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges = <0 0 0 0xffffffff>; + + rx1_dma: dma@84A30000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x84A30000 0x10000>; + #dma-cells = <1>; + interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zynqmp_clk 71>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <64>; + adi,source-bus-type = <2>; + adi,destination-bus-width = <64>; + adi,destination-bus-type = <0>; + }; + }; + }; + + rx2_dma: dma@84A40000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x84A40000 0x10000>; + #dma-cells = <1>; + interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zynqmp_clk 71>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <64>; + adi,source-bus-type = <2>; + adi,destination-bus-width = <64>; + adi,destination-bus-type = <0>; + }; + }; + }; + + tx1_dma: dma@84A50000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x84A50000 0x10000>; + #dma-cells = <1>; + interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zynqmp_clk 71>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <64>; + adi,source-bus-type = <0>; + adi,destination-bus-width = <64>; + adi,destination-bus-type = <2>; + }; + }; + }; + + tx2_dma: dma@84A6000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x84A60000 0x10000>; + #dma-cells = <1>; + interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zynqmp_clk 71>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <64>; + adi,source-bus-type = <0>; + adi,destination-bus-width = <64>; + adi,destination-bus-type = <2>; + }; + }; + }; + + axi_adrv9002_core_rx1: axi-adrv9002-rx-lpc@84A00000 { + compatible = "adi,axi-adrv9002-rx-1.0"; + reg = <0x84A00000 0x6000>; + clocks = <&adc0_adrv9002 0>; + dmas = <&rx1_dma 0>; + dma-names = "rx"; + spibus-connected = <&adc0_adrv9002>; + }; + + axi_adrv9002_core_tx1: axi-adrv9002-tx-lpc@84A04000 { + compatible = "adi,axi-adrv9002-tx-1.0"; + reg = <0x84A0A000 0x2000>; + clocks = <&adc0_adrv9002 1>; + clock-names = "sampl_clk"; + dmas = <&tx1_dma 0>; + dma-names = "tx"; + adi,axi-dds-default-scale = <0x800>; + adi,axi-dds-default-frequency = <2000000>; + }; + + axi_adrv9002_core_rx2: axi-adrv9002-rx2-lpc@84A02000 { + compatible = "adi,axi-adrv9002-rx2-1.0"; + reg = <0x84A09000 0x1000>; + clocks = <&adc0_adrv9002 3>; + clock-names = "sampl_clk"; + dmas = <&rx2_dma 0>; + dma-names = "rx"; + }; + + axi_adrv9002_core_tx2: axi-adrv9002-tx2-lpc@84A06000 { + compatible = "adi,axi-adrv9002-tx-1.0"; + reg = <0x84A0C000 0x2000>; + clocks = <&adc0_adrv9002 4>; + clock-names = "sampl_clk"; + dmas = <&tx2_dma 0>; + dma-names = "tx"; + adi,axi-dds-default-scale = <0x800>; + adi,axi-dds-default-frequency = <2000000>; + }; + + axi_sysid_0: axi-sysid-0@85000000 { + compatible = "adi,axi-sysid-1.00.a"; + reg = <0x85000000 0x10000>; + }; + }; + + gpio-keys-power { + #address-cells = <1>; + #size-cells = <0>; + compatible = "gpio-keys"; + + power { + interrupt-parent = <&gpio>; + interrupts = <20 IRQ_TYPE_EDGE_FALLING>; + label = "Power"; + linux,code = ; + gpio-key,wakeup; + }; + }; + + gpio-poweroff { + compatible = "gpio-poweroff"; + gpios = <&gpio 19 GPIO_ACTIVE_LOW>; + }; +}; + +#define fmc_spi spi0 + +#include "adi-adrv9002.dtsi" + +&adc0_adrv9002 { + reset-gpios = <&gpio 81 GPIO_ACTIVE_LOW>; + interrupts = <78 IRQ_TYPE_EDGE_RISING>; +}; From aa385f3df441d607118a6931342dedfc88969154 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 29 Nov 2021 16:43:47 +0200 Subject: [PATCH 030/407] drivers:iio:frequency: adrf6780 sync with upstream Sync driver with the upstream version. Signed-off-by: Antoniu Miclaus --- drivers/iio/frequency/adrf6780.c | 489 +++++++++++++++---------------- 1 file changed, 241 insertions(+), 248 deletions(-) diff --git a/drivers/iio/frequency/adrf6780.c b/drivers/iio/frequency/adrf6780.c index c492c4e4adf10f..8255ffd174f6a2 100644 --- a/drivers/iio/frequency/adrf6780.c +++ b/drivers/iio/frequency/adrf6780.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +// SPDX-License-Identifier: GPL-2.0-only /* * ADRF6780 driver * @@ -14,9 +14,11 @@ #include #include #include -#include +#include #include +#include + /* ADRF6780 Register Map */ #define ADRF6780_REG_CONTROL 0x00 #define ADRF6780_REG_ALARM_READBACK 0x01 @@ -29,84 +31,52 @@ /* 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) - -enum supported_parts { - ADRF6780, -}; -struct adrf6780_dev { +struct adrf6780_state { struct spi_device *spi; struct clk *clkin; /* Protect against concurrent accesses to the device */ struct mutex lock; - bool parity_en; bool vga_buff_en; - bool det_en; bool lo_buff_en; bool if_mode_en; bool iq_mode_en; @@ -116,158 +86,155 @@ struct adrf6780_dev { bool uc_bias_en; bool lo_sideband; bool vdet_out_en; + u8 data[3] ____cacheline_aligned; }; -static int adrf6780_spi_read(struct adrf6780_dev *dev, unsigned int reg, - unsigned int *val) +static int __adrf6780_spi_read(struct adrf6780_state *st, unsigned int reg, + unsigned int *val) { int ret; - unsigned int cnt, temp; struct spi_transfer t = {0}; - u8 data[3]; - data[0] = 0x80 | (reg << 1); - data[1] = 0x0; - data[2] = 0x0; + st->data[0] = 0x80 | (reg << 1); + st->data[1] = 0x0; + st->data[2] = 0x0; - t.rx_buf = &data[0]; - t.tx_buf = &data[0]; + t.rx_buf = &st->data[0]; + t.tx_buf = &st->data[0]; t.len = 3; - ret = spi_sync_transfer(dev->spi, &t, 1); - if (ret < 0) + ret = spi_sync_transfer(st->spi, &t, 1); + if (ret) return ret; - temp = ((data[0] | 0x80 | (reg << 1)) << 16) | - (data[1] << 8) | data[2]; + *val = (get_unaligned_be24(&st->data[0]) >> 1) & GENMASK(15, 0); - if (dev->parity_en) { - cnt = hweight_long(temp); - if (!(cnt % 2)) - return -EINVAL; - } + return ret; +} + +static int adrf6780_spi_read(struct adrf6780_state *st, unsigned int reg, + unsigned int *val) +{ + int ret; - *val = (temp >> 1) & 0xFFFF; + mutex_lock(&st->lock); + ret = __adrf6780_spi_read(st, reg, val); + mutex_unlock(&st->lock); return ret; } -static int adrf6780_spi_write(struct adrf6780_dev *dev, - unsigned int reg, - unsigned int val) +static int __adrf6780_spi_write(struct adrf6780_state *st, + unsigned int reg, + unsigned int val) { - unsigned int cnt; - u8 data[3]; + put_unaligned_be24((val << 1) | (reg << 17), &st->data[0]); - val = (val << 1); + return spi_write(st->spi, &st->data[0], 3); +} - if (dev->parity_en) { - cnt = hweight_long((reg << 17) | val); - if (cnt % 2 == 0) - val |= 0x1; - } +static int adrf6780_spi_write(struct adrf6780_state *st, unsigned int reg, + unsigned int val) +{ + int ret; - data[0] = (reg << 1) | (val >> 16); - data[1] = val >> 8; - data[2] = val; + mutex_lock(&st->lock); + ret = __adrf6780_spi_write(st, reg, val); + mutex_unlock(&st->lock); - return spi_write(dev->spi, &data[0], 3); + return ret; } -static int __adrf6780_spi_update_bits(struct adrf6780_dev *dev, unsigned int reg, - unsigned int mask, unsigned int val) +static int __adrf6780_spi_update_bits(struct adrf6780_state *st, + unsigned int reg, unsigned int mask, + unsigned int val) { int ret; unsigned int data, temp; - ret = adrf6780_spi_read(dev, reg, &data); - if (ret < 0) + ret = __adrf6780_spi_read(st, reg, &data); + if (ret) return ret; temp = (data & ~mask) | (val & mask); - return adrf6780_spi_write(dev, reg, temp); + return __adrf6780_spi_write(st, reg, temp); +} + +static int adrf6780_spi_update_bits(struct adrf6780_state *st, unsigned int reg, + unsigned int mask, unsigned int val) +{ + int ret; + + mutex_lock(&st->lock); + ret = __adrf6780_spi_update_bits(st, reg, mask, val); + mutex_unlock(&st->lock); + + return ret; } -static int adrf6780_spi_update_bits(struct adrf6780_dev *dev, unsigned int reg, - unsigned int mask, unsigned int val) +static int adrf6780_read_adc_raw(struct adrf6780_state *st, unsigned int *read_val) { int ret; - mutex_lock(&dev->lock); - ret = __adrf6780_spi_update_bits(dev, reg, mask, val); - mutex_unlock(&dev->lock); + mutex_lock(&st->lock); + + ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_ADC_CONTROL, + ADRF6780_ADC_EN_MSK | + ADRF6780_ADC_CLOCK_EN_MSK | + ADRF6780_ADC_START_MSK, + FIELD_PREP(ADRF6780_ADC_EN_MSK, 1) | + FIELD_PREP(ADRF6780_ADC_CLOCK_EN_MSK, 1) | + FIELD_PREP(ADRF6780_ADC_START_MSK, 1)); + if (ret) + goto exit; + + /* Recommended delay for the ADC to be ready*/ + usleep_range(200, 250); + + ret = __adrf6780_spi_read(st, ADRF6780_REG_ADC_OUTPUT, read_val); + if (ret) + goto exit; + + if (!(*read_val & ADRF6780_ADC_STATUS_MSK)) { + ret = -EINVAL; + goto exit; + } + + ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_ADC_CONTROL, + ADRF6780_ADC_START_MSK, + FIELD_PREP(ADRF6780_ADC_START_MSK, 0)); + if (ret) + goto exit; + + ret = __adrf6780_spi_read(st, ADRF6780_REG_ADC_OUTPUT, read_val); + +exit: + mutex_unlock(&st->lock); return ret; } static int adrf6780_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long info) + struct iio_chan_spec const *chan, + int *val, int *val2, long info) { - struct adrf6780_dev *dev = iio_priv(indio_dev); + struct adrf6780_state *dev = iio_priv(indio_dev); unsigned int data; int ret; switch (info) { case IIO_CHAN_INFO_RAW: - mutex_lock(&dev->lock); - - ret = __adrf6780_spi_update_bits(dev, ADRF6780_REG_ENABLE, - ADRF6780_DETECTOR_EN_MSK, - ADRF6780_DETECTOR_EN(1)); - if (ret < 0) - goto exit; - - ret = __adrf6780_spi_update_bits(dev, ADRF6780_REG_ADC_CONTROL, - ADRF6780_ADC_EN_MSK, - ADRF6780_ADC_EN(1)); - if (ret < 0) - goto exit; - - ret = __adrf6780_spi_update_bits(dev, ADRF6780_REG_ADC_CONTROL, - ADRF6780_ADC_CLOCK_EN_MSK, - ADRF6780_ADC_CLOCK_EN(1)); - if (ret < 0) - goto exit; - - ret = __adrf6780_spi_update_bits(dev, ADRF6780_REG_ADC_CONTROL, - ADRF6780_ADC_START_MSK, - ADRF6780_ADC_START(1)); - if (ret < 0) - goto exit; - - usleep_range(200, 250); - - ret = adrf6780_spi_read(dev, ADRF6780_REG_ADC_OUTPUT, &data); - if (ret < 0) - goto exit; - - if (!(data & ADRF6780_ADC_STATUS_MSK)) { - ret = -EINVAL; - goto exit; - } - - ret = __adrf6780_spi_update_bits(dev, ADRF6780_REG_ADC_CONTROL, - ADRF6780_ADC_START_MSK, - ADRF6780_ADC_START(0)); - if (ret < 0) - goto exit; - - ret = adrf6780_spi_read(dev, ADRF6780_REG_ADC_OUTPUT, &data); - if (ret < 0) - goto exit; - - mutex_unlock(&dev->lock); + ret = adrf6780_read_adc_raw(dev, &data); + if (ret) + return ret; *val = data & ADRF6780_ADC_VALUE_MSK; return IIO_VAL_INT; -exit: - mutex_unlock(&dev->lock); - return ret; + case IIO_CHAN_INFO_SCALE: ret = adrf6780_spi_read(dev, ADRF6780_REG_LINEARIZE, &data); - if (ret < 0) + if (ret) return ret; *val = data & ADRF6780_RDAC_LINEARIZE_MSK; @@ -275,56 +242,67 @@ static int adrf6780_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_PHASE: ret = adrf6780_spi_read(dev, ADRF6780_REG_LO_PATH, &data); - if (ret < 0) + if (ret) return ret; - if (chan->channel2 == IIO_MOD_I) + switch (chan->channel2) { + case IIO_MOD_I: *val = data & ADRF6780_I_PATH_PHASE_ACCURACY_MSK; - else - *val = (data & ADRF6780_Q_PATH_PHASE_ACCURACY_MSK) >> 4; - return IIO_VAL_INT; + return IIO_VAL_INT; + case IIO_MOD_Q: + *val = FIELD_GET(ADRF6780_Q_PATH_PHASE_ACCURACY_MSK, + data); + + return IIO_VAL_INT; + default: + return -EINVAL; + } default: return -EINVAL; } } static int adrf6780_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long info) + struct iio_chan_spec const *chan, + int val, int val2, long info) { - struct adrf6780_dev *dev = iio_priv(indio_dev); - int ret; + struct adrf6780_state *st = iio_priv(indio_dev); switch (info) { case IIO_CHAN_INFO_SCALE: - return adrf6780_spi_write(dev, ADRF6780_REG_LINEARIZE, val); + return adrf6780_spi_write(st, ADRF6780_REG_LINEARIZE, val); case IIO_CHAN_INFO_PHASE: - if (chan->channel2 == IIO_MOD_I) - ret = adrf6780_spi_update_bits(dev, ADRF6780_REG_LO_PATH, - ADRF6780_I_PATH_PHASE_ACCURACY_MSK, - ADRF6780_I_PATH_PHASE_ACCURACY(val)); - else - ret = adrf6780_spi_update_bits(dev, ADRF6780_REG_LO_PATH, - ADRF6780_Q_PATH_PHASE_ACCURACY_MSK, - ADRF6780_Q_PATH_PHASE_ACCURACY(val)); - return ret; + switch (chan->channel2) { + case IIO_MOD_I: + return adrf6780_spi_update_bits(st, + ADRF6780_REG_LO_PATH, + ADRF6780_I_PATH_PHASE_ACCURACY_MSK, + FIELD_PREP(ADRF6780_I_PATH_PHASE_ACCURACY_MSK, val)); + case IIO_MOD_Q: + return adrf6780_spi_update_bits(st, + ADRF6780_REG_LO_PATH, + ADRF6780_Q_PATH_PHASE_ACCURACY_MSK, + FIELD_PREP(ADRF6780_Q_PATH_PHASE_ACCURACY_MSK, val)); + default: + return -EINVAL; + } default: return -EINVAL; } } static int adrf6780_reg_access(struct iio_dev *indio_dev, - unsigned int reg, - unsigned int write_val, - unsigned int *read_val) + unsigned int reg, + unsigned int write_val, + unsigned int *read_val) { - struct adrf6780_dev *dev = iio_priv(indio_dev); + struct adrf6780_state *st = iio_priv(indio_dev); if (read_val) - return adrf6780_spi_read(dev, reg, read_val); + return adrf6780_spi_read(st, reg, read_val); else - return adrf6780_spi_write(dev, reg, write_val); + return adrf6780_spi_write(st, reg, write_val); } static const struct iio_info adrf6780_info = { @@ -333,16 +311,23 @@ static const struct iio_info adrf6780_info = { .debugfs_reg_access = &adrf6780_reg_access, }; -#define ADRF6780_CHAN(_channel) { \ - .type = IIO_VOLTAGE, \ +#define ADRF6780_CHAN_ADC(_channel) { \ + .type = IIO_ALTVOLTAGE, \ + .output = 0, \ + .indexed = 1, \ + .channel = _channel, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ +} + +#define ADRF6780_CHAN_RDAC(_channel) { \ + .type = IIO_ALTVOLTAGE, \ .output = 1, \ .indexed = 1, \ .channel = _channel, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_SCALE) \ + .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) \ } -#define ADRF6780_CHAN_IQ(_channel, rf_comp) { \ +#define ADRF6780_CHAN_IQ_PHASE(_channel, rf_comp) { \ .type = IIO_ALTVOLTAGE, \ .modified = 1, \ .output = 1, \ @@ -353,50 +338,52 @@ static const struct iio_info adrf6780_info = { } static const struct iio_chan_spec adrf6780_channels[] = { - ADRF6780_CHAN(0), - ADRF6780_CHAN_IQ(0, I), - ADRF6780_CHAN_IQ(0, Q), + ADRF6780_CHAN_ADC(0), + ADRF6780_CHAN_RDAC(0), + ADRF6780_CHAN_IQ_PHASE(0, I), + ADRF6780_CHAN_IQ_PHASE(0, Q), }; -static int adrf6780_init(struct adrf6780_dev *dev) +static int adrf6780_reset(struct adrf6780_state *st) { int ret; - unsigned int chip_id, enable_reg, enable_reg_msk; - struct spi_device *spi = dev->spi; - bool temp_parity = dev->parity_en; + struct spi_device *spi = st->spi; - dev->parity_en = false; - - /* Perform a software reset */ - ret = __adrf6780_spi_update_bits(dev, ADRF6780_REG_CONTROL, - ADRF6780_SOFT_RESET_MSK, - ADRF6780_SOFT_RESET(1)); - if (ret < 0) { + ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_CONTROL, + ADRF6780_SOFT_RESET_MSK, + FIELD_PREP(ADRF6780_SOFT_RESET_MSK, 1)); + if (ret) { dev_err(&spi->dev, "ADRF6780 SPI software reset failed.\n"); return ret; } - ret = __adrf6780_spi_update_bits(dev, ADRF6780_REG_CONTROL, - ADRF6780_SOFT_RESET_MSK, - ADRF6780_SOFT_RESET(0)); - if (ret < 0) { + ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_CONTROL, + ADRF6780_SOFT_RESET_MSK, + FIELD_PREP(ADRF6780_SOFT_RESET_MSK, 0)); + if (ret) { dev_err(&spi->dev, "ADRF6780 SPI software reset disable failed.\n"); return ret; } - ret = __adrf6780_spi_update_bits(dev, ADRF6780_REG_CONTROL, - ADRF6780_PARITY_EN_MSK, - ADRF6780_PARITY_EN(temp_parity)); - if (ret < 0) - return ret; + return 0; +} + +static int adrf6780_init(struct adrf6780_state *st) +{ + int ret; + unsigned int chip_id, enable_reg, enable_reg_msk; + struct spi_device *spi = st->spi; - dev->parity_en = temp_parity; + /* Perform a software reset */ + ret = adrf6780_reset(st); + if (ret) + return ret; - ret = adrf6780_spi_read(dev, ADRF6780_REG_CONTROL, &chip_id); - if (ret < 0) + ret = __adrf6780_spi_read(st, ADRF6780_REG_CONTROL, &chip_id); + if (ret) return ret; - chip_id = (chip_id & ADRF6780_CHIP_ID_MSK) >> 4; + chip_id = FIELD_GET(ADRF6780_CHIP_ID_MSK, chip_id); if (chip_id != ADRF6780_CHIP_ID) { dev_err(&spi->dev, "ADRF6780 Invalid Chip ID.\n"); return -EINVAL; @@ -412,29 +399,46 @@ static int adrf6780_init(struct adrf6780_dev *dev) ADRF6780_LO_EN_MSK | ADRF6780_UC_BIAS_EN_MSK; - enable_reg = ADRF6780_VGA_BUFFER_EN(dev->vga_buff_en) | - ADRF6780_DETECTOR_EN(dev->det_en) | - ADRF6780_LO_BUFFER_EN(dev->lo_buff_en) | - ADRF6780_IF_MODE_EN(dev->if_mode_en) | - ADRF6780_IQ_MODE_EN(dev->iq_mode_en) | - ADRF6780_LO_X2_EN(dev->lo_x2_en) | - ADRF6780_LO_PPF_EN(dev->lo_ppf_en) | - ADRF6780_LO_EN(dev->lo_en) | - ADRF6780_UC_BIAS_EN(dev->uc_bias_en); - - ret = __adrf6780_spi_update_bits(dev, ADRF6780_REG_ENABLE, enable_reg_msk, enable_reg); - if (ret < 0) + enable_reg = FIELD_PREP(ADRF6780_VGA_BUFFER_EN_MSK, st->vga_buff_en) | + FIELD_PREP(ADRF6780_DETECTOR_EN_MSK, 1) | + FIELD_PREP(ADRF6780_LO_BUFFER_EN_MSK, st->lo_buff_en) | + FIELD_PREP(ADRF6780_IF_MODE_EN_MSK, st->if_mode_en) | + FIELD_PREP(ADRF6780_IQ_MODE_EN_MSK, st->iq_mode_en) | + FIELD_PREP(ADRF6780_LO_X2_EN_MSK, st->lo_x2_en) | + FIELD_PREP(ADRF6780_LO_PPF_EN_MSK, st->lo_ppf_en) | + FIELD_PREP(ADRF6780_LO_EN_MSK, st->lo_en) | + FIELD_PREP(ADRF6780_UC_BIAS_EN_MSK, st->uc_bias_en); + + ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_ENABLE, + enable_reg_msk, enable_reg); + if (ret) return ret; - ret = __adrf6780_spi_update_bits(dev, ADRF6780_REG_LO_PATH, - ADRF6780_LO_SIDEBAND_MSK, - ADRF6780_LO_SIDEBAND(dev->lo_sideband)); - if (ret < 0) + ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_LO_PATH, + ADRF6780_LO_SIDEBAND_MSK, + FIELD_PREP(ADRF6780_LO_SIDEBAND_MSK, st->lo_sideband)); + if (ret) return ret; - return __adrf6780_spi_update_bits(dev, ADRF6780_REG_ADC_CONTROL, - ADRF6780_VDET_OUTPUT_SELECT_MSK, - ADRF6780_VDET_OUTPUT_SELECT(dev->vdet_out_en)); + return __adrf6780_spi_update_bits(st, ADRF6780_REG_ADC_CONTROL, + ADRF6780_VDET_OUTPUT_SELECT_MSK, + FIELD_PREP(ADRF6780_VDET_OUTPUT_SELECT_MSK, st->vdet_out_en)); +} + +static void adrf6780_properties_parse(struct adrf6780_state *st) +{ + struct spi_device *spi = st->spi; + + st->vga_buff_en = device_property_read_bool(&spi->dev, "adi,vga-buff-en"); + st->lo_buff_en = device_property_read_bool(&spi->dev, "adi,lo-buff-en"); + st->if_mode_en = device_property_read_bool(&spi->dev, "adi,if-mode-en"); + st->iq_mode_en = device_property_read_bool(&spi->dev, "adi,iq-mode-en"); + st->lo_x2_en = device_property_read_bool(&spi->dev, "adi,lo-x2-en"); + st->lo_ppf_en = device_property_read_bool(&spi->dev, "adi,lo-ppf-en"); + st->lo_en = device_property_read_bool(&spi->dev, "adi,lo-en"); + st->uc_bias_en = device_property_read_bool(&spi->dev, "adi,uc-bias-en"); + st->lo_sideband = device_property_read_bool(&spi->dev, "adi,lo-sideband"); + st->vdet_out_en = device_property_read_bool(&spi->dev, "adi,vdet-out-en"); } static void adrf6780_clk_disable(void *data) @@ -442,80 +446,69 @@ static void adrf6780_clk_disable(void *data) clk_disable_unprepare(data); } -static int adrf6780_dt_parse(struct adrf6780_dev *dev) +static void adrf6780_powerdown(void *data) { - struct spi_device *spi = dev->spi; - - dev->parity_en = of_property_read_bool(spi->dev.of_node, "adi,parity-en"); - dev->vga_buff_en = of_property_read_bool(spi->dev.of_node, "adi,vga-buff-en"); - dev->det_en = of_property_read_bool(spi->dev.of_node, "adi,det-en"); - dev->lo_buff_en = of_property_read_bool(spi->dev.of_node, "adi,lo-buff-en"); - dev->if_mode_en = of_property_read_bool(spi->dev.of_node, "adi,if-mode-en"); - dev->iq_mode_en = of_property_read_bool(spi->dev.of_node, "adi,iq-mode-en"); - dev->lo_x2_en = of_property_read_bool(spi->dev.of_node, "adi,lo-x2-en"); - dev->lo_ppf_en = of_property_read_bool(spi->dev.of_node, "adi,lo-ppf-en"); - dev->lo_en = of_property_read_bool(spi->dev.of_node, "adi,lo-en"); - dev->uc_bias_en = of_property_read_bool(spi->dev.of_node, "adi,uc-bias-en"); - dev->lo_sideband = of_property_read_bool(spi->dev.of_node, "adi,lo-sideband"); - dev->vdet_out_en = of_property_read_bool(spi->dev.of_node, "adi,vdet-out-en"); - - dev->clkin = devm_clk_get(&spi->dev, "lo_in"); - if (IS_ERR(dev->clkin)) - return PTR_ERR(dev->clkin); - - return 0; + /* Disable all components in the Enable Register */ + adrf6780_spi_write(data, ADRF6780_REG_ENABLE, 0x0); } static int adrf6780_probe(struct spi_device *spi) { struct iio_dev *indio_dev; - struct adrf6780_dev *dev; + struct adrf6780_state *st; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*dev)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; - dev = iio_priv(indio_dev); + st = iio_priv(indio_dev); - indio_dev->dev.parent = &spi->dev; indio_dev->info = &adrf6780_info; indio_dev->name = "adrf6780"; indio_dev->channels = adrf6780_channels; indio_dev->num_channels = ARRAY_SIZE(adrf6780_channels); - dev->spi = spi; + st->spi = spi; - ret = adrf6780_dt_parse(dev); - if (ret < 0) - return ret; + adrf6780_properties_parse(st); - ret = clk_prepare_enable(dev->clkin); - if (ret < 0) + st->clkin = devm_clk_get(&spi->dev, "lo_in"); + if (IS_ERR(st->clkin)) + return dev_err_probe(&spi->dev, PTR_ERR(st->clkin), + "failed to get the LO input clock\n"); + + ret = clk_prepare_enable(st->clkin); + if (ret) return ret; - ret = devm_add_action_or_reset(&spi->dev, adrf6780_clk_disable, dev->clkin); - if (ret < 0) + ret = devm_add_action_or_reset(&spi->dev, adrf6780_clk_disable, + st->clkin); + if (ret) return ret; - mutex_init(&dev->lock); + mutex_init(&st->lock); + + ret = adrf6780_init(st); + if (ret) + return ret; - ret = adrf6780_init(dev); - if (ret < 0) + ret = devm_add_action_or_reset(&spi->dev, adrf6780_powerdown, st); + if (ret) return ret; return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id adrf6780_id[] = { - { "adrf6780", ADRF6780 }, + { "adrf6780", 0 }, {} }; MODULE_DEVICE_TABLE(spi, adrf6780_id); static const struct of_device_id adrf6780_of_match[] = { { .compatible = "adi,adrf6780" }, - {}, + {} }; MODULE_DEVICE_TABLE(of, adrf6780_of_match); From f86861b539c74155b5fd2bbd9ccff3e85e30c80b Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 29 Nov 2021 16:46:43 +0200 Subject: [PATCH 031/407] doc:dt-bindings:adrf6780: sync with upstream Sync adrf6780 dt bindings with the upstream version. Signed-off-by: Antoniu Miclaus --- .../bindings/iio/frequency/adi,adrf6780.yaml | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,adrf6780.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,adrf6780.yaml index 1c27f7069de3cb..3a8ea93f4e0c1e 100644 --- a/Documentation/devicetree/bindings/iio/frequency/adi,adrf6780.yaml +++ b/Documentation/devicetree/bindings/iio/frequency/adi,adrf6780.yaml @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- $id: http://devicetree.org/schemas/iio/frequency/adi,adrf6780.yaml# @@ -7,11 +7,14 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: ADRF6780 Microwave Upconverter maintainers: -- Antoniu Miclaus + - Antoniu Miclaus description: | - wideband, microwave upconverter optimized for point to point microwave + Wideband, microwave upconverter optimized for point to point microwave radio designs operating in the 5.9 GHz to 23.6 GHz frequency range. + + https://www.analog.com/en/products/adrf6780.html + properties: compatible: enum: @@ -25,107 +28,104 @@ properties: clocks: description: - Definition of the external clock (see clock/clock-bindings.txt) + Definition of the external clock. minItems: 1 clock-names: - description: - Must be "lo_in" - maxItems: 1 + items: + - const: lo_in clock-output-names: maxItems: 1 - adi,parity-en: - description: - Enable Parity for Write execution. - type: boolean - adi,vga-buff-en: description: - VGA Buffer Enable. - type: boolean - - adi,det-en: - description: - Detector Enable. + RF Variable Gain Amplifier Buffer Enable. Gain is controlled by + the voltage on the VATT pin. type: boolean adi,lo-buff-en: description: - LO Buffer Enable. + Local Oscillator Amplifier Enable. Disable to put the part in + a power down state. type: boolean adi,if-mode-en: description: - IF Mode Enable. + Intermediate Frequency Mode Enable. Either IF Mode or I/Q Mode + can be enabled at a time. type: boolean adi,iq-mode-en: description: - IQ Mode Enable. + I/Q Mode Enable. Either IF Mode or I/Q Mode can be enabled at a + time. type: boolean adi,lo-x2-en: description: - LO x2 Enable. + Double the Local Oscillator output frequency from the Local + Oscillator Input Frequency. Either LOx1 or LOx2 can be enabled + at a time. type: boolean adi,lo-ppf-en: description: - LO x1 Enable. + Local Oscillator input frequency equal to the Local Oscillator + output frequency (LO x1). Either LOx1 or LOx2 can be enabled + at a time. type: boolean adi,lo-en: description: - LO Enable. + Enable additional cirtuitry in the LO chain. Disable to put the + part in a power down state. type: boolean adi,uc-bias-en: description: - UC Bias Enable. + Enable all bias circuitry thourghout the entire part. + Disable to put the part in a power down state. type: boolean adi,lo-sideband: description: - Switch to the Other LO Sideband. + Switch to the Lower LO Sideband. By default the Upper LO + sideband is enabled. type: boolean adi,vdet-out-en: description: - VDET Output Select Enable. + VDET Output Select Enable. Expose the RF detector output to the + VDET external pin. type: boolean - '#address-cells': - const: 1 - - '#size-cells': - const: 0 - '#clock-cells': const: 0 +dependencies: + adi,lo-x2-en: [ "adi,lo-en" ] + adi,lo-ppf-en: [ "adi,lo-en" ] + required: -- compatible -- reg -- clocks -- clock-names + - compatible + - reg + - clocks + - clock-names additionalProperties: false examples: -- | + - | spi { #address-cells = <1>; #size-cells = <0>; - adrf6780@0{ + adrf6780@0 { compatible = "adi,adrf6780"; reg = <0>; spi-max-frequency = <1000000>; clocks = <&adrf6780_lo>; clock-names = "lo_in"; - adi,parity-en; }; }; ... - From a256e98cb806ece989809cad306fbccb3c7842d2 Mon Sep 17 00:00:00 2001 From: David Winter Date: Wed, 24 Nov 2021 12:44:14 +0100 Subject: [PATCH 032/407] arm64: dts: zcu102-adrv9002: Move EEPROM to HPC0 In accordance with the HDL the EEPROM is expected to be available on HPC0 not HPC1. Signed-off-by: David Winter --- .../dts/xilinx/zynqmp-zcu102-rev10-adrv9002-rx2tx2.dts | 6 +++--- .../arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9002.dts | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9002-rx2tx2.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9002-rx2tx2.dts index f32a44b810f99b..ad7870a8ba1321 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9002-rx2tx2.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9002-rx2tx2.dts @@ -13,11 +13,11 @@ &i2c1 { i2c-mux@75 { - i2c@1 { /* HPC1 */ + i2c@0 { /* HPC0 */ #address-cells = <1>; #size-cells = <0>; - reg = <1>; - + reg = <0>; + /* HPC0_IIC */ eeprom@50 { compatible = "at24,24c02"; reg = <0x50>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9002.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9002.dts index 46a12ae2c67ed6..2cf7cb808c7651 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9002.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9002.dts @@ -13,16 +13,15 @@ &i2c1 { i2c-mux@75 { - i2c@1 { /* HPC1 */ + i2c@0 { /* HPC0 */ #address-cells = <1>; #size-cells = <0>; - reg = <1>; - + reg = <0>; + /* HPC0_IIC */ eeprom@50 { compatible = "at24,24c02"; reg = <0x50>; }; - }; }; }; From bc4a82e5475cb4f2273201da21c6ef30f4387d71 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 23 Nov 2021 16:13:02 +0100 Subject: [PATCH 033/407] driver core: export driver_deferred_probe_trigger() Please see here: https://lkml.org/lkml/2021/8/17/802 Signed-off-by: Michael Hennerich --- drivers/base/dd.c | 4 ++-- include/linux/device/driver.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 148e81969e0462..a61db3fbd765d6 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -162,7 +162,7 @@ static bool driver_deferred_probe_enable = false; * changes in the midst of a probe, then deferred processing should be triggered * again. */ -static void driver_deferred_probe_trigger(void) +void driver_deferred_probe_trigger(void) { if (!driver_deferred_probe_enable) return; @@ -184,7 +184,7 @@ static void driver_deferred_probe_trigger(void) */ schedule_work(&deferred_probe_work); } - +EXPORT_SYMBOL_GPL(driver_deferred_probe_trigger); /** * device_block_probing() - Block/defer device's probes * diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index ee7ba5b5417e51..d769593f50a502 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -240,6 +240,7 @@ extern int driver_deferred_probe_timeout; void driver_deferred_probe_add(struct device *dev); int driver_deferred_probe_check_state(struct device *dev); void driver_init(void); +void driver_deferred_probe_trigger(void); /** * module_driver() - Helper macro for drivers that don't do anything From b61aebb5a54aaa534f72b22517e80bcc75983eff Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 23 Nov 2021 16:15:07 +0100 Subject: [PATCH 034/407] jesd204: jesd204-core: Support for dynamic dt changes This adds support for loading dt overlays including a jesd204-devices. The requirement for this to work is that the base devicetree doesn't define any jesd204-devices. Also overlay removal are currently not supported. Signed-off-by: Michael Hennerich --- drivers/jesd204/jesd204-core.c | 88 +++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/drivers/jesd204/jesd204-core.c b/drivers/jesd204/jesd204-core.c index b1ecd792a81f6d..7842ee7ef8886b 100644 --- a/drivers/jesd204/jesd204-core.c +++ b/drivers/jesd204/jesd204-core.c @@ -30,6 +30,7 @@ static unsigned int jesd204_device_count; static unsigned int jesd204_topologies_count; static unsigned int jesd204_con_id_counter; +static bool jesd204_dyn_dt_change; static void jesd204_dev_unregister(struct jesd204_dev *jdev); @@ -934,11 +935,14 @@ static struct jesd204_dev *jesd204_dev_register(struct device *dev, } jdev = jesd204_dev_find_by_of_node(dev->of_node); - if (!jdev) { + if (!jdev && !jesd204_dyn_dt_change) { dev_err(dev, "Device has no configuration node\n"); return ERR_PTR(-ENODEV); } + if (!jdev) + return ERR_PTR(-EPROBE_DEFER); + ret = jesd204_dev_init_links_data(dev, jdev, init); if (ret) return ERR_PTR(ret); @@ -1068,6 +1072,83 @@ struct jesd204_dev *devm_jesd204_dev_register(struct device *dev, } EXPORT_SYMBOL_GPL(devm_jesd204_dev_register); + +static int jesd204_overlay_has_device(struct device_node *node) +{ + struct device_node *dn; + int i = 0; + + for (dn = of_find_node_with_property(node, "jesd204-device"); dn; + dn = of_find_node_with_property(dn, "jesd204-device")) + i++; + + return i; +} + +/** + * of_jesd204_notify - reconfig notifier for dynamic DT changes + * @nb: notifier block + * @action: notifier action + * @arg: reconfig data + * + */ +static int of_jesd204_notify(struct notifier_block *nb, + unsigned long action, void *arg) +{ + struct of_overlay_notify_data *nd = arg; + int devs, ret = 0; + + switch (action) { + case OF_OVERLAY_PRE_APPLY: + pr_debug("%s OF_OVERLAY_PRE_APPLY\n", __func__); + + devs = jesd204_overlay_has_device(nd->overlay); + if (!devs) + return NOTIFY_OK; + + if (jesd204_device_count || jesd204_topologies_count) { + pr_err("%s Failed: base devicetree must not have any jesd204-devices", + __func__); + return notifier_from_errno(-EOPNOTSUPP); + } + + jesd204_dyn_dt_change = true; + + return NOTIFY_OK; + case OF_OVERLAY_POST_APPLY: + pr_debug("%s OF_OVERLAY_POST_APPLY\n", __func__); + + if (jesd204_dyn_dt_change) { + ret = jesd204_of_create_devices(); + + pr_info("found %u devices and %u topologies\n", + jesd204_device_count, jesd204_topologies_count); + + jesd204_dyn_dt_change = false; + if (!ret) + driver_deferred_probe_trigger(); + + return notifier_from_errno(ret); + } + + return NOTIFY_OK; + case OF_OVERLAY_PRE_REMOVE: + pr_debug("%s OF_OVERLAY_PRE_REMOVE\n", __func__); + + if (jesd204_device_count) + return notifier_from_errno(-EOPNOTSUPP); + + return NOTIFY_OK; + default: + pr_debug("%s Not implemented action: %ld\n", __func__, action); + return NOTIFY_OK; + } +} + +static struct notifier_block jesd204_of_nb = { + .notifier_call = of_jesd204_notify, +}; + static int __init jesd204_init(void) { int ret; @@ -1084,6 +1165,10 @@ static int __init jesd204_init(void) if (ret < 0) goto error_unreg_devices; + ret = of_overlay_notifier_register(&jesd204_of_nb); + if (ret) + return ret; + pr_info("found %u devices and %u topologies\n", jesd204_device_count, jesd204_topologies_count); @@ -1099,6 +1184,7 @@ static void __exit jesd204_exit(void) { jesd204_of_unregister_devices(); bus_unregister(&jesd204_bus_type); + of_overlay_notifier_unregister(&jesd204_of_nb); } subsys_initcall(jesd204_init); From aab747b6bd3b4931203be4350fe17246152b8ee5 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 23 Nov 2021 16:15:44 +0100 Subject: [PATCH 035/407] dts: zynqmp-zcu102-rev10-ad9081-m8-l4-overlay.dts: Dt overlay example Signed-off-by: Michael Hennerich --- ...nqmp-zcu102-rev10-ad9081-m8-l4-overlay.dts | 536 ++++++++++++++++++ 1 file changed, 536 insertions(+) create mode 100644 arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-overlay.dts diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-overlay.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-overlay.dts new file mode 100644 index 00000000000000..2429f14c75cfc8 --- /dev/null +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-overlay.dts @@ -0,0 +1,536 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD9081-FMC-EBZ + * https://wiki.analog.com/resources/eval/user-guides/quadmxfe/quick-start + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2021 Analog Devices Inc. + */ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +/ { + + fragment@0 { + + target = <&fpga_full>; + #address-cells = <2>; + #size-cells = <2>; + + __overlay__ { + #address-cells = <2>; + #size-cells = <2>; + firmware-name = "system_top.bit"; + }; + }; + + fragment@1 { + target = <&spi1>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + hmc7044: hmc7044@0 { + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + compatible = "adi,hmc7044"; + reg = <0>; + spi-max-frequency = <1000000>; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-sysref-provider; + adi,hmc-two-level-tree-sync-en; + + adi,jesd204-max-sysref-frequency-hz = <2000000>; /* 2 MHz */ + + /* + * There are different versions of the AD9081-FMCA-EBZ & AD9082-FMCA-EBZ + * VCXO = 122.880 MHz, XO = 122.880MHz (AD9081-FMC-EBZ & AD9082-FMC-EBZ) + * VCXO = 100.000 MHz, XO = 100.000MHz (AD9081-FMC-EBZ-A2 & AD9082-FMC-EBZ-A2) + * To determine which board is which, read the freqency printed on the VCXO + * or use the fru-dump utility: + * #fru-dump -b /sys/bus/i2c/devices/15-0050/eeprom + */ + + //adi,pll1-clkin-frequencies = <122880000 30720000 0 0>; + //adi,vcxo-frequency = <122880000>; + + adi,pll1-clkin-frequencies = <100000000 10000000 0 0>; + adi,vcxo-frequency = <100000000>; + + adi,pll1-loop-bandwidth-hz = <200>; + + adi,pll2-output-frequency = <2880000000>; + + adi,sysref-timer-divider = <1024>; + adi,pulse-generator-mode = <0>; + + adi,clkin0-buffer-mode = <0x07>; + adi,clkin1-buffer-mode = <0x07>; + adi,oscin-buffer-mode = <0x15>; + + adi,gpi-controls = <0x00 0x00 0x00 0x00>; + adi,gpo-controls = <0x37 0x33 0x00 0x00>; + + clock-output-names = + "hmc7044_out0", "hmc7044_out1", "hmc7044_out2", + "hmc7044_out3", "hmc7044_out4", "hmc7044_out5", + "hmc7044_out6", "hmc7044_out7", "hmc7044_out8", + "hmc7044_out9", "hmc7044_out10", "hmc7044_out11", + "hmc7044_out12", "hmc7044_out13"; + + hmc7044_c0: channel@0 { + reg = <0>; + adi,extended-name = "CORE_CLK_RX"; + adi,divider = <20>; + adi,driver-mode = ; + + }; + hmc7044_c2: channel@2 { + reg = <2>; + adi,extended-name = "DEV_REFCLK"; + adi,divider = <10>; + adi,driver-mode = ; + }; + hmc7044_c3: channel@3 { + reg = <3>; + adi,extended-name = "DEV_SYSREF"; + adi,divider = <1536>; + adi,driver-mode = ; + adi,jesd204-sysref-chan; + }; + + hmc7044_c6: channel@6 { + reg = <6>; + adi,extended-name = "CORE_CLK_TX"; + adi,divider = <20>; + adi,driver-mode = ; + }; + + hmc7044_c8: channel@8 { + reg = <8>; + adi,extended-name = "FPGA_REFCLK1"; + adi,divider = <10>; + adi,driver-mode = ; + }; + hmc7044_c10: channel@10 { + reg = <10>; + adi,extended-name = "CORE_CLK_RX_ALT"; + adi,divider = <20>; + adi,driver-mode = ; + }; + + hmc7044_c12: channel@12 { + reg = <12>; + adi,extended-name = "FPGA_REFCLK2"; + adi,divider = <10>; + adi,driver-mode = ; + }; + hmc7044_c13: channel@13 { + reg = <13>; + adi,extended-name = "FPGA_SYSREF"; + adi,divider = <1536>; + adi,driver-mode = ; + adi,jesd204-sysref-chan; + }; + }; + + }; + }; + + fragment@2 { + target = <&spi0>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + trx0_ad9081: ad9081@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,ad9081"; + reg = <0>; + spi-max-frequency = <5000000>; + + /* Clocks */ + clocks = <&hmc7044 2>; + clock-names = "dev_clk"; + + clock-output-names = "rx_sampl_clk", "tx_sampl_clk"; + #clock-cells = <1>; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <0>; /* This is the TOP device */ + jesd204-link-ids = ; + //jesd204-ignore-errors; + + jesd204-inputs = + <&axi_ad9081_core_rx 0 FRAMER_LINK0_RX>, + <&axi_ad9081_core_tx 0 DEFRAMER_LINK0_TX>; + + reset-gpios = <&gpio 133 0>; + sysref-req-gpios = <&gpio 121 0>; + rx2-enable-gpios = <&gpio 135 0>; + rx1-enable-gpios = <&gpio 134 0>; + tx2-enable-gpios = <&gpio 137 0>; + tx1-enable-gpios = <&gpio 136 0>; + + adi,tx-dacs { + #size-cells = <0>; + #address-cells = <1>; + + adi,dac-frequency-hz = /bits/ 64 <6912000000>; + + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + + adi,interpolation = <8>; + + ad9081_dac0: dac@0 { + reg = <0>; + adi,crossbar-select = <&ad9081_tx_fddc_chan0>; + adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 100 MHz */ + }; + ad9081_dac1: dac@1 { + reg = <1>; + adi,crossbar-select = <&ad9081_tx_fddc_chan1>; + adi,nco-frequency-shift-hz = /bits/ 64 <1100000000>; /* 200 MHz */ + }; + ad9081_dac2: dac@2 { + reg = <2>; + adi,crossbar-select = <&ad9081_tx_fddc_chan2>; /* All 4 channels @ dac2 */ + adi,nco-frequency-shift-hz = /bits/ 64 <1200000000>; /* 300 MHz */ + }; + ad9081_dac3: dac@3 { + reg = <3>; + adi,crossbar-select = <&ad9081_tx_fddc_chan3>; /* All 4 channels @ dac2 */ + adi,nco-frequency-shift-hz = /bits/ 64 <1300000000>; /* 400 MHz */ + }; + }; + + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = <6>; + + ad9081_tx_fddc_chan0: channel@0 { + reg = <0>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_tx_fddc_chan1: channel@1 { + reg = <1>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_tx_fddc_chan2: channel@2 { + reg = <2>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_tx_fddc_chan3: channel@3 { + reg = <3>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + }; + + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + + ad9081_tx_jesd_l0: link@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + adi,logical-lane-mapping = /bits/ 8 <0 2 7 7 1 7 7 3>; + + adi,link-mode = <9>; /* JESD Quick Configuration Mode */ + adi,subclass = <1>; /* JESD SUBCLASS 0,1,2 */ + adi,version = <1>; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + + adi,converters-per-device = <8>; /* JESD M */ + adi,octets-per-frame = <4>; /* JESD F */ + + adi,frames-per-multiframe = <32>; /* JESD K */ + adi,converter-resolution = <16>; /* JESD N */ + adi,bits-per-sample = <16>; /* JESD NP' */ + adi,control-bits-per-sample = <0>; /* JESD CS */ + adi,lanes-per-device = <4>; /* JESD L */ + adi,samples-per-converter-per-frame = <1>; /* JESD S */ + adi,high-density = <0>; /* JESD HD */ + }; + }; + }; + + adi,rx-adcs { + #size-cells = <0>; + #address-cells = <1>; + + adi,adc-frequency-hz = /bits/ 64 <3456000000>; + + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + + + ad9081_adc0: adc@0 { + reg = <0>; + adi,decimation = <3>; + adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ + }; + ad9081_adc1: adc@1 { + reg = <1>; + adi,decimation = <3>; + adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ + }; + ad9081_adc2: adc@2 { + reg = <2>; + adi,decimation = <3>; + adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan4>, <&ad9081_rx_fddc_chan6>; /* Static for now */ + }; + ad9081_adc3: adc@3 { + reg = <3>; + adi,decimation = <3>; + adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan5>, <&ad9081_rx_fddc_chan7>; /* Static for now */ + }; + }; + + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + + + ad9081_rx_fddc_chan0: channel@0 { + reg = <0>; + adi,decimation = <8>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_rx_fddc_chan1: channel@1 { + reg = <1>; + adi,decimation = <8>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_rx_fddc_chan4: channel@4 { + reg = <4>; + adi,decimation = <8>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_rx_fddc_chan5: channel@5 { + reg = <5>; + adi,decimation = <8>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + }; + + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + + ad9081_rx_jesd_l0: link@0 { + reg = <0>; + adi,converter-select = + <&ad9081_rx_fddc_chan0 FDDC_I>, <&ad9081_rx_fddc_chan0 FDDC_Q>, + <&ad9081_rx_fddc_chan1 FDDC_I>, <&ad9081_rx_fddc_chan1 FDDC_Q>, + <&ad9081_rx_fddc_chan4 FDDC_I>, <&ad9081_rx_fddc_chan4 FDDC_Q>, + <&ad9081_rx_fddc_chan5 FDDC_I>, <&ad9081_rx_fddc_chan5 FDDC_Q>; + + adi,logical-lane-mapping = /bits/ 8 <2 0 7 7 7 7 3 1>; + + adi,link-mode = <10>; /* JESD Quick Configuration Mode */ + adi,subclass = <1>; /* JESD SUBCLASS 0,1,2 */ + adi,version = <1>; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + + adi,converters-per-device = <8>; /* JESD M */ + adi,octets-per-frame = <4>; /* JESD F */ + + adi,frames-per-multiframe = <32>; /* JESD K */ + adi,converter-resolution = <16>; /* JESD N */ + adi,bits-per-sample = <16>; /* JESD NP' */ + adi,control-bits-per-sample = <0>; /* JESD CS */ + adi,lanes-per-device = <4>; /* JESD L */ + adi,samples-per-converter-per-frame = <1>; /* JESD S */ + adi,high-density = <0>; /* JESD HD */ + }; + }; + }; + }; + }; + }; + + fragment@3 { + target = <&amba>; + __overlay__ { + interrupt-parent = <&gic>; + status = "okay"; + #address-cells = <2>; + #size-cells = <2>; + + axi_sysid_0: axi-sysid-0@85000000 { + status = "okay"; + compatible = "adi,axi-sysid-1.00.a"; + reg = <0x0 0x85000000 0x0 0x10000>; + }; + + rx_dma: dma@9c420000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x0 0x9c420000 0x0 0x10000>; + #dma-cells = <1>; + #clock-cells = <0>; + interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zynqmp_clk 73>; + }; + + tx_dma: dma@9c430000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x0 0x9c430000 0x0 0x10000>; + #dma-cells = <1>; + #clock-cells = <0>; + interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zynqmp_clk 73>; + }; + + axi_ad9081_adxcvr_rx: axi-adxcvr-rx@84a60000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,axi-adxcvr-1.0"; + reg = <0x0 0x84a60000 0x0 0x1000>; + + clocks = <&hmc7044 12>; + clock-names = "conv"; + + #clock-cells = <1>; + clock-output-names = "rx_gt_clk", "rx_out_clk"; + + adi,sys-clk-select = ; + adi,out-clk-select = ; + adi,use-lpm-enable; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&hmc7044 0 FRAMER_LINK0_RX>; + }; + + axi_ad9081_adxcvr_tx: axi-adxcvr-tx@84b60000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,axi-adxcvr-1.0"; + reg = <0x0 0x84b60000 0x0 0x1000>; + + clocks = <&hmc7044 12>; + clock-names = "conv"; + + #clock-cells = <1>; + clock-output-names = "tx_gt_clk", "tx_out_clk"; + + adi,sys-clk-select = ; + adi,out-clk-select = ; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&hmc7044 0 DEFRAMER_LINK0_TX>; + }; + + + + axi_ad9081_rx_jesd: axi-jesd204-rx@84a90000 { + compatible = "adi,axi-jesd204-rx-1.0"; + reg = <0x0 0x84a90000 0x0 0x1000>; + + interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>; + + clocks = <&zynqmp_clk 71>, <&hmc7044 10>, <&axi_ad9081_adxcvr_rx 0>; + clock-names = "s_axi_aclk", "device_clk", "lane_clk"; + + #clock-cells = <0>; + clock-output-names = "jesd_rx_lane_clk"; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9081_adxcvr_rx 0 FRAMER_LINK0_RX>; + }; + + axi_ad9081_tx_jesd: axi-jesd204-tx@84b90000 { + compatible = "adi,axi-jesd204-tx-1.0"; + reg = <0x0 0x84b90000 0x0 0x1000>; + + interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>; + + clocks = <&zynqmp_clk 71>, <&hmc7044 6>, <&axi_ad9081_adxcvr_tx 0>; + clock-names = "s_axi_aclk", "device_clk", "lane_clk"; + + #clock-cells = <0>; + clock-output-names = "jesd_tx_lane_clk"; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9081_adxcvr_tx 0 DEFRAMER_LINK0_TX>; + }; + + axi_ad9081_core_rx: axi-ad9081-rx-hpc@84a10000 { + compatible = "adi,axi-ad9081-rx-1.0"; + reg = <0x0 0x84a10000 0x0 0x8000>; + dmas = <&rx_dma 0>; + dma-names = "rx"; + spibus-connected = <&trx0_ad9081>; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9081_rx_jesd 0 FRAMER_LINK0_RX>; + }; + + axi_ad9081_core_tx: axi-ad9081-tx-hpc@84b10000 { + compatible = "adi,axi-ad9081-tx-1.0"; + reg = <0x0 0x84b10000 0x0 0x4000>; + dmas = <&tx_dma 0>; + dma-names = "tx"; + clocks = <&trx0_ad9081 1>; + clock-names = "sampl_clk"; + spibus-connected = <&trx0_ad9081>; + //adi,axi-pl-fifo-enable; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9081_tx_jesd 0 DEFRAMER_LINK0_TX>; + }; + }; + }; + +}; + From 4d4bc49aa7be4549b78b0b6faeb992ee9122bbe5 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 2 Dec 2021 08:38:51 +0100 Subject: [PATCH 036/407] iio: adc: ad9081: Fix adi,jesd-links node parsing With dynamic dt, we must not assume sequential ordering of nodes. Always use reg property. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index f6c33dfaf7b5f5..702ee7f20cd5e9 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -3572,13 +3572,15 @@ static int ad9081_parse_dt_tx(struct ad9081_phy *phy, struct device_node *np) phy->jrx_link_watchdog_en = of_property_read_bool(of_channels, "adi,jrx-link-watchdog-enable"); - - i = 0; - for_each_child_of_node(of_channels, of_chan) { - ad9081_parse_jesd_link_dt(phy, of_chan, &phy->jrx_link_tx[i++], - false); - if (i >= ARRAY_SIZE(phy->jrx_link_tx)) { + ret = of_property_read_u32(of_chan, "reg", ®); + if (!ret && (reg < ARRAY_SIZE(phy->jrx_link_tx))) { + ad9081_parse_jesd_link_dt(phy, of_chan, + &phy->jrx_link_tx[reg], false); + } else { + dev_err(&phy->spi->dev, + "Missing or invalid reg property in tx jesd-links node (%d)\n", + reg); of_node_put(of_chan); break; } @@ -3587,7 +3589,7 @@ static int ad9081_parse_dt_tx(struct ad9081_phy *phy, struct device_node *np) of_node_put(of_channels); of_node_put(of_trx_path); - return 0; + return ret; } static int ad9081_parse_dt_rx(struct ad9081_phy *phy, struct device_node *np) @@ -3595,7 +3597,7 @@ static int ad9081_parse_dt_rx(struct ad9081_phy *phy, struct device_node *np) struct device_node *of_channels, *of_chan; struct device_node *of_trx_path; u32 reg, tmp, nz; - int i = 0, ret; + int ret; /* The 4 ADC Main Datapaths */ @@ -3680,9 +3682,14 @@ static int ad9081_parse_dt_rx(struct ad9081_phy *phy, struct device_node *np) } for_each_child_of_node(of_channels, of_chan) { - ad9081_parse_jesd_link_dt(phy, of_chan, &phy->jtx_link_rx[i++], - true); - if (i >= ARRAY_SIZE(phy->jtx_link_rx)) { + ret = of_property_read_u32(of_chan, "reg", ®); + if (!ret && (reg < ARRAY_SIZE(phy->jtx_link_rx))) { + ad9081_parse_jesd_link_dt(phy, of_chan, + &phy->jtx_link_rx[reg], true); + } else { + dev_err(&phy->spi->dev, + "Missing or invalid reg property in rx jesd-links node (%d)\n", + reg); of_node_put(of_chan); break; } @@ -3691,7 +3698,7 @@ static int ad9081_parse_dt_rx(struct ad9081_phy *phy, struct device_node *np) of_node_put(of_channels); of_node_put(of_trx_path); - return 0; + return ret; } static int ad9081_parse_dt(struct ad9081_phy *phy, struct device *dev) From d0e86fc2ac3c9045c1b31f48ad58661cbf029d44 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 2 Dec 2021 10:30:42 +0100 Subject: [PATCH 037/407] iio: adc: ad9081: Allow TX or RX only operation This adds support for either RX or TX only operation. In the devicetree both nodes below with the ADC/DAC frequency are still required. adi,tx-dacs { adi,dac-frequency-hz = /bits/ 64 <12000000000>; ... } adi,rx-adcs { adi,adc-frequency-hz = /bits/ 64 <4000000000>; ... } But deleting subnodes will effectively disable the corresponding path. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 292 ++++++++++++++++++++++++++------------- 1 file changed, 195 insertions(+), 97 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 702ee7f20cd5e9..7f2439eba01c4f 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -177,6 +177,8 @@ struct ad9081_phy { bool config_sync_0a_cmos_en; bool jrx_link_watchdog_en; bool is_initialized; + bool tx_disable; + bool rx_disable; struct device_settings_cache device_cache; @@ -1736,71 +1738,80 @@ static void ad9081_convert_link_converter_select( jesd_conv_sel->virtual_converterf_index = *vals++; } -static int ad9081_setup(struct spi_device *spi) +static int ad9081_setup_tx(struct spi_device *spi) { struct axiadc_converter *conv = spi_get_drvdata(spi); struct ad9081_phy *phy = conv->phy; - struct clock_scale devclk_clkscale; - u64 dev_frequency_hz, sample_rate, status64; - adi_cms_jesd_param_t jesd_param[2]; - adi_ad9081_jtx_conv_sel_t jesd_conv_sel[2]; - u8 txfe_pll_stat, dcm; + u64 sample_rate, status64; int ret, i; - of_clk_get_scale(spi->dev.of_node, "dev_clk", &devclk_clkscale); - dev_frequency_hz = clk_get_rate_scaled(phy->dev_clk, &devclk_clkscale); + if (phy->tx_disable) + return 0; - ret = adi_ad9081_hal_bf_set(&phy->ad9081, REG_SYNC_LMFC_DELAY_ADDR, - BF_SYNC_LMFC_DELAY_SET_INFO, - BF_SYNC_LMFC_DELAY_SET(phy->lmfc_delay)); - if (ret != 0) - return ret; + /* start txfe tx */ + ret = adi_ad9081_device_startup_tx( + &phy->ad9081, phy->tx_main_interp, phy->tx_chan_interp, + phy->tx_chan_interp == 1 ? phy->tx_dac_chan_xbar_1x_non1x : phy->tx_dac_chan_xbar, + phy->tx_main_shift, phy->tx_chan_shift, + &phy->jrx_link_tx[0].jesd_param); - /* DC couple SYSREF */ - ret = adi_ad9081_jesd_sysref_input_mode_set(&phy->ad9081, 1, 1, - phy->sysref_coupling_ac_en ? COUPLING_AC : COUPLING_DC); if (ret != 0) return ret; - ret = adi_ad9081_hal_bf_set(&phy->ad9081, REG_SYNC_DEBUG0_ADDR, - BF_AVRG_FLOW_EN_INFO, 1); + /* setup txfe dac channel gain */ + ret = adi_ad9081_dac_duc_nco_gains_set(&phy->ad9081, + phy->dac_cache.chan_gain); if (ret != 0) return ret; - ret = adi_ad9081_hal_bf_set(&phy->ad9081, REG_SYSREF_AVERAGE_ADDR, - BF_SYSREF_AVERAGE_INFO, - BF_SYSREF_AVERAGE(phy->sysref_average_cnt_exp)); - if (ret != 0) - return ret; + adi_ad9081_jesd_rx_lmfc_delay_set(&phy->ad9081, AD9081_LINK_0, + phy->jrx_link_tx[0].jrx_tpl_phase_adjust); - ret = adi_ad9081_device_clk_config_set( - &phy->ad9081, phy->dac_frequency_hz, phy->adc_frequency_hz, - dev_frequency_hz); - if (ret != 0) - return ret; + adi_ad9081_jesd_rx_lmfc_delay_set(&phy->ad9081, AD9081_LINK_1, + phy->jrx_link_tx[1].jrx_tpl_phase_adjust); - if (dev_frequency_hz != phy->dac_frequency_hz) { - ret = adi_ad9081_device_clk_pll_lock_status_get(&phy->ad9081, - &txfe_pll_stat); + if (phy->jrx_link_tx[0].jesd_param.jesd_jesdv == 2 && + phy->ad9081.dev_info.dev_rev < 3) { + ret = adi_ad9081_hal_bf_set(&phy->ad9081, REG_JRX_TPL_1_ADDR, + BF_JRX_TPL_BUF_PROTECT_EN_INFO, + 0); if (ret != 0) return ret; + } - if (txfe_pll_stat != 3) { - dev_err(&spi->dev, "CLK PLL Failed to Lock (Status: %d)", - txfe_pll_stat); - return -EFAULT; + adi_ad9081_dac_irqs_status_get(&phy->ad9081, &status64); + dev_dbg(&spi->dev, "DAC IRQ status 0x%llX\n", status64); + + sample_rate = DIV_ROUND_CLOSEST_ULL(phy->dac_frequency_hz, + phy->tx_main_interp * phy->tx_chan_interp); + clk_set_rate(phy->clks[TX_SAMPL_CLK], sample_rate); + + for (i = 0; i < ARRAY_SIZE(phy->tx_dac_fsc); i++) { + if (phy->tx_dac_fsc[i]) { + ret = adi_ad9081_dac_fsc_set(&phy->ad9081, BIT(i), phy->tx_dac_fsc[i], 1); + if (ret != 0) + return ret; } } - /* start txfe tx */ - ret = adi_ad9081_device_startup_tx( - &phy->ad9081, phy->tx_main_interp, phy->tx_chan_interp, - phy->tx_chan_interp == 1 ? phy->tx_dac_chan_xbar_1x_non1x : phy->tx_dac_chan_xbar, - phy->tx_main_shift, phy->tx_chan_shift, - &phy->jrx_link_tx[0].jesd_param); + return 0; +} - if (ret != 0) - return ret; +static int ad9081_setup_rx(struct spi_device *spi) +{ + struct axiadc_converter *conv = spi_get_drvdata(spi); + struct ad9081_phy *phy = conv->phy; + u64 sample_rate; + adi_cms_jesd_param_t jesd_param[2]; + adi_ad9081_jtx_conv_sel_t jesd_conv_sel[2]; + u8 dcm; + int ret, i; + + if (phy->rx_disable) { + adi_ad9081_adc_clk_enable_set(&phy->ad9081, 0); + + return 0; + } for (i = 0; i < ARRAY_SIZE(phy->adc_main_decimation); i++) { ret = ad9081_main_decimation_to_val( @@ -1874,18 +1885,6 @@ static int ad9081_setup(struct spi_device *spi) return ret; } - /* setup txfe dac channel gain */ - ret = adi_ad9081_dac_duc_nco_gains_set(&phy->ad9081, - phy->dac_cache.chan_gain); - if (ret != 0) - return ret; - - adi_ad9081_jesd_rx_lmfc_delay_set(&phy->ad9081, AD9081_LINK_0, - phy->jrx_link_tx[0].jrx_tpl_phase_adjust); - - adi_ad9081_jesd_rx_lmfc_delay_set(&phy->ad9081, AD9081_LINK_1, - phy->jrx_link_tx[1].jrx_tpl_phase_adjust); - /* setup txfe jtx converter mapping */ for (i = 0; i < ARRAY_SIZE(phy->jtx_link_rx[0].link_converter_select); i++) { @@ -1923,8 +1922,71 @@ static int ad9081_setup(struct spi_device *spi) phy->adc_dcm[1] = dcm; } - if (phy->config_sync_01_swapped && - phy->jrx_link_tx[0].jesd_param.jesd_jesdv != 2) { + sample_rate = DIV_ROUND_CLOSEST_ULL(phy->adc_frequency_hz, phy->adc_dcm[0]); + clk_set_rate(phy->clks[RX_SAMPL_CLK], sample_rate); + + if (ad9081_link_is_dual(phy->jtx_link_rx)) { + sample_rate = DIV_ROUND_CLOSEST_ULL(phy->adc_frequency_hz, phy->adc_dcm[1]); + clk_set_rate(phy->clks[RX_SAMPL_CLK_LINK2], sample_rate); + } + + return 0; +} + +static int ad9081_setup(struct spi_device *spi) +{ + struct axiadc_converter *conv = spi_get_drvdata(spi); + struct ad9081_phy *phy = conv->phy; + struct clock_scale devclk_clkscale; + u64 dev_frequency_hz; + u8 txfe_pll_stat; + int ret; + + of_clk_get_scale(spi->dev.of_node, "dev_clk", &devclk_clkscale); + dev_frequency_hz = clk_get_rate_scaled(phy->dev_clk, &devclk_clkscale); + + ret = adi_ad9081_hal_bf_set(&phy->ad9081, REG_SYNC_LMFC_DELAY_ADDR, + BF_SYNC_LMFC_DELAY_SET_INFO, + BF_SYNC_LMFC_DELAY_SET(phy->lmfc_delay)); + if (ret != 0) + return ret; + + /* DC couple SYSREF */ + ret = adi_ad9081_jesd_sysref_input_mode_set(&phy->ad9081, 1, 1, + phy->sysref_coupling_ac_en ? COUPLING_AC : COUPLING_DC); + if (ret != 0) + return ret; + + ret = adi_ad9081_hal_bf_set(&phy->ad9081, REG_SYNC_DEBUG0_ADDR, + BF_AVRG_FLOW_EN_INFO, 1); + if (ret != 0) + return ret; + + ret = adi_ad9081_hal_bf_set(&phy->ad9081, REG_SYSREF_AVERAGE_ADDR, + BF_SYSREF_AVERAGE_INFO, + BF_SYSREF_AVERAGE(phy->sysref_average_cnt_exp)); + if (ret != 0) + return ret; + + ret = adi_ad9081_device_clk_config_set(&phy->ad9081, + phy->dac_frequency_hz, phy->adc_frequency_hz, dev_frequency_hz); + if (ret != 0) + return ret; + + if (dev_frequency_hz != phy->dac_frequency_hz) { + ret = adi_ad9081_device_clk_pll_lock_status_get(&phy->ad9081, + &txfe_pll_stat); + if (ret != 0) + return ret; + + if (txfe_pll_stat != 3) { + dev_err(&spi->dev, "CLK PLL Failed to Lock (Status: %d)", + txfe_pll_stat); + return -EFAULT; + } + } + + if (phy->config_sync_01_swapped) { adi_ad9081_jesd_rx_syncb_driver_powerdown_set(&phy->ad9081, 0); adi_ad9081_hal_reg_set(&phy->ad9081, REG_GENERAL_JRX_CTRL_ADDR, 0x80); @@ -1947,37 +2009,14 @@ static int ad9081_setup(struct spi_device *spi) adi_ad9081_hal_reg_set(&phy->ad9081, REG_SYNCA_CTRL_ADDR, 0x0); } - if (phy->jrx_link_tx[0].jesd_param.jesd_jesdv == 2 && - phy->ad9081.dev_info.dev_rev < 3) { - ret = adi_ad9081_hal_bf_set(&phy->ad9081, REG_JRX_TPL_1_ADDR, - BF_JRX_TPL_BUF_PROTECT_EN_INFO, - 0); - if (ret != 0) - return ret; - } - - adi_ad9081_dac_irqs_status_get(&phy->ad9081, &status64); - dev_dbg(&spi->dev, "DAC IRQ status 0x%llX\n", status64); - - sample_rate = DIV_ROUND_CLOSEST_ULL(phy->adc_frequency_hz, phy->adc_dcm[0]); - clk_set_rate(phy->clks[RX_SAMPL_CLK], sample_rate); - - if (ad9081_link_is_dual(phy->jtx_link_rx)) { - sample_rate = DIV_ROUND_CLOSEST_ULL(phy->adc_frequency_hz, phy->adc_dcm[1]); - clk_set_rate(phy->clks[RX_SAMPL_CLK_LINK2], sample_rate); - } - sample_rate = DIV_ROUND_CLOSEST_ULL(phy->dac_frequency_hz, - phy->tx_main_interp * phy->tx_chan_interp); - clk_set_rate(phy->clks[TX_SAMPL_CLK], sample_rate); + ret = ad9081_setup_tx(spi); + if (ret) + return ret; - for (i = 0; i < ARRAY_SIZE(phy->tx_dac_fsc); i++) { - if (phy->tx_dac_fsc[i]) { - ret = adi_ad9081_dac_fsc_set(&phy->ad9081, BIT(i), phy->tx_dac_fsc[i], 1); - if (ret != 0) - return ret; - } - } + ret = ad9081_setup_rx(spi); + if (ret) + return ret; return 0; } @@ -2129,6 +2168,11 @@ static ssize_t ad9081_phy_store(struct device *dev, break; } + if (phy->tx_disable || phy->rx_disable) { + ret = -ENODEV; + break; + } + ret = kstrtoul(buf, 0, &res); /* setup mxfe loopback mode */ @@ -2164,6 +2208,11 @@ static ssize_t ad9081_phy_store(struct device *dev, phy->device_cache.loopback_mode = res; break; case AD9081_ADC_CLK_PWDN: + if (phy->rx_disable) { + ret = -ENODEV; + break; + } + ret = strtobool(buf, &bres); if (ret < 0) { ret = -EINVAL; @@ -2191,6 +2240,11 @@ static ssize_t ad9081_phy_store(struct device *dev, break; } + if (phy->tx_disable) { + ret = -ENODEV; + break; + } + ret = kstrtoul(buf, 0, &res); if (ret) { ret = -EINVAL; @@ -2203,6 +2257,12 @@ static ssize_t ad9081_phy_store(struct device *dev, ret = -ENOTSUPP; break; } + + if (phy->tx_disable) { + ret = -ENODEV; + break; + } + ret = kstrtoll(buf, 10, &lval); if (ret) { ret = -EINVAL; @@ -2233,6 +2293,11 @@ static ssize_t ad9081_phy_store(struct device *dev, break; } + if (phy->tx_disable) { + ret = -ENODEV; + break; + } + ret = sysfs_match_string(ffh_modes, buf); if (ret < 0) { ret = -EINVAL; @@ -2305,18 +2370,38 @@ static ssize_t ad9081_phy_show(struct device *dev, mutex_lock(&indio_dev->mlock); switch ((u32)this_attr->address & 0xFF) { case AD9081_LOOPBACK_MODE: + if (phy->tx_disable || phy->rx_disable) { + ret = -ENODEV; + break; + } ret = sprintf(buf, "%u\n", phy->device_cache.loopback_mode); break; case AD9081_ADC_CLK_PWDN: + if (phy->rx_disable) { + ret = -ENODEV; + break; + } ret = sprintf(buf, "%u\n", phy->device_cache.adc_clk_pwdn); break; case AD9081_DAC_FFH_INDEX_SET: + if (phy->tx_disable) { + ret = -ENODEV; + break; + } ret = sprintf(buf, "%u\n", phy->ffh_hopf_index); break; case AD9081_DAC_FFH_FREQ_SET: + if (phy->tx_disable) { + ret = -ENODEV; + break; + } ret = sprintf(buf, "%lld\n", phy->ffh_hopf_vals[phy->ffh_hopf_index]); break; case AD9081_DAC_FFH_MODE_SET: + if (phy->tx_disable) { + ret = -ENODEV; + break; + } ret = sprintf(buf, "%s\n", ffh_modes[phy->ffh_hopf_mode]); break; case AD9081_MCS: @@ -3747,13 +3832,19 @@ static int ad9081_parse_dt(struct ad9081_phy *phy, struct device *dev) &phy->direct_lb_map); ret = ad9081_parse_dt_tx(phy, np); - if (ret < 0) { + if (ret == -ENODEV && phy->dac_frequency_hz) { + phy->tx_disable = true; + dev_info(&phy->spi->dev, "Disabling TX side\n"); + } else if (ret < 0) { dev_err(&phy->spi->dev, "failed to parse devicetree"); return ret; } ret = ad9081_parse_dt_rx(phy, np); - if (ret < 0) { + if (ret == -ENODEV && phy->adc_frequency_hz) { + phy->rx_disable = true; + dev_info(&phy->spi->dev, "Disabling RX side\n"); + } else if (ret < 0) { dev_err(&phy->spi->dev, "failed to parse devicetree"); return ret; } @@ -3792,6 +3883,7 @@ static int ad9081_setup_chip_info_tbl(struct ad9081_phy *phy, phy->jtx_link_rx[1].jesd_param.jesd_m; switch (m) { + case 0: case 2: case 4: case 6: @@ -3938,12 +4030,16 @@ static int ad9081_jesd204_link_init(struct jesd204_dev *jdev, switch (lnk->link_id) { case DEFRAMER_LINK0_TX: case DEFRAMER_LINK1_TX: + if (phy->tx_disable) + return -ENODEV; link = &phy->jrx_link_tx[0]; lnk->sample_rate = phy->dac_frequency_hz; lnk->sample_rate_div = phy->tx_main_interp * phy->tx_chan_interp; break; case FRAMER_LINK0_RX: case FRAMER_LINK1_RX: + if (phy->rx_disable) + return -ENODEV; link = &phy->jtx_link_rx[lnk->link_id - FRAMER_LINK0_RX]; lnk->sample_rate = phy->adc_frequency_hz; lnk->sample_rate_div = phy->adc_dcm[lnk->link_id - FRAMER_LINK0_RX]; @@ -4420,17 +4516,19 @@ static int ad9081_probe(struct spi_device *spi) return -ENODEV; } - ad9081_clk_register(phy, "-rx_sampl_clk", - __clk_get_name(phy->dev_clk), NULL, - CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED, - RX_SAMPL_CLK); + if (!phy->rx_disable) + ad9081_clk_register(phy, "-rx_sampl_clk", + __clk_get_name(phy->dev_clk), NULL, + CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED, + RX_SAMPL_CLK); - ad9081_clk_register(phy, "-tx_sampl_clk", - __clk_get_name(phy->dev_clk), NULL, - CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED, - TX_SAMPL_CLK); + if (!phy->tx_disable) + ad9081_clk_register(phy, "-tx_sampl_clk", + __clk_get_name(phy->dev_clk), NULL, + CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED, + TX_SAMPL_CLK); - if (ad9081_link_is_dual(phy->jtx_link_rx)) + if (!phy->rx_disable && ad9081_link_is_dual(phy->jtx_link_rx)) ad9081_clk_register(phy, "-rx_sampl_clk_link2", __clk_get_name(phy->dev_clk), NULL, CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED, From 1ee303b9b400f6fb27d36d1ec60a824abf0177b4 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 2 Dec 2021 13:03:53 +0100 Subject: [PATCH 038/407] jesd204: jesd204_top_device: Print info during probe Let's make this device a bit more verbose. This will help during debug and support. Signed-off-by: Michael Hennerich --- drivers/jesd204/jesd204_top_device.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/jesd204/jesd204_top_device.c b/drivers/jesd204/jesd204_top_device.c index 32808c90ae35da..11a3b5bd57ef98 100644 --- a/drivers/jesd204/jesd204_top_device.c +++ b/drivers/jesd204/jesd204_top_device.c @@ -148,6 +148,9 @@ static int jesd204_top_device_probe(struct platform_device *pdev) if (IS_ERR(jdev)) return PTR_ERR(jdev); + dev_info(&pdev->dev, "JESD204-GENERIC-TOP-DEVICE probed %d links\n", + tdev->jesd204_dev_data.max_num_links); + return jesd204_fsm_start(jdev, JESD204_LINKS_ALL); } From 576c5422315ebd3388339ff30e7e618e71cbf110 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 3 Dec 2021 15:53:45 +0100 Subject: [PATCH 039/407] dts: zynqmp-zcu102-rev10-ad9988-fmcb-m8-l4: Add AD9988 MxFE example dt This adds an example devicetree for AD9988. Signed-off-by: Michael Hennerich --- .../zynqmp-zcu102-rev10-ad9988-fmcb-m8-l4.dts | 379 ++++++++++++++++++ 1 file changed, 379 insertions(+) create mode 100644 arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9988-fmcb-m8-l4.dts diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9988-fmcb-m8-l4.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9988-fmcb-m8-l4.dts new file mode 100644 index 00000000000000..44a6abede75c9a --- /dev/null +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9988-fmcb-m8-l4.dts @@ -0,0 +1,379 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD9988-FMCB-EBZ + * https://wiki.analog.com/resources/eval/user-guides/quadmxfe/quick-start + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2021 Analog Devices Inc. + */ + +#include "zynqmp-zcu102-rev10-ad9081.dts" + +#define HMC7044_PLL2_FREQUENCY 2949120000 +#define AD9988_DAC_FREQUENCY 11796480000 +#define AD9988_ADC_FREQUENCY 3932160000 + +/* + * These numbers get you to exactly 250.000MSPS baseband rate + * with the expense of worse phase noise performance at the output of the HMC7044 + * due to the large feedback dividers. Ideally you would use a 100MHz or 125MHz VCXO + * for this frequency + */ + +//#define HMC7044_PLL2_FREQUENCY 3000000000 +//#define AD9988_DAC_FREQUENCY 12000000000 +//#define AD9988_ADC_FREQUENCY 4000000000 + +&axi_ad9081_adxcvr_rx { + adi,sys-clk-select = ; +}; + +&spi1 { + status = "okay"; + + hmc7044: hmc7044@0 { + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + compatible = "adi,hmc7044"; + reg = <0>; + spi-max-frequency = <1000000>; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-sysref-provider; + + adi,jesd204-max-sysref-frequency-hz = <2000000>; /* 2 MHz */ + + /* + * There are different versions of the AD9081-FMCA-EBZ & AD9082-FMCA-EBZ + * VCXO = 122.880 MHz, XO = 122.880MHz (AD9081-FMC-EBZ & AD9082-FMC-EBZ) + * VCXO = 100.000 MHz, XO = 100.000MHz (AD9081-FMC-EBZ-A2 & AD9082-FMC-EBZ-A2) + * To determine which board is which, read the freqency printed on the VCXO + * or use the fru-dump utility: + * #fru-dump -b /sys/bus/i2c/devices/15-0050/eeprom + */ + + adi,pll1-clkin-frequencies = <122880000 30720000 0 0>; + adi,vcxo-frequency = <122880000>; + + adi,pll1-loop-bandwidth-hz = <200>; + + adi,pll2-output-frequency = ; + + adi,sysref-timer-divider = <1024>; + adi,pulse-generator-mode = <0>; + + adi,clkin0-buffer-mode = <0x07>; + adi,clkin1-buffer-mode = <0x07>; + adi,oscin-buffer-mode = <0x15>; + + adi,gpi-controls = <0x00 0x00 0x00 0x00>; + adi,gpo-controls = <0x37 0x33 0x00 0x00>; + + clock-output-names = + "hmc7044_out0", "hmc7044_out1", "hmc7044_out2", + "hmc7044_out3", "hmc7044_out4", "hmc7044_out5", + "hmc7044_out6", "hmc7044_out7", "hmc7044_out8", + "hmc7044_out9", "hmc7044_out10", "hmc7044_out11", + "hmc7044_out12", "hmc7044_out13"; + + hmc7044_c0: channel@0 { + reg = <0>; + adi,extended-name = "CORE_CLK_RX"; + adi,divider = <12>; + adi,driver-mode = ; + + }; + hmc7044_c2: channel@2 { + reg = <2>; + adi,extended-name = "DEV_REFCLK"; + adi,divider = <12>; + adi,driver-mode = ; + }; + hmc7044_c3: channel@3 { + reg = <3>; + adi,extended-name = "DEV_SYSREF"; + adi,divider = <1536>; + adi,driver-mode = ; + adi,jesd204-sysref-chan; + }; + + hmc7044_c6: channel@6 { + reg = <6>; + adi,extended-name = "CORE_CLK_TX"; + adi,divider = <12>; + adi,driver-mode = ; + }; + + hmc7044_c8: channel@8 { + reg = <8>; + adi,extended-name = "FPGA_REFCLK1"; + adi,divider = <6>; + adi,driver-mode = ; + }; + hmc7044_c10: channel@10 { + reg = <10>; + adi,extended-name = "CORE_CLK_RX_ALT"; + adi,divider = <12>; + adi,driver-mode = ; + }; + + hmc7044_c12: channel@12 { + reg = <12>; + adi,extended-name = "FPGA_REFCLK2"; + adi,divider = <6>; + adi,driver-mode = ; + }; + hmc7044_c13: channel@13 { + reg = <13>; + adi,extended-name = "FPGA_SYSREF"; + adi,divider = <1536>; + adi,driver-mode = ; + adi,jesd204-sysref-chan; + }; + }; +}; + +&fmc_spi { + /delete-node/ ad9081@0; + + trx0_ad9081: ad9988@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,ad9988"; + reg = <0>; + spi-max-frequency = <10000000>; + + /* Clocks */ + clocks = <&hmc7044 2>; + clock-names = "dev_clk"; + + clock-output-names = "rx_sampl_clk", "tx_sampl_clk"; + #clock-cells = <1>; + + /* GPIO */ + reset-gpios = <&gpio 133 0>; + sysref-req-gpios = <&gpio 121 0>; + rx2-enable-gpios = <&gpio 135 0>; + rx1-enable-gpios = <&gpio 134 0>; + tx2-enable-gpios = <&gpio 137 0>; + tx1-enable-gpios = <&gpio 136 0>; + + /* JESD204-FSM */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <0>; /* This is the TOP device */ + jesd204-link-ids = ; + + jesd204-inputs = + <&axi_ad9081_core_rx 0 FRAMER_LINK0_RX>, + <&axi_ad9081_core_tx 0 DEFRAMER_LINK0_TX>; + + adi,tx-dacs { + #size-cells = <0>; + #address-cells = <1>; + + adi,dac-frequency-hz = /bits/ 64 ; + + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + + adi,interpolation = <8>; + + ad9081_dac0: dac@0 { + reg = <0>; + adi,crossbar-select = <&ad9081_tx_fddc_chan0>; + adi,nco-frequency-shift-hz = /bits/ 64 <250000000>; /* 250 MHz */ + }; + ad9081_dac1: dac@1 { + reg = <1>; + adi,crossbar-select = <&ad9081_tx_fddc_chan1>; + adi,nco-frequency-shift-hz = /bits/ 64 <500000000>; /* 500 MHz */ + }; + ad9081_dac2: dac@2 { + reg = <2>; + adi,crossbar-select = <&ad9081_tx_fddc_chan2>; /* All 4 channels @ dac2 */ + adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 1000 MHz */ + }; + ad9081_dac3: dac@3 { + reg = <3>; + adi,crossbar-select = <&ad9081_tx_fddc_chan3>; /* All 4 channels @ dac2 */ + adi,nco-frequency-shift-hz = /bits/ 64 <1500000000>; /* 1500 MHz */ + }; + }; + + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = <6>; + + ad9081_tx_fddc_chan0: channel@0 { + reg = <0>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_tx_fddc_chan1: channel@1 { + reg = <1>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_tx_fddc_chan2: channel@2 { + reg = <2>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_tx_fddc_chan3: channel@3 { + reg = <3>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + }; + + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + + ad9081_tx_jesd_l0: link@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + adi,logical-lane-mapping = /bits/ 8 <0 2 7 7 1 7 7 3>; + + adi,link-mode = <9>; /* JESD Quick Configuration Mode */ + adi,subclass = <1>; /* JESD SUBCLASS 0,1,2 */ + adi,version = <1>; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + + adi,converters-per-device = <8>; /* JESD M */ + adi,octets-per-frame = <4>; /* JESD F */ + + adi,frames-per-multiframe = <32>; /* JESD K */ + adi,converter-resolution = <16>; /* JESD N */ + adi,bits-per-sample = <16>; /* JESD NP' */ + adi,control-bits-per-sample = <0>; /* JESD CS */ + adi,lanes-per-device = <4>; /* JESD L */ + adi,samples-per-converter-per-frame = <1>; /* JESD S */ + adi,high-density = <0>; /* JESD HD */ + }; + }; + }; + + adi,rx-adcs { + #size-cells = <0>; + #address-cells = <1>; + + adi,adc-frequency-hz = /bits/ 64 ; + + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + + ad9081_adc0: adc@0 { + reg = <0>; + adi,decimation = <4>; + adi,nco-frequency-shift-hz = /bits/ 64 <250000000>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ + }; + ad9081_adc1: adc@1 { + reg = <1>; + adi,decimation = <4>; + adi,nco-frequency-shift-hz = /bits/ 64 <500000000>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ + }; + ad9081_adc2: adc@2 { + reg = <2>; + adi,decimation = <4>; + adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan4>, <&ad9081_rx_fddc_chan6>; /* Static for now */ + }; + ad9081_adc3: adc@3 { + reg = <3>; + adi,decimation = <4>; + adi,nco-frequency-shift-hz = /bits/ 64 <1500000000>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan5>, <&ad9081_rx_fddc_chan7>; /* Static for now */ + }; + }; + + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + + + ad9081_rx_fddc_chan0: channel@0 { + reg = <0>; + adi,decimation = <4>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_rx_fddc_chan1: channel@1 { + reg = <1>; + adi,decimation = <4>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_rx_fddc_chan4: channel@4 { + reg = <4>; + adi,decimation = <4>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + ad9081_rx_fddc_chan5: channel@5 { + reg = <5>; + adi,decimation = <4>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + }; + + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + + ad9081_rx_jesd_l0: link@0 { + reg = <0>; + adi,converter-select = + <&ad9081_rx_fddc_chan0 FDDC_I>, <&ad9081_rx_fddc_chan0 FDDC_Q>, + <&ad9081_rx_fddc_chan1 FDDC_I>, <&ad9081_rx_fddc_chan1 FDDC_Q>, + <&ad9081_rx_fddc_chan4 FDDC_I>, <&ad9081_rx_fddc_chan4 FDDC_Q>, + <&ad9081_rx_fddc_chan5 FDDC_I>, <&ad9081_rx_fddc_chan5 FDDC_Q>; + + adi,logical-lane-mapping = /bits/ 8 <2 0 7 7 7 7 3 1>; + + adi,link-mode = <10>; /* JESD Quick Configuration Mode */ + adi,subclass = <1>; /* JESD SUBCLASS 0,1,2 */ + adi,version = <1>; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + + adi,converters-per-device = <8>; /* JESD M */ + adi,octets-per-frame = <4>; /* JESD F */ + + adi,frames-per-multiframe = <32>; /* JESD K */ + adi,converter-resolution = <16>; /* JESD N */ + adi,bits-per-sample = <16>; /* JESD NP' */ + adi,control-bits-per-sample = <0>; /* JESD CS */ + adi,lanes-per-device = <4>; /* JESD L */ + adi,samples-per-converter-per-frame = <1>; /* JESD S */ + adi,high-density = <0>; /* JESD HD */ + }; + }; + }; + }; +}; From bdc9c1e20c94691dbda86ffc62c6ce17f7d61dd9 Mon Sep 17 00:00:00 2001 From: Raluca Chis Date: Mon, 6 Dec 2021 09:52:05 +0200 Subject: [PATCH 040/407] CI: update rpi YAML file - the azure-pipelines-rpi.yml file is updated based on actual rpi branch in order to have less to modify for future updates on rpi branch Signed-off-by: Raluca Chis --- azure-pipelines-rpi.yml | 133 ++++++++++++++++++++++++++++++---------- 1 file changed, 101 insertions(+), 32 deletions(-) diff --git a/azure-pipelines-rpi.yml b/azure-pipelines-rpi.yml index e387126829f0bc..cb472767dc7608 100644 --- a/azure-pipelines-rpi.yml +++ b/azure-pipelines-rpi.yml @@ -1,44 +1,113 @@ trigger: - rpi-4.19.y - rpi-5.4.y +- rpi-5.10.y - staging-rpi/* pr: - rpi-4.19.y - rpi-5.4.y +- rpi-5.10.y -pool: - vmImage: 'ubuntu-latest' +stages: +- stage: Builds + jobs: + - job: checkpatch + condition: eq(variables['Build.Reason'], 'PullRequest') + variables: + BUILD_TYPE: checkpatch + TARGET_BRANCH: $[ variables['System.PullRequest.TargetBranch'] ] + pool: + vmImage: 'ubuntu-latest' + steps: + - checkout: self + fetchDepth: 50 + clean: true + - script: ./ci/travis/run-build.sh + displayName: 'Checkpatch Script' -jobs: + - job: BuildDockerized + strategy: + matrix: + bcm2709_arm_adi: + DEFCONFIG: adi_bcm2709_defconfig + ARCH: arm + artifactName: 'adi_bcm2709_defconfig' + bcm2711_arm_adi: + DEFCONFIG: adi_bcm2711_defconfig + ARCH: arm + artifactName: 'adi_bcm2711_defconfig' + bcmrpi_arm_adi: + DEFCONFIG: adi_bcmrpi_defconfig + ARCH: arm + artifactName: 'adi_bcmrpi_defconfig' + pool: + vmImage: 'ubuntu-latest' + steps: + - checkout: self + fetchDepth: 1 + clean: true + - script: ./ci/travis/run-build-docker.sh + displayName: "Build test for '$(DEFCONFIG)'" + - task: CopyFiles@2 + inputs: + sourceFolder: '$(Agent.BuildDirectory)/s/arch/arm/boot/dts/overlays' + contents: '$(Agent.BuildDirectory)/s/arch/arm/boot/dts/overlays/?(*.dtbo)' + targetFolder: '$(Build.ArtifactStagingDirectory)' + - task: CopyFiles@2 + inputs: + sourceFolder: '$(Agent.BuildDirectory)/s/arch/arm/boot' + contents: '$(Agent.BuildDirectory)/s/arch/arm/boot/zImage' + targetFolder: '$(Build.ArtifactStagingDirectory)' + - task: CopyFiles@2 + inputs: + sourceFolder: '$(Agent.BuildDirectory)/s/arch/arm/boot/dts' + contents: '$(Agent.BuildDirectory)/s/arch/arm/boot/dts/?(*.dtb)' + targetFolder: '$(Build.ArtifactStagingDirectory)' + - task: PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)' + artifactName: '$(artifactName)' -- job: checkpatch - condition: eq(variables['Build.Reason'], 'PullRequest') +- stage: PushArtifacts + dependsOn: Builds variables: - BUILD_TYPE: checkpatch - TARGET_BRANCH: $[ variables['System.PullRequest.TargetBranch'] ] - steps: - - checkout: self - fetchDepth: 50 - clean: true - - script: ./ci/travis/run-build.sh - displayName: 'Checkpatch Script' - -- job: BuildDockerized - strategy: - matrix: - bcm2709_arm_adi: - DEFCONFIG: adi_bcm2709_defconfig - ARCH: arm - bcm2711_arm_adi: - DEFCONFIG: adi_bcm2711_defconfig - ARCH: arm - bcmrpi_arm_adi: - DEFCONFIG: adi_bcmrpi_defconfig - ARCH: arm - steps: - - checkout: self - fetchDepth: 1 - clean: true - - script: ./ci/travis/run-build-docker.sh - displayName: "Build test for '$(DEFCONFIG)'" + SOURCE_DIRECTORY: $(Build.SourcesDirectory)/bin + KEY_FILE: $(key.secureFilePath) + jobs: + - job: Push_to_SWDownloads + condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/rpi-5.10.y')) + pool: + vmImage: 'ubuntu-latest' + steps: + - task: DownloadPipelineArtifact@2 + inputs: + path: $(Build.SourcesDirectory)/bin + - bash: ./ci/travis/prepare_artifacts.sh structure + displayName: 'Prepare the folder structure' + - task: DownloadSecureFile@1 + name: key + displayName: 'Download rsa key' + inputs: + secureFile: 'id_rsa' + - bash: ./ci/travis/prepare_artifacts.sh swdownloads + env: + DEST_SERVER: $(SERVER_ADDRESS) + displayName: "Push to SWDownloads" + - job: Push_to_Artifactory + condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/rpi-5.10.y')) + pool: + name: Default + demands: + - agent.name -equals lab2_b5 + steps: + - task: DownloadPipelineArtifact@2 + inputs: + path: $(Build.SourcesDirectory)/bin + - bash: ./ci/travis/prepare_artifacts.sh structure + displayName: 'Prepare the folder structure' + - bash: ./ci/travis/prepare_artifacts.sh artifactory + env: + ARTIFACTORY_PATH: $(PATH) + ARTIFACTORY_TOKEN: $(TOKEN) + displayName: "Push to Artifactory" From b39467c90e29766ecd6e08d3f6c3d7ff3c84b420 Mon Sep 17 00:00:00 2001 From: "stefan.raus" Date: Mon, 6 Dec 2021 12:32:57 +0000 Subject: [PATCH 041/407] Microblaze DTS: add missing hdl_project tags Add missing hdl_project tags in comment section of DTS. Fix also some typos. Signed-off-by: stefan.raus --- arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts | 4 ++-- arch/microblaze/boot/dts/kc705_fmcjesdadc1.dts | 12 +++++++++++- arch/microblaze/boot/dts/kc705_fmcomms2-3.dts | 12 +++++++++++- arch/microblaze/boot/dts/kc705_fmcomms4.dts | 12 +++++++++++- arch/microblaze/boot/dts/kcu105_fmcdaq3.dts | 11 ++++++++++- arch/microblaze/boot/dts/kcu105_fmcomms2-3.dts | 12 +++++++++++- arch/microblaze/boot/dts/kcu105_fmcomms4.dts | 12 +++++++++++- arch/microblaze/boot/dts/vc707_fmcadc2.dts | 11 ++++++++++- arch/microblaze/boot/dts/vc707_fmcadc5.dts | 11 ++++++++++- arch/microblaze/boot/dts/vc707_fmcdaq2.dts | 11 ++++++++++- arch/microblaze/boot/dts/vc707_fmcjesdadc1.dts | 12 +++++++++++- arch/microblaze/boot/dts/vc707_fmcomms2-3.dts | 12 +++++++++++- arch/microblaze/boot/dts/vc707_fmcomms4.dts | 12 +++++++++++- arch/microblaze/boot/dts/vcu118_dual_ad9208.dts | 11 +++++++++++ arch/microblaze/boot/dts/vcu118_fmcdaq3.dts | 11 ++++++++++- 15 files changed, 151 insertions(+), 15 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts index 285b2ec474887c..7bb91a847a559a 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Analog Devices AD-FMCOMMS11-EBZ + * Analog Devices AD-FMCJESDADC1 FMC * https://wiki.analog.com/resources/eval/user-guides/ad-fmcjesdadc1-ebz * * hdl_project: * board_revision: <> * - * Copyright (C) 2014-2020 Analog Devices Inc. + * Copyright (C) 2014-2021 Analog Devices Inc. */ /dts-v1/; diff --git a/arch/microblaze/boot/dts/kc705_fmcjesdadc1.dts b/arch/microblaze/boot/dts/kc705_fmcjesdadc1.dts index f9e57e011d0e35..9b11d4bec1ad8e 100644 --- a/arch/microblaze/boot/dts/kc705_fmcjesdadc1.dts +++ b/arch/microblaze/boot/dts/kc705_fmcjesdadc1.dts @@ -1,4 +1,14 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCJESDADC1 FMC + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/axi-adc-hdl + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcjesdadc1-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2016-2021 Analog Devices Inc. + */ /dts-v1/; #include "kc705.dtsi" diff --git a/arch/microblaze/boot/dts/kc705_fmcomms2-3.dts b/arch/microblaze/boot/dts/kc705_fmcomms2-3.dts index 7ae9d3253997b5..1864017528755b 100644 --- a/arch/microblaze/boot/dts/kc705_fmcomms2-3.dts +++ b/arch/microblaze/boot/dts/kc705_fmcomms2-3.dts @@ -1,4 +1,14 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCOMMS2-EBZ/AD-FMCOMMS3-EBZ + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcomms2-ebz + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcomms3-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2014-2021 Analog Devices Inc. + */ /dts-v1/; #include "kc705.dtsi" diff --git a/arch/microblaze/boot/dts/kc705_fmcomms4.dts b/arch/microblaze/boot/dts/kc705_fmcomms4.dts index cb9211149725e3..35e0e37d2f283f 100644 --- a/arch/microblaze/boot/dts/kc705_fmcomms4.dts +++ b/arch/microblaze/boot/dts/kc705_fmcomms4.dts @@ -1,4 +1,14 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices EVAL-AD-FMCOMMS4-EBZ + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-transceiver/ad9361 + * https://wiki.analog.com/eval/user-guides/ad-fmcomms4-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2014-2021 Analog Devices Inc. + */ /dts-v1/; #include "kc705.dtsi" diff --git a/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts b/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts index 59adc93759500e..c774bf77bde74c 100644 --- a/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts +++ b/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts @@ -1,4 +1,13 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCDAQ3-EBZ + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq3-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2015-2021 Analog Devices Inc. + */ /dts-v1/; #include "kcu105.dtsi" diff --git a/arch/microblaze/boot/dts/kcu105_fmcomms2-3.dts b/arch/microblaze/boot/dts/kcu105_fmcomms2-3.dts index f90eddc3807945..daa4012a43f5a5 100644 --- a/arch/microblaze/boot/dts/kcu105_fmcomms2-3.dts +++ b/arch/microblaze/boot/dts/kcu105_fmcomms2-3.dts @@ -1,4 +1,14 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCOMMS2-EBZ/AD-FMCOMMS3-EBZ + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcomms2-ebz + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcomms3-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2014-2021 Analog Devices Inc. + */ /dts-v1/; #include "kcu105.dtsi" diff --git a/arch/microblaze/boot/dts/kcu105_fmcomms4.dts b/arch/microblaze/boot/dts/kcu105_fmcomms4.dts index 95f7cfcd2c688a..540a0a81ac719c 100644 --- a/arch/microblaze/boot/dts/kcu105_fmcomms4.dts +++ b/arch/microblaze/boot/dts/kcu105_fmcomms4.dts @@ -1,4 +1,14 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices EVAL-AD-FMCOMMS4-EBZ + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-transceiver/ad9361 + * https://wiki.analog.com/eval/user-guides/ad-fmcomms4-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2014-2021 Analog Devices Inc. + */ /dts-v1/; #include "kcu105.dtsi" diff --git a/arch/microblaze/boot/dts/vc707_fmcadc2.dts b/arch/microblaze/boot/dts/vc707_fmcadc2.dts index 9032d5461aad42..44ac0f96d5fb19 100644 --- a/arch/microblaze/boot/dts/vc707_fmcadc2.dts +++ b/arch/microblaze/boot/dts/vc707_fmcadc2.dts @@ -1,4 +1,13 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCADC2-EBZ + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcadc2-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2014-2021 Analog Devices Inc. + */ /dts-v1/; #include "vc707.dtsi" diff --git a/arch/microblaze/boot/dts/vc707_fmcadc5.dts b/arch/microblaze/boot/dts/vc707_fmcadc5.dts index 89d98f3fb611d0..6e5cb7e3bfd3ee 100644 --- a/arch/microblaze/boot/dts/vc707_fmcadc5.dts +++ b/arch/microblaze/boot/dts/vc707_fmcadc5.dts @@ -1,4 +1,13 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCADC5-EBZ + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcadc5-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2014-2021 Analog Devices Inc. + */ /dts-v1/; #include "vc707.dtsi" diff --git a/arch/microblaze/boot/dts/vc707_fmcdaq2.dts b/arch/microblaze/boot/dts/vc707_fmcdaq2.dts index c65c947654a0c4..06fd427d2a709f 100644 --- a/arch/microblaze/boot/dts/vc707_fmcdaq2.dts +++ b/arch/microblaze/boot/dts/vc707_fmcdaq2.dts @@ -1,4 +1,13 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCDAQ2-EBZ + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq2-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2014-2021 Analog Devices Inc. + */ /dts-v1/; #include "vc707.dtsi" diff --git a/arch/microblaze/boot/dts/vc707_fmcjesdadc1.dts b/arch/microblaze/boot/dts/vc707_fmcjesdadc1.dts index e171119cd023cf..362d91e78baeb7 100644 --- a/arch/microblaze/boot/dts/vc707_fmcjesdadc1.dts +++ b/arch/microblaze/boot/dts/vc707_fmcjesdadc1.dts @@ -1,4 +1,14 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCJESDADC1 FMC + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/axi-adc-hdl + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcjesdadc1-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2016-2021 Analog Devices Inc. + */ /dts-v1/; #include "vc707.dtsi" diff --git a/arch/microblaze/boot/dts/vc707_fmcomms2-3.dts b/arch/microblaze/boot/dts/vc707_fmcomms2-3.dts index c39fb9e4a99bd2..2dea4e2ea119d9 100644 --- a/arch/microblaze/boot/dts/vc707_fmcomms2-3.dts +++ b/arch/microblaze/boot/dts/vc707_fmcomms2-3.dts @@ -1,4 +1,14 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCOMMS2-EBZ/AD-FMCOMMS3-EBZ + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcomms2-ebz + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcomms3-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2014-2021 Analog Devices Inc. + */ /dts-v1/; #include "vc707.dtsi" diff --git a/arch/microblaze/boot/dts/vc707_fmcomms4.dts b/arch/microblaze/boot/dts/vc707_fmcomms4.dts index 371cf790964e15..4b389c9ab47f34 100644 --- a/arch/microblaze/boot/dts/vc707_fmcomms4.dts +++ b/arch/microblaze/boot/dts/vc707_fmcomms4.dts @@ -1,4 +1,14 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices EVAL-AD-FMCOMMS4-EBZ + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-transceiver/ad9361 + * https://wiki.analog.com/eval/user-guides/ad-fmcomms4-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2014-2021 Analog Devices Inc. + */ /dts-v1/; #include "vc707.dtsi" diff --git a/arch/microblaze/boot/dts/vcu118_dual_ad9208.dts b/arch/microblaze/boot/dts/vcu118_dual_ad9208.dts index 16a0289c472bd9..988b3e2d074664 100644 --- a/arch/microblaze/boot/dts/vcu118_dual_ad9208.dts +++ b/arch/microblaze/boot/dts/vcu118_dual_ad9208.dts @@ -1,4 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD9208 / AD9689 ANALOG-TO-DIGITAL CONVERTER + * https://wiki.analog.com/resources/eval/ad9208-3000ebz + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/ad9208 + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2021 Analog Devices Inc. + */ + /dts-v1/; #include "vcu118.dtsi" diff --git a/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts b/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts index 52474b3ce4a3cb..46a62efbd35361 100644 --- a/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts +++ b/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts @@ -1,4 +1,13 @@ - +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCDAQ3-EBZ + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq3-ebz + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2015-2021 Analog Devices Inc. + */ /dts-v1/; #include "vcu118.dtsi" From 4f862df3c5d59726b90fb13ddbed1d601a59002f Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 8 Dec 2021 10:09:55 +0100 Subject: [PATCH 042/407] iio: adc: ad9081: Revise debugfs jesd status * Always print single line per link * Handle asymmetric dual link cases (JRX dual/JTX single, ...) * Include JESDV Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 44 +++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 7f2439eba01c4f..cd4be43413dd3e 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -2641,57 +2641,55 @@ static int ad9081_status_show(struct seq_file *file, void *offset) u16 stat; u8 vals[3]; - for (l = AD9081_LINK_0; l < AD9081_LINK_ALL; l++) { + for (l = AD9081_LINK_0; !phy->tx_disable && (l < (ad9081_link_is_dual(phy->jrx_link_tx) ? + AD9081_LINK_ALL : AD9081_LINK_1)); l++) { ret = adi_ad9081_jesd_rx_link_status_get( &phy->ad9081, l, &stat); if (ret) return -EFAULT; - if (phy->jtx_link_rx[l - 1].jesd_param.jesd_jesdv == JESD204_VERSION_C) { + adi_ad9081_hal_reg_get(&phy->ad9081, REG_JRX_TPL_3_ADDR, &vals[0]); + adi_ad9081_hal_reg_get(&phy->ad9081, REG_JRX_TPL_4_ADDR, &vals[1]); + adi_ad9081_hal_reg_get(&phy->ad9081, REG_JRX_TPL_5_ADDR, &vals[2]); + + if (phy->jrx_link_tx[l - 1].jesd_param.jesd_jesdv == JESD204_VERSION_C) { stat >>= 8; seq_printf(file, - "JESD TX (JRX) Link%d 204C status %s (%d)\n", - l, ad9081_jrx_204c_states[stat & 0x7], stat); + "JESD TX (JRX) Link%d 204C status %s (%d), TPL Phase Difference Read %u, Set %u\n", + l - 1, ad9081_jrx_204c_states[stat & 0x7], stat, + vals[2], vals[1] << 8 | vals[0]); } else { seq_printf(file, - "JESD TX (JRX) Link%d 0x%X lanes in DATA\n", - l, stat & 0xF); + "JESD TX (JRX) Link%d 204B 0x%X lanes in DATA, TPL Phase Difference Read %u, Set %u\n", + l - 1, stat & 0xF, vals[2], vals[1] << 8 | vals[0]); } + } - adi_ad9081_hal_reg_get(&phy->ad9081, REG_JRX_TPL_3_ADDR, &vals[0]); - adi_ad9081_hal_reg_get(&phy->ad9081, REG_JRX_TPL_4_ADDR, &vals[1]); - adi_ad9081_hal_reg_get(&phy->ad9081, REG_JRX_TPL_5_ADDR, &vals[2]); - - seq_printf(file, - "JESD TX (JRX) Link%d TPL Phase Difference Read %u, Set %u\n", - l, vals[2], vals[1] << 8 | vals[0]); + for (l = AD9081_LINK_0; !phy->rx_disable && (l < (ad9081_link_is_dual(phy->jtx_link_rx) ? + AD9081_LINK_ALL : AD9081_LINK_1)); l++) { ret = adi_ad9081_jesd_tx_link_status_get( &phy->ad9081, l, &stat); if (ret) return -EFAULT; - if (phy->jrx_link_tx[0].jesd_param.jesd_jesdv == JESD204_VERSION_C) { + + if (phy->jtx_link_rx[0].jesd_param.jesd_jesdv == JESD204_VERSION_C) { seq_printf(file, - "JESD RX (JTX) Link%d PLL %s, PHASE %s, MODE %s\n", - l, + "JESD RX (JTX) Link%d 204C PLL %s, PHASE %s, MODE %s\n", + l - 1, stat & BIT(5) ? "locked" : "unlocked", stat & BIT(6) ? "established" : "lost", stat & BIT(7) ? "invalid" : "valid"); } else { seq_printf(file, - "JESD RX (JTX) Link%d in %s, SYNC %s, PLL %s, PHASE %s, MODE %s\n", - l, ad9081_jtx_qbf_states[stat & 0xF], + "JESD RX (JTX) Link%d 204B in %s, SYNC %s, PLL %s, PHASE %s, MODE %s\n", + l - 1, ad9081_jtx_qbf_states[stat & 0xf], stat & BIT(4) ? "deasserted" : "asserted", stat & BIT(5) ? "locked" : "unlocked", stat & BIT(6) ? "established" : "lost", stat & BIT(7) ? "invalid" : "valid"); } - if (!phy->jtx_link_rx[l - 1].jesd_param.jesd_duallink) - return 0; - - if (!ad9081_link_is_dual(phy->jrx_link_tx)) - return 0; } return 0; From cb0a0048415743ffd6c94bcf3fe9d3097889bec7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 8 Dec 2021 10:16:00 +0100 Subject: [PATCH 043/407] iio: adc: ad9081: Fix single JTX with DUAL JRX link use case In this use case even when the second link doesn't get enabled The physical to logical lane mapping must not conflict. Move memcpys to the individual RX/TX setup functions. Prevent in single JTX use case the case where we would zero the mapping. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 110 +++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 40 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index cd4be43413dd3e..b5cc3e477de82e 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -1748,6 +1748,14 @@ static int ad9081_setup_tx(struct spi_device *spi) if (phy->tx_disable) return 0; + memcpy(phy->ad9081.serdes_info.des_settings.lane_mapping[0], + phy->jrx_link_tx[0].logiclane_mapping, + sizeof(phy->jrx_link_tx[0].logiclane_mapping)); + + memcpy(phy->ad9081.serdes_info.des_settings.lane_mapping[1], + phy->jrx_link_tx[1].logiclane_mapping, + sizeof(phy->jrx_link_tx[1].logiclane_mapping)); + /* start txfe tx */ ret = adi_ad9081_device_startup_tx( &phy->ad9081, phy->tx_main_interp, phy->tx_chan_interp, @@ -1813,6 +1821,15 @@ static int ad9081_setup_rx(struct spi_device *spi) return 0; } + memcpy(phy->ad9081.serdes_info.ser_settings.lane_mapping[0], + phy->jtx_link_rx[0].logiclane_mapping, + sizeof(phy->jtx_link_rx[0].logiclane_mapping)); + + if (ad9081_link_is_dual(phy->jtx_link_rx)) + memcpy(phy->ad9081.serdes_info.ser_settings.lane_mapping[1], + phy->jtx_link_rx[1].logiclane_mapping, + sizeof(phy->jtx_link_rx[1].logiclane_mapping)); + for (i = 0; i < ARRAY_SIZE(phy->adc_main_decimation); i++) { ret = ad9081_main_decimation_to_val( phy->adc_main_decimation[i]); @@ -4421,30 +4438,59 @@ static int ad9081_probe(struct spi_device *spi) phy->ad9081.hal_info.user_data = conv; phy->ad9081.hal_info.log_write = ad9081_log_write; - phy->ad9081.serdes_info = (adi_ad9081_serdes_settings_t) { - .ser_settings = { /* txfe jtx */ - .lane_settings = { - {.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB}, - {.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB}, - {.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB}, - {.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB}, - {.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB}, - {.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB}, - {.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB}, - {.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB}, - }, - .invert_mask = 0x00, - .lane_mapping = { { 0, 1, 2, 3, 4, 5, 6, 7}, { 0, 1, 2, 3, 4, 5, 6, 7 } }, /* link0, link1 */ - }, - .des_settings = { /* txfe jrx */ - .boost_mask = 0xff, - .invert_mask = 0x00, - .ctle_filter = { 2, 2, 2, 2, 2, 2, 2, 2 }, - .lane_mapping = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7} }, /* link0, link1 */ - } - }; - - + phy->ad9081.serdes_info = (adi_ad9081_serdes_settings_t) { + .ser_settings = { /* txfe jtx */ + .lane_settings = { + { + .swing_setting = AD9081_SER_SWING_850, + .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, + .post_emp_setting = AD9081_SER_POST_EMP_0DB + }, { + .swing_setting = AD9081_SER_SWING_850, + .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, + .post_emp_setting = AD9081_SER_POST_EMP_0DB + }, { + .swing_setting = AD9081_SER_SWING_850, + .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, + .post_emp_setting = AD9081_SER_POST_EMP_0DB + }, { + .swing_setting = AD9081_SER_SWING_850, + .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, + .post_emp_setting = AD9081_SER_POST_EMP_0DB + }, { + .swing_setting = AD9081_SER_SWING_850, + .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, + .post_emp_setting = AD9081_SER_POST_EMP_0DB + }, { + .swing_setting = AD9081_SER_SWING_850, + .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, + .post_emp_setting = AD9081_SER_POST_EMP_0DB + }, { + .swing_setting = AD9081_SER_SWING_850, + .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, + .post_emp_setting = AD9081_SER_POST_EMP_0DB + }, { + .swing_setting = AD9081_SER_SWING_850, + .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, + .post_emp_setting = AD9081_SER_POST_EMP_0DB + }, + }, + .invert_mask = 0x00, + .lane_mapping = { + { 0, 1, 2, 3, 4, 5, 6, 7 }, + { 7, 7, 7, 7, 7, 7, 7, 7 } + }, /* link0, link1 */ + }, + .des_settings = { /* txfe jrx */ + .boost_mask = 0xff, + .invert_mask = 0x00, + .ctle_filter = { 2, 2, 2, 2, 2, 2, 2, 2 }, + .lane_mapping = { + { 0, 1, 2, 3, 4, 5, 6, 7 }, + { 0, 1, 2, 3, 4, 5, 6, 7 } + }, /* link0, link1 */ + } + }; conv->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_HIGH); @@ -4477,22 +4523,6 @@ static int ad9081_probe(struct spi_device *spi) return -ENODEV; } - memcpy(phy->ad9081.serdes_info.ser_settings.lane_mapping[0], - phy->jtx_link_rx[0].logiclane_mapping, - sizeof(phy->jtx_link_rx[0].logiclane_mapping)); - - memcpy(phy->ad9081.serdes_info.ser_settings.lane_mapping[1], - phy->jtx_link_rx[1].logiclane_mapping, - sizeof(phy->jtx_link_rx[1].logiclane_mapping)); - - memcpy(phy->ad9081.serdes_info.des_settings.lane_mapping[0], - phy->jrx_link_tx[0].logiclane_mapping, - sizeof(phy->jrx_link_tx[0].logiclane_mapping)); - - memcpy(phy->ad9081.serdes_info.des_settings.lane_mapping[1], - phy->jrx_link_tx[1].logiclane_mapping, - sizeof(phy->jrx_link_tx[1].logiclane_mapping)); - ret = adi_ad9081_device_reset(&phy->ad9081, conv->reset_gpio ? AD9081_HARD_RESET_AND_INIT : AD9081_SOFT_RESET_AND_INIT); From 9344f4285eed13f4d351231a5480a4c1288d3cb1 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 8 Dec 2021 10:22:03 +0100 Subject: [PATCH 044/407] jesd204: jesd204-core: Avoid race condition during dyn. dt changes Always return EPROBE_DEFER while dynamic device tree change is in progress. fixes: b61aebb5a54("jesd204: jesd204-core: Support for dynamic dt changes") Signed-off-by: Michael Hennerich --- drivers/jesd204/jesd204-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/jesd204/jesd204-core.c b/drivers/jesd204/jesd204-core.c index 7842ee7ef8886b..85f20aab128e05 100644 --- a/drivers/jesd204/jesd204-core.c +++ b/drivers/jesd204/jesd204-core.c @@ -940,7 +940,7 @@ static struct jesd204_dev *jesd204_dev_register(struct device *dev, return ERR_PTR(-ENODEV); } - if (!jdev) + if (jesd204_dyn_dt_change) return ERR_PTR(-EPROBE_DEFER); ret = jesd204_dev_init_links_data(dev, jdev, init); From 12401977df5ef3721f31a66b1d99290c5ff7ce65 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sun, 15 Aug 2021 17:33:06 -0400 Subject: [PATCH 045/407] iio: adc: ad7949: enable use with non 14/16-bit controllers This driver supports devices with 14-bit and 16-bit sample sizes. This implies different SPI transfer lengths which are not always handled properly by some SPI controllers. To work around this limitation, define a big endian buffer used to split the buffer into two 8-bit messages in the event that the controller doesn't support 14-bit or 16-bit transfers. A separate buffer is introduced here to avoid performing operations on types of different endianness. Since all transfers use the same bits_per_word value, move that logic to the probe function, and let transfers default to the value defined in the struct spi_device. Signed-off-by: Liam Beguin Link: https://lore.kernel.org/r/20210815213309.2847711-3-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7949.c | 86 +++++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 28 deletions(-) diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c index 5d597e5050f682..9dd522e89ccad4 100644 --- a/drivers/iio/adc/ad7949.c +++ b/drivers/iio/adc/ad7949.c @@ -16,7 +16,6 @@ #define AD7949_MASK_TOTAL GENMASK(13, 0) #define AD7949_OFFSET_CHANNEL_SEL 7 #define AD7949_CFG_READ_BACK 0x1 -#define AD7949_CFG_REG_SIZE_BITS 14 enum { ID_AD7949 = 0, @@ -45,6 +44,7 @@ static const struct ad7949_adc_spec ad7949_adc_spec[] = { * @cfg: copy of the configuration register * @current_channel: current channel in use * @buffer: buffer to send / receive data to / from device + * @buf8b: be16 buffer to exchange data with the device in 8-bit transfers */ struct ad7949_adc_chip { struct mutex lock; @@ -55,27 +55,34 @@ struct ad7949_adc_chip { u16 cfg; unsigned int current_channel; u16 buffer ____cacheline_aligned; + __be16 buf8b; }; static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc, u16 val, u16 mask) { int ret; - int bits_per_word = ad7949_adc->resolution; - int shift = bits_per_word - AD7949_CFG_REG_SIZE_BITS; - struct spi_message msg; - struct spi_transfer tx[] = { - { - .tx_buf = &ad7949_adc->buffer, - .len = 2, - .bits_per_word = bits_per_word, - }, - }; ad7949_adc->cfg = (val & mask) | (ad7949_adc->cfg & ~mask); - ad7949_adc->buffer = ad7949_adc->cfg << shift; - spi_message_init_with_transfers(&msg, tx, 1); - ret = spi_sync(ad7949_adc->spi, &msg); + + switch (ad7949_adc->spi->bits_per_word) { + case 16: + ad7949_adc->buffer = ad7949_adc->cfg << 2; + ret = spi_write(ad7949_adc->spi, &ad7949_adc->buffer, 2); + break; + case 14: + ad7949_adc->buffer = ad7949_adc->cfg; + ret = spi_write(ad7949_adc->spi, &ad7949_adc->buffer, 2); + break; + case 8: + /* Here, type is big endian as it must be sent in two transfers */ + ad7949_adc->buf8b = cpu_to_be16(ad7949_adc->cfg << 2); + ret = spi_write(ad7949_adc->spi, &ad7949_adc->buf8b, 2); + break; + default: + dev_err(&ad7949_adc->indio_dev->dev, "unsupported BPW\n"); + return -EINVAL; + } /* * This delay is to avoid a new request before the required time to @@ -90,16 +97,6 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val, { int ret; int i; - int bits_per_word = ad7949_adc->resolution; - int mask = GENMASK(ad7949_adc->resolution, 0); - struct spi_message msg; - struct spi_transfer tx[] = { - { - .rx_buf = &ad7949_adc->buffer, - .len = 2, - .bits_per_word = bits_per_word, - }, - }; /* * 1: write CFG for sample N and read old data (sample N-2) @@ -118,9 +115,11 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val, } /* 3: write something and read actual data */ - ad7949_adc->buffer = 0; - spi_message_init_with_transfers(&msg, tx, 1); - ret = spi_sync(ad7949_adc->spi, &msg); + if (ad7949_adc->spi->bits_per_word == 8) + ret = spi_read(ad7949_adc->spi, &ad7949_adc->buf8b, 2); + else + ret = spi_read(ad7949_adc->spi, &ad7949_adc->buffer, 2); + if (ret) return ret; @@ -132,7 +131,25 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val, ad7949_adc->current_channel = channel; - *val = ad7949_adc->buffer & mask; + switch (ad7949_adc->spi->bits_per_word) { + case 16: + *val = ad7949_adc->buffer; + /* Shift-out padding bits */ + *val >>= 16 - ad7949_adc->resolution; + break; + case 14: + *val = ad7949_adc->buffer & GENMASK(13, 0); + break; + case 8: + /* Here, type is big endian as data was sent in two transfers */ + *val = be16_to_cpu(ad7949_adc->buf8b); + /* Shift-out padding bits */ + *val >>= 16 - ad7949_adc->resolution; + break; + default: + dev_err(&ad7949_adc->indio_dev->dev, "unsupported BPW\n"); + return -EINVAL; + } return 0; } @@ -231,6 +248,7 @@ static int ad7949_spi_init(struct ad7949_adc_chip *ad7949_adc) static int ad7949_spi_probe(struct spi_device *spi) { + u32 spi_ctrl_mask = spi->controller->bits_per_word_mask; struct device *dev = &spi->dev; const struct ad7949_adc_spec *spec; struct ad7949_adc_chip *ad7949_adc; @@ -257,6 +275,18 @@ static int ad7949_spi_probe(struct spi_device *spi) indio_dev->num_channels = spec->num_channels; ad7949_adc->resolution = spec->resolution; + /* Set SPI bits per word */ + if (spi_ctrl_mask & SPI_BPW_MASK(ad7949_adc->resolution)) { + spi->bits_per_word = ad7949_adc->resolution; + } else if (spi_ctrl_mask == SPI_BPW_MASK(16)) { + spi->bits_per_word = 16; + } else if (spi_ctrl_mask == SPI_BPW_MASK(8)) { + spi->bits_per_word = 8; + } else { + dev_err(dev, "unable to find common BPW with spi controller\n"); + return -EINVAL; + } + ad7949_adc->vref = devm_regulator_get(dev, "vref"); if (IS_ERR(ad7949_adc->vref)) { dev_err(dev, "fail to request regulator\n"); From 702f9ad91ce8319156f524f448a1dc32fe30503b Mon Sep 17 00:00:00 2001 From: Andrei Drimbarean Date: Tue, 14 Dec 2021 16:14:29 +0200 Subject: [PATCH 046/407] drivers:iio:adc:mykonos: fix ARM state check routine Correctly use a bitwise operation to check for the desired ARM state instead of logical operation. Signed-off-by: Andrei Drimbarean --- drivers/iio/adc/mykonos/mykonos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/mykonos/mykonos.c b/drivers/iio/adc/mykonos/mykonos.c index 03f0f0e488c3cc..04e2d92a512b83 100644 --- a/drivers/iio/adc/mykonos/mykonos.c +++ b/drivers/iio/adc/mykonos/mykonos.c @@ -13548,7 +13548,7 @@ mykonosErr_t MYKONOS_checkArmState(mykonosDevice_t *device, mykonosArmState_t ar break; } - if (armStateCheck && armStatusMapped) + if ((armStateCheck & armStatusMapped) || !(armStateCheck || armStatusMapped)) { retVal = MYKONOS_ERR_OK; break; From 02203501899c64105ada57f97b4af25edd45b366 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 16 Dec 2021 13:44:02 +0100 Subject: [PATCH 047/407] drivers/usb/Kconfig.adi: Remove USB Mass Storage Gadget This precomposed configurations interferes with the gadget created in configfs. Signed-off-by: Michael Hennerich --- drivers/usb/Kconfig.adi | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/Kconfig.adi b/drivers/usb/Kconfig.adi index cb460cb170c0cf..37ec5ab629000a 100644 --- a/drivers/usb/Kconfig.adi +++ b/drivers/usb/Kconfig.adi @@ -12,7 +12,6 @@ config USB_ALL_ADI_DRIVERS select USB_UAS select USB_EHCI_HCD select USB_STORAGE - select USB_MASS_STORAGE select USB_CHIPIDEA select USB_CHIPIDEA_UDC select USB_CHIPIDEA_HOST From 68049844d62547f6db05c7f2bd67def51ea0ea38 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 16 Dec 2021 13:44:52 +0100 Subject: [PATCH 048/407] configs: adi_zynqmp_defconfig: Update config for PlutoNG Also remove precomposed gadget functions. Moving forward all these gadgets are supported at runtime using configfs. Signed-off-by: Michael Hennerich --- arch/arm64/configs/adi_zynqmp_defconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/adi_zynqmp_defconfig b/arch/arm64/configs/adi_zynqmp_defconfig index dfe07d491b6a1b..d81ac9a5f0312f 100644 --- a/arch/arm64/configs/adi_zynqmp_defconfig +++ b/arch/arm64/configs/adi_zynqmp_defconfig @@ -264,8 +264,9 @@ CONFIG_SND_SOC_XILINX_SDI=y CONFIG_SND_SOC_XILINX_I2S=y CONFIG_SND_SOC_XILINX_SPDIF=y CONFIG_SND_SOC_XILINX_PL_SND_CARD=y -CONFIG_USB_ETH=m -CONFIG_USB_ETH_EEM=y +CONFIG_USB_OTG_FSM=y +CONFIG_USB_DWC3_ULPI=y +CONFIG_TYPEC_TPS6598X=y CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y From 0b18c371c4676cabd2f327056697b8e52c64f5a5 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 16 Dec 2021 13:48:11 +0100 Subject: [PATCH 049/407] dts: zynqmp-pluto-ng.dts: Add support for USB PDC Disable PDC initiated role switching using connectors for now. We revist this feature later. Signed-off-by: Michael Hennerich --- .../arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts b/arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts index b9d51dc4218a21..b168aa028616f6 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts @@ -18,6 +18,8 @@ #include #include +#undef PLUTO_NG_USB_ROLE_SW + / { model = "Analog Devices, Inc. Pluto NG"; compatible = "xlnx,zynqmp"; @@ -245,6 +247,34 @@ compatible = "adi,ltc2945"; reg = <0x6a>; }; + + typec_pd: usb-pd@38 { + compatible = "ti,tps6598x"; + reg = <0x38>; + interrupt-parent = <&gpio>; + interrupts = <31 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; + +#ifdef PLUTO_NG_USB_ROLE_SW + typec_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + port { + typec_ep: endpoint { + remote-endpoint = <&otg_ep>; + }; + }; + }; +#endif + }; + + typec_pd1: usb-pd@3f { + compatible = "ti,tps6598x"; + reg = <0x3F>; + interrupt-parent = <&gpio>; + interrupts = <31 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; + }; }; &zynqmp_dpsub { @@ -299,6 +329,18 @@ phy-names = "usb3-phy"; phys = <&psgtr 0 PHY_TYPE_USB3 0 0>; maximum-speed = "super-speed"; +#ifdef PLUTO_NG_USB_ROLE_SW + usb-role-switch; + role-switch-default-mode = "device"; + + port@0 { + reg = <0>; + + otg_ep: endpoint { + remote-endpoint = <&typec_con>; + }; + }; +#endif }; &gpio { From c0c1250c10886e431da77a06fd9a1e3bbeee2bb3 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Tue, 14 Dec 2021 11:38:28 -0500 Subject: [PATCH 050/407] iio:ad9361 print out the SPI CLK during probe This will only work for those SPI controllers which populate their effective_speed_hz during the clock setting, but for those that do, this will print out the SPI clock (in MHz) so it is easier to understand what's going on in the system. will see things like: ad9361 : AD936x Rev 2 successfully initialized (SPI @ 5.20 MHz) or ad9361 : AD936x Rev 2 successfully initialized (SPI @ 41.66 MHz) or (with older SPI controller drivers) ad9361 : AD936x Rev 2 successfully initialized tested on PlutoSDR Signed-off-by: Robin Getz --- drivers/iio/adc/ad9361.c | 50 ++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/drivers/iio/adc/ad9361.c b/drivers/iio/adc/ad9361.c index c9bd0805c3fc2a..ae85e1a42f319c 100644 --- a/drivers/iio/adc/ad9361.c +++ b/drivers/iio/adc/ad9361.c @@ -9399,13 +9399,44 @@ ad9361_gt_bin_read(struct file *filp, struct kobject *kobj, return ret; } +static int ad9361_spi_check(struct spi_device *spi) +{ + u8 buf[3] = {0}; + int ret; + u16 cmd; + struct spi_transfer t = { + .tx_buf = buf, + .rx_buf = buf, + .len = sizeof(buf), + }; + + /* + * We need do a low level spi transfer to get the effective speed + * otherwise we would just do a ad9361_spi_read() + */ + cmd = AD_READ | AD_CNT(1) | AD_ADDR(REG_PRODUCT_ID); + buf[0] = cmd >> 8; + buf[1] = cmd & 0xFF; + + ret = spi_sync_transfer(spi, &t, 1); + if (ret) + return ret; + + if ((buf[2] & PRODUCT_ID_MASK) != PRODUCT_ID_9361) { + dev_err(&spi->dev, "%s : Unsupported PRODUCT_ID 0x%X", __func__, buf[2]); + return -ENODEV; + } + + return t.effective_speed_hz; +} + static int ad9361_probe(struct spi_device *spi) { struct iio_dev *indio_dev; struct ad9361_rf_phy_state *st; struct ad9361_rf_phy *phy; struct clk *clk = NULL; - int ret, rev; + int ret, rev, hz; dev_info(&spi->dev, "%s : enter (%s)", __func__, spi_get_device_id(spi)->name); @@ -9468,12 +9499,9 @@ static int ad9361_probe(struct spi_device *spi) ad9361_reset(phy); - ret = ad9361_spi_read(spi, REG_PRODUCT_ID); - if ((ret & PRODUCT_ID_MASK) != PRODUCT_ID_9361) { - dev_err(&spi->dev, "%s : Unsupported PRODUCT_ID 0x%X", - __func__, ret); - return -ENODEV; - } + hz = ad9361_spi_check(spi); + if (hz < 0) + return hz; rev = ret & REV_MASK; @@ -9544,8 +9572,12 @@ static int ad9361_probe(struct spi_device *spi) if (ret < 0) dev_warn(&spi->dev, "%s: failed to register debugfs", __func__); - dev_info(&spi->dev, "%s : AD936x Rev %d successfully initialized", - __func__, rev); + if (hz > 0) + dev_info(&spi->dev, "%s : AD936x Rev %d successfully initialized (SPI @ %u.%02u MHz)", + __func__, rev, hz / 1000000, hz % 1000000 / 1000 / 10); + else + dev_info(&spi->dev, "%s : AD936x Rev %d successfully initialized", + __func__, rev); return 0; From 09b932e47b55250cdd51341215a0fc84a3424af1 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 16 Dec 2021 14:44:27 +0100 Subject: [PATCH 051/407] iio: adc: ad9081: Support for reading the API and silicon version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for reading the API and silicon version vi debugfs. Format for chip_version is “AD%X Rev. %u Grade %u", for api_version it is "%u.%u.%u“ Example: root@analog:~# iio_attr -u ip:analog.local -D axi-ad9081-rx-hpc api_version 1.2.0 root@analog:~# iio_attr -u ip:analog.local -D axi-ad9081-rx-hpc chip_version AD9082 Rev. 3 Grade 2 Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index b5cc3e477de82e..6baeacef52153b 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -3114,6 +3114,8 @@ enum ad9081_debugfs_cmd { DBGFS_BIST_JRX_SPO_SET, DBGFS_BIST_JRX_SPO_SWEEP, DBGFS_BIST_PRBS_JTX, + DBGFS_DEV_API_INFO, + DBGFS_DEV_CHIP_INFO, }; static ssize_t ad9081_debugfs_read(struct file *file, char __user *userbuf, @@ -3127,6 +3129,7 @@ static ssize_t ad9081_debugfs_read(struct file *file, char __user *userbuf, u64 val = 0; ssize_t len = 0; int ret, i, j; + u8 api_rev[3]; if (entry->out_value) { switch (entry->size) { @@ -3176,6 +3179,20 @@ static ssize_t ad9081_debugfs_read(struct file *file, char __user *userbuf, case DBGFS_BIST_JRX_SPO_SET: len = snprintf(buf, sizeof(buf), "%d\n", (int) entry->val); break; + case DBGFS_DEV_API_INFO: + adi_ad9081_device_api_revision_get(&phy->ad9081, + &api_rev[0], &api_rev[1], &api_rev[2]); + + len = snprintf(buf, sizeof(buf), "%u.%u.%u\n", + api_rev[0], api_rev[1], api_rev[2]); + break; + case DBGFS_DEV_CHIP_INFO: + adi_ad9081_device_api_revision_get(&phy->ad9081, &api_rev[0], + &api_rev[1], &api_rev[2]); + + len = snprintf(buf, sizeof(buf), "AD%X Rev. %u Grade %u\n", + conv->id, phy->chip_id.dev_revision, phy->chip_id.prod_grade); + break; default: val = entry->val; } @@ -3389,6 +3406,10 @@ static int ad9081_post_iio_register(struct iio_dev *indio_dev) "bist_spo_set_jrx", DBGFS_BIST_JRX_SPO_SET); ad9081_add_debugfs_entry(indio_dev, "bist_spo_sweep_jrx", DBGFS_BIST_JRX_SPO_SWEEP); + ad9081_add_debugfs_entry(indio_dev, + "api_version", DBGFS_DEV_API_INFO); + ad9081_add_debugfs_entry(indio_dev, + "chip_version", DBGFS_DEV_CHIP_INFO); for (i = 0; i < phy->ad9081_debugfs_entry_index; i++) debugfs_create_file( phy->debugfs_entry[i].propname, 0644, From faa92b69233b256cc0e1088bdf1d634ae24a4401 Mon Sep 17 00:00:00 2001 From: Mihail Chindris Date: Tue, 16 Nov 2021 15:20:02 +0000 Subject: [PATCH 052/407] dt-bindings: iio: dac: Add adi,ad3552r.yaml Add documentation for ad3552r and ad3542r Signed-off-by: Mihail Chindris --- .../bindings/iio/dac/adi,ad3552r.yaml | 217 ++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml new file mode 100644 index 00000000000000..501a463e5d882f --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml @@ -0,0 +1,217 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2020 Analog Devices Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,ad3552r.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD2552R DAC device driver + +maintainers: + - Mihail Chindris + +description: | + Bindings for the Analog Devices AD3552R DAC device and similar. + Datasheet can be found here: + https://www.analog.com/media/en/technical-documentation/data-sheets/ad3542r.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad3552r.pdf + +properties: + compatible: + enum: + - adi,ad3542r + - adi,ad3552r + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 30000000 + + reset-gpios: + maxItems: 1 + + ldac-gpios: + description: | + LDAC pin to be used as a hardware trigger to update the DAC channels. + maxItems: 1 + + vref-supply: + description: + The regulator to use as an external reference. If it does not exists the + internal reference will be used. External reference must be 2.5V + + adi,vref-out-en: + description: Vref I/O driven by internal vref to 2.5V. If not set, Vref pin + will be floating. + type: boolean + + adi,sdo-drive-strength: + description: | + Configure SDIO0 and SDIO1 strength levels: + - 0: low SDO drive strength. + - 1: medium low SDO drive strength. + - 2: medium high SDO drive strength. + - 3: high SDO drive strength + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3] + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + "^channel@([0-1])$": + type: object + description: Configurations of the DAC Channels + + additionalProperties: false + + properties: + reg: + description: Channel number + enum: [0, 1] + + adi,output-range-microvolt: true + + custom-output-range-config: + type: object + description: Configuration of custom range when + adi,output-range-microvolt is not present. + The formulas for calculation the output voltages are + Vout_fs = 2.5 + [(GainN + Offset/1024) * 2.5 * Rfbx * 1.03] + Vout_zs = 2.5 - [(GainP + Offset/1024) * 2.5 * Rfbx * 1.03] + + properties: + adi,gain-offset: + description: Gain offset used in the above formula + $ref: /schemas/types.yaml#/definitions/int32 + maximum: 511 + minimum: -511 + + adi,gain-scaling-p-inv-log2: + description: GainP = 1 / ( 2 ^ adi,gain-scaling-p-inv-log2) + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3] + + adi,gain-scaling-n-inv-log2: + description: GainN = 1 / ( 2 ^ adi,gain-scaling-n-inv-log2) + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3] + + adi,rfb-ohms: + description: Feedback Resistor + + required: + - adi,gain-offset + - adi,gain-scaling-p-inv-log2 + - adi,gain-scaling-n-inv-log2 + - adi,rfb-ohms + + required: + - reg + + oneOf: + # If adi,output-range-microvolt is missing, + # custom-output-range-config must be used + - required: + - adi,output-range-microvolt + + - required: + - custom-output-range-config + +allOf: + - if: + properties: + compatible: + contains: + const: adi,ad3542r + then: + patternProperties: + "^channel@([0-1])$": + type: object + properties: + adi,output-range-microvolt: + description: | + Voltage output range of the channel as + Required connections: + Rfb1x for: 0 to 2.5 V; 0 to 3V; 0 to 5 V; + Rfb2x for: 0 to 10 V; 2.5 to 7.5V; -5 to 5 V; + oneOf: + - items: + - const: 0 + - enum: [2500000, 3000000, 5000000, 10000000] + - items: + - const: -2500000 + - const: 7500000 + - items: + - const: -5000000 + - const: 5000000 + + required: + - adi,output-range-microvolt + + - if: + properties: + compatible: + contains: + const: adi,ad3552r + then: + patternProperties: + "^channel@([0-1])$": + type: object + properties: + adi,output-range-microvolt: + description: | + Voltage output range of the channel as + Required connections: + Rfb1x for: 0 to 2.5 V; 0 to 5 V; + Rfb2x for: 0 to 10 V; -5 to 5 V; + Rfb4x for: -10 to 10V + oneOf: + - items: + - const: 0 + - enum: [2500000, 5000000, 10000000] + - items: + - const: -5000000 + - const: 5000000 + - items: + - const: -10000000 + - const: 10000000 + +required: + - compatible + - reg + - spi-max-frequency + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + ad3552r@0 { + compatible = "adi,ad3552r"; + reg = <0>; + spi-max-frequency = <20000000>; + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + adi,output-range-microvolt = <0 10000000>; + }; + channel@1 { + reg = <1>; + custom-output-range-config { + adi,gain-offset = <5>; + adi,gain-scaling-p-inv-log2 = <1>; + adi,gain-scaling-n-inv-log2 = <2>; + adi,rfb-ohms = <1>; + }; + }; + }; + }; +... From 90d6efa3a0f81478bdafa69e95dd268f4666cf3c Mon Sep 17 00:00:00 2001 From: Mihail Chindris Date: Tue, 16 Nov 2021 15:21:28 +0000 Subject: [PATCH 053/407] drivers:iio:dac: Add AD3552R driver support The AD3552R-16 is a low drift ultrafast, 16-bit accuracy, current output digital-to-analog converter (DAC) designed to generate multiple output voltage span ranges. The AD3552R-16 operates with a fixed 2.5V reference. Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ad3552r.pdf Signed-off-by: Mihail Chindris --- drivers/iio/dac/Kconfig | 10 + drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ad3552r.c | 1148 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1159 insertions(+) create mode 100644 drivers/iio/dac/ad3552r.c diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index a4c6121bf0842b..07ceef61abe8a7 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -6,6 +6,16 @@ menu "Digital to analog converters" +config AD3552R + tristate "Analog Devices AD3552R DAC driver" + depends on SPI_MASTER + help + Say yes here to build support for Analog Devices AD3552R + Digital to Analog Converter. + + To compile this driver as a module, choose M here: the + module will be called ad3552r. + config AD5064 tristate "Analog Devices AD5064 and similar multi-channel DAC driver" depends on (SPI_MASTER && I2C!=m) || I2C diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 345308982520ca..bb4c40cf8e7261 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -4,6 +4,7 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AD3552R) += ad3552r.o obj-$(CONFIG_AD5270) += ad5270.o obj-$(CONFIG_AD5360) += ad5360.o obj-$(CONFIG_AD5380) += ad5380.o diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c new file mode 100644 index 00000000000000..3ebdb3a6610e98 --- /dev/null +++ b/drivers/iio/dac/ad3552r.c @@ -0,0 +1,1148 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices AD3552R + * Digital to Analog converter driver + * + * Copyright 2021 Analog Devices Inc. + */ +#include +#include +/* iio.h and buffer.h not in 5.14 */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register addresses */ +/* Primary address space */ +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00 +#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0)) +#define AD3552R_MASK_ADDR_ASCENSION BIT(5) +#define AD3552R_MASK_SDO_ACTIVE BIT(4) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01 +#define AD3552R_MASK_SINGLE_INST BIT(7) +#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3) +#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02 +#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n)) +#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2) +#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0) +#define AD3552R_REG_ADDR_CHIP_TYPE 0x03 +#define AD3552R_MASK_CLASS GENMASK(7, 0) +#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04 +#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05 +#define AD3552R_REG_ADDR_CHIP_GRADE 0x06 +#define AD3552R_MASK_GRADE GENMASK(7, 4) +#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0) +#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A +#define AD3552R_REG_ADDR_SPI_REVISION 0x0B +#define AD3552R_REG_ADDR_VENDOR_L 0x0C +#define AD3552R_REG_ADDR_VENDOR_H 0x0D +#define AD3552R_REG_ADDR_STREAM_MODE 0x0E +#define AD3552R_MASK_LENGTH GENMASK(7, 0) +#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F +#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6) +#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10 +#define AD3552R_MASK_CRC_ENABLE (GENMASK(7, 6) |\ + GENMASK(1, 0)) +#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5) +#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11 +#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7) +#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5) +#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3) +#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2) +#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1) +#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14 +#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6) +#define AD3552R_MASK_MEM_CRC_EN BIT(4) +#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2) +#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1) +#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0) +#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15 +#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6) +#define AD3552R_MASK_SAMPLE_HOLD_DIFFERENTIAL_USER_EN BIT(5) +#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3) +#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2) +#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0) +#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16 +#define AD3552R_MASK_REF_RANGE_ALARM BIT(6) +#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5) +#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4) +#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3) +#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2) +#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1) +#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0) +#define AD3552R_REG_ADDR_ERR_STATUS 0x17 +#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6) +#define AD3552R_MASK_DUAL_SPI_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5) +#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4) +#define AD3552R_MASK_RESET_STATUS BIT(0) +#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18 +#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch)) +#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch) +#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19 +#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) ((ch) ? GENMASK(7, 4) :\ + GENMASK(3, 0)) +#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2) +#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0) +#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2) +#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7) +#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5) +#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3) +#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2) +#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(0) +/* + * Secondary region + * For multibyte registers specify the highest address because the access is + * done in descending order + */ +#define AD3552R_SECONDARY_REGION_START 0x28 +#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28 +#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - ch) * 2) +#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E +#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F +#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31 +#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32 +#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - ch) * 2) +/* 3 bytes registers */ +#define AD3552R_REG_START_24B 0x37 +#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37 +#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - ch) * 3) +#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40 +#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41 +#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44 +#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45 +#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - ch) * 3) + +/* Useful defines */ +#define AD3552R_NUM_CH 2 +#define AD3552R_MASK_CH(ch) BIT(ch) +#define AD3552R_MASK_ALL_CH GENMASK(1, 0) +#define AD3552R_MAX_REG_SIZE 3 +#define AD3552R_READ_BIT BIT(7) +#define AD3552R_ADDR_MASK GENMASK(6, 0) +#define AD3552R_MASK_DAC_12B 0xFFF0 +#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8 +#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34 +#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2 +#define AD3552R_GAIN_SCALE 1000 +#define AD3552R_LDAC_PULSE_US 100 + +enum ad3552r_ch_vref_select { + /* Internal source with Vref I/O floating */ + AD3552R_INTERNAL_VREF_PIN_FLOATING, + /* Internal source with Vref I/O at 2.5V */ + AD3552R_INTERNAL_VREF_PIN_2P5V, + /* External source with Vref I/O as input */ + AD3552R_EXTERNAL_VREF_PIN_INPUT +}; + +enum ad3542r_id { + AD3542R_ID = 0x4008, + AD3552R_ID = 0x4009, +}; + +enum ad3552r_ch_output_range { + /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ + AD3552R_CH_OUTPUT_RANGE_0__2P5V, + /* Range from 0 V to 5 V. Requires Rfb1x connection */ + AD3552R_CH_OUTPUT_RANGE_0__5V, + /* Range from 0 V to 10 V. Requires Rfb2x connection */ + AD3552R_CH_OUTPUT_RANGE_0__10V, + /* Range from -5 V to 5 V. Requires Rfb2x connection */ + AD3552R_CH_OUTPUT_RANGE_NEG_5__5V, + /* Range from -10 V to 10 V. Requires Rfb4x connection */ + AD3552R_CH_OUTPUT_RANGE_NEG_10__10V, +}; + +static const s32 ad3552r_ch_ranges[][2] = { + [AD3552R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500}, + [AD3552R_CH_OUTPUT_RANGE_0__5V] = {0, 5000}, + [AD3552R_CH_OUTPUT_RANGE_0__10V] = {0, 10000}, + [AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000}, + [AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = {-10000, 10000} +}; + +enum ad3542r_ch_output_range { + /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__2P5V, + /* Range from 0 V to 3 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__3V, + /* Range from 0 V to 5 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__5V, + /* Range from 0 V to 10 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_0__10V, + /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V, + /* Range from -5 V to 5 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_NEG_5__5V, +}; + +static const s32 ad3542r_ch_ranges[][2] = { + [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500}, + [AD3542R_CH_OUTPUT_RANGE_0__3V] = {0, 3000}, + [AD3542R_CH_OUTPUT_RANGE_0__5V] = {0, 5000}, + [AD3542R_CH_OUTPUT_RANGE_0__10V] = {0, 10000}, + [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = {-2500, 7500}, + [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000} +}; + +enum ad3552r_ch_gain_scaling { + /* Gain scaling of 1 */ + AD3552R_CH_GAIN_SCALING_1, + /* Gain scaling of 0.5 */ + AD3552R_CH_GAIN_SCALING_0_5, + /* Gain scaling of 0.25 */ + AD3552R_CH_GAIN_SCALING_0_25, + /* Gain scaling of 0.125 */ + AD3552R_CH_GAIN_SCALING_0_125, +}; + +/* Gain * AD3552R_GAIN_SCALE */ +static const s32 gains_scaling_table[] = { + [AD3552R_CH_GAIN_SCALING_1] = 1000, + [AD3552R_CH_GAIN_SCALING_0_5] = 500, + [AD3552R_CH_GAIN_SCALING_0_25] = 250, + [AD3552R_CH_GAIN_SCALING_0_125] = 125 +}; + +enum ad3552r_dev_attributes { + /* - Direct register values */ + /* From 0-3 */ + AD3552R_SDO_DRIVE_STRENGTH, + /* + * 0 -> Internal Vref, vref_io pin floating (default) + * 1 -> Internal Vref, vref_io driven by internal vref + * 2 or 3 -> External Vref + */ + AD3552R_VREF_SELECT, + /* Read registers in ascending order if set. Else descending */ + AD3552R_ADDR_ASCENSION, +}; + +enum ad3552r_ch_attributes { + /* DAC powerdown */ + AD3552R_CH_DAC_POWERDOWN, + /* DAC amplifier powerdown */ + AD3552R_CH_AMPLIFIER_POWERDOWN, + /* Select the output range. Select from enum ad3552r_ch_output_range */ + AD3552R_CH_OUTPUT_RANGE_SEL, + /* + * Over-rider the range selector in order to manually set the output + * voltage range + */ + AD3552R_CH_RANGE_OVERRIDE, + /* Manually set the offset voltage */ + AD3552R_CH_GAIN_OFFSET, + /* Sets the polarity of the offset. */ + AD3552R_CH_GAIN_OFFSET_POLARITY, + /* PDAC gain scaling */ + AD3552R_CH_GAIN_SCALING_P, + /* NDAC gain scaling */ + AD3552R_CH_GAIN_SCALING_N, + /* Rfb value */ + AD3552R_CH_RFB, + /* Channel select. When set allow Input -> DAC and Mask -> DAC */ + AD3552R_CH_SELECT, +}; + +struct ad3552r_ch_data { + s32 scale_int; + s32 scale_dec; + s32 offset_int; + s32 offset_dec; + s16 gain_offset; + u16 rfb; + u8 n; + u8 p; + u8 range; + bool range_override; +}; + +struct ad3552r_desc { + /* Used to look the spi bus for atomic operations where needed */ + struct mutex lock; + struct gpio_desc *gpio_reset; + struct gpio_desc *gpio_ldac; + struct spi_device *spi; + struct ad3552r_ch_data ch_data[AD3552R_NUM_CH]; + struct iio_chan_spec channels[AD3552R_NUM_CH + 1]; + unsigned long enabled_ch; + unsigned int num_ch; + enum ad3542r_id chip_id; +}; + +static const u16 addr_mask_map[][2] = { + [AD3552R_ADDR_ASCENSION] = { + AD3552R_REG_ADDR_INTERFACE_CONFIG_A, + AD3552R_MASK_ADDR_ASCENSION + }, + [AD3552R_SDO_DRIVE_STRENGTH] = { + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SDO_DRIVE_STRENGTH + }, + [AD3552R_VREF_SELECT] = { + AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, + AD3552R_MASK_REFERENCE_VOLTAGE_SEL + }, +}; + +/* 0 -> reg addr, 1->ch0 mask, 2->ch1 mask */ +static const u16 addr_mask_map_ch[][3] = { + [AD3552R_CH_DAC_POWERDOWN] = { + AD3552R_REG_ADDR_POWERDOWN_CONFIG, + AD3552R_MASK_CH_DAC_POWERDOWN(0), + AD3552R_MASK_CH_DAC_POWERDOWN(1) + }, + [AD3552R_CH_AMPLIFIER_POWERDOWN] = { + AD3552R_REG_ADDR_POWERDOWN_CONFIG, + AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0), + AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1) + }, + [AD3552R_CH_OUTPUT_RANGE_SEL] = { + AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE, + AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), + AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1) + }, + [AD3552R_CH_SELECT] = { + AD3552R_REG_ADDR_CH_SELECT_16B, + AD3552R_MASK_CH(0), + AD3552R_MASK_CH(1) + } +}; + +static u8 _ad3552r_reg_len(u8 addr) +{ + switch (addr) { + case AD3552R_REG_ADDR_HW_LDAC_16B: + case AD3552R_REG_ADDR_CH_SELECT_16B: + case AD3552R_REG_ADDR_SW_LDAC_16B: + case AD3552R_REG_ADDR_HW_LDAC_24B: + case AD3552R_REG_ADDR_CH_SELECT_24B: + case AD3552R_REG_ADDR_SW_LDAC_24B: + return 1; + default: + break; + } + + if (addr > AD3552R_REG_ADDR_HW_LDAC_24B) + return 3; + if (addr > AD3552R_REG_ADDR_HW_LDAC_16B) + return 2; + + return 1; +} + +/* SPI transfer to device */ +static int ad3552r_transfer(struct ad3552r_desc *dac, u8 addr, u32 len, + u8 *data, bool is_read) +{ + /* Maximum transfer: Addr (1B) + 2 * (Data Reg (3B)) + SW LDAC(1B) */ + u8 buf[8]; + + buf[0] = addr & AD3552R_ADDR_MASK; + buf[0] |= is_read ? AD3552R_READ_BIT : 0; + if (is_read) + return spi_write_then_read(dac->spi, buf, 1, data, len); + + memcpy(buf + 1, data, len); + return spi_write_then_read(dac->spi, buf, len + 1, NULL, 0); +} + +static int ad3552r_write_reg(struct ad3552r_desc *dac, u8 addr, u16 val) +{ + u8 reg_len; + u8 buf[AD3552R_MAX_REG_SIZE] = { 0 }; + + reg_len = _ad3552r_reg_len(addr); + if (reg_len == 2) + /* Only DAC register are 2 bytes wide */ + val &= AD3552R_MASK_DAC_12B; + if (reg_len == 1) + buf[0] = val & 0xFF; + else + /* reg_len can be 2 or 3, but 3rd bytes needs to be set to 0 */ + put_unaligned_be16(val, buf); + + return ad3552r_transfer(dac, addr, reg_len, buf, false); +} + +static int ad3552r_read_reg(struct ad3552r_desc *dac, u8 addr, u16 *val) +{ + int err; + u8 reg_len, buf[AD3552R_MAX_REG_SIZE] = { 0 }; + + reg_len = _ad3552r_reg_len(addr); + err = ad3552r_transfer(dac, addr, reg_len, buf, true); + if (err) + return err; + + if (reg_len == 1) + *val = buf[0]; + else + /* reg_len can be 2 or 3, but only first 2 bytes are relevant */ + *val = get_unaligned_be16(buf); + + return 0; +} + +static u16 ad3552r_field_prep(u16 val, u16 mask) +{ + return (val << __ffs(mask)) & mask; +} + +/* Update field of a register, shift val if needed */ +static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask, + u16 val) +{ + int ret; + u16 reg; + + ret = ad3552r_read_reg(dac, addr, ®); + if (ret < 0) + return ret; + + reg &= ~mask; + reg |= ad3552r_field_prep(val, mask); + + return ad3552r_write_reg(dac, addr, reg); +} + +static int ad3552r_set_ch_value(struct ad3552r_desc *dac, + enum ad3552r_ch_attributes attr, + u8 ch, + u16 val) +{ + /* Update register related to attributes in chip */ + return ad3552r_update_reg_field(dac, addr_mask_map_ch[attr][0], + addr_mask_map_ch[attr][ch + 1], val); +} + +#define AD3552R_CH_DAC(_idx) ((struct iio_chan_spec) { \ + .type = IIO_VOLTAGE, \ + .output = true, \ + .indexed = true, \ + .channel = _idx, \ + .scan_index = _idx, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_ENABLE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ +}) + +static int ad3552r_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct ad3552r_desc *dac = iio_priv(indio_dev); + u16 tmp_val; + int err; + u8 ch = chan->channel; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&dac->lock); + err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_CH_DAC_24B(ch), + &tmp_val); + mutex_unlock(&dac->lock); + if (err < 0) + return err; + *val = tmp_val; + return IIO_VAL_INT; + case IIO_CHAN_INFO_ENABLE: + mutex_lock(&dac->lock); + err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_POWERDOWN_CONFIG, + &tmp_val); + mutex_unlock(&dac->lock); + if (err < 0) + return err; + *val = !((tmp_val & AD3552R_MASK_CH_DAC_POWERDOWN(ch)) >> + __ffs(AD3552R_MASK_CH_DAC_POWERDOWN(ch))); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = dac->ch_data[ch].scale_int; + *val2 = dac->ch_data[ch].scale_dec; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = dac->ch_data[ch].offset_int; + *val2 = dac->ch_data[ch].offset_dec; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int ad3552r_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct ad3552r_desc *dac = iio_priv(indio_dev); + int err; + + mutex_lock(&dac->lock); + switch (mask) { + case IIO_CHAN_INFO_RAW: + err = ad3552r_write_reg(dac, + AD3552R_REG_ADDR_CH_DAC_24B(chan->channel), + val); + break; + case IIO_CHAN_INFO_ENABLE: + err = ad3552r_set_ch_value(dac, AD3552R_CH_DAC_POWERDOWN, + chan->channel, !val); + break; + default: + err = -EINVAL; + break; + } + mutex_unlock(&dac->lock); + + return err; +} + +static const struct iio_info ad3552r_iio_info = { + .read_raw = ad3552r_read_raw, + .write_raw = ad3552r_write_raw +}; + +static int32_t ad3552r_trigger_hw_ldac(struct gpio_desc *ldac) +{ + gpiod_set_value_cansleep(ldac, 0); + usleep_range(AD3552R_LDAC_PULSE_US, AD3552R_LDAC_PULSE_US + 10); + gpiod_set_value_cansleep(ldac, 1); + + return 0; +} + +static int ad3552r_write_all_channels(struct ad3552r_desc *dac, u8 *data) +{ + int err, len; + u8 addr, buff[AD3552R_NUM_CH * AD3552R_MAX_REG_SIZE + 1]; + + addr = AD3552R_REG_ADDR_CH_INPUT_24B(1); + /* CH1 */ + memcpy(buff, data + 2, 2); + buff[2] = 0; + /* CH0 */ + memcpy(buff + 3, data, 2); + buff[5] = 0; + len = 6; + if (!dac->gpio_ldac) { + /* Software LDAC */ + buff[6] = AD3552R_MASK_ALL_CH; + ++len; + } + err = ad3552r_transfer(dac, addr, len, buff, false); + if (err) + return err; + + if (dac->gpio_ldac) + return ad3552r_trigger_hw_ldac(dac->gpio_ldac); + + return 0; +} + +static int ad3552r_write_codes(struct ad3552r_desc *dac, u32 mask, u8 *data) +{ + int err; + u8 addr, buff[AD3552R_MAX_REG_SIZE]; + + if (mask == AD3552R_MASK_ALL_CH) { + if (memcmp(data, data + 2, 2) != 0) + return ad3552r_write_all_channels(dac, data); + + addr = AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B; + } else { + addr = AD3552R_REG_ADDR_CH_INPUT_24B(__ffs(mask)); + } + + memcpy(buff, data, 2); + buff[2] = 0; + err = ad3552r_transfer(dac, addr, 3, data, false); + if (err) + return err; + + if (dac->gpio_ldac) + return ad3552r_trigger_hw_ldac(dac->gpio_ldac); + + return ad3552r_write_reg(dac, AD3552R_REG_ADDR_SW_LDAC_24B, mask); +} + +static irqreturn_t ad3552r_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct iio_buffer *buf = indio_dev->buffer; + struct ad3552r_desc *dac = iio_priv(indio_dev); + /* Maximum size of a scan */ + u8 buff[AD3552R_NUM_CH * AD3552R_MAX_REG_SIZE]; + int err; + + memset(buff, 0, sizeof(buff)); + /* In 5.14 iio_pop_from_buffer is used */ + //err = iio_pop_from_buffer(buf, buff); + err = iio_buffer_remove_sample(buf, buff); + if (err) + goto end; + + mutex_lock(&dac->lock); + ad3552r_write_codes(dac, *indio_dev->active_scan_mask, buff); + mutex_unlock(&dac->lock); +end: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int ad3552r_check_scratch_pad(struct ad3552r_desc *dac) +{ + const u16 val1 = AD3552R_SCRATCH_PAD_TEST_VAL1; + const u16 val2 = AD3552R_SCRATCH_PAD_TEST_VAL2; + u16 val; + int err; + + err = ad3552r_write_reg(dac, AD3552R_REG_ADDR_SCRATCH_PAD, val1); + if (err < 0) + return err; + + err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_SCRATCH_PAD, &val); + if (err < 0) + return err; + + if (val1 != val) + return -ENODEV; + + err = ad3552r_write_reg(dac, AD3552R_REG_ADDR_SCRATCH_PAD, val2); + if (err < 0) + return err; + + err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_SCRATCH_PAD, &val); + if (err < 0) + return err; + + if (val2 != val) + return -ENODEV; + + return 0; +} + +struct reg_addr_pool { + struct ad3552r_desc *dac; + u8 addr; +}; + +static int ad3552r_read_reg_wrapper(struct reg_addr_pool *addr) +{ + int err; + u16 val; + + err = ad3552r_read_reg(addr->dac, addr->addr, &val); + if (err) + return err; + + return val; +} + +static int ad3552r_reset(struct ad3552r_desc *dac) +{ + struct reg_addr_pool addr; + int ret; + u16 val; + + dac->gpio_reset = devm_gpiod_get_optional(&dac->spi->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(dac->gpio_reset)) + return dev_err_probe(&dac->spi->dev, PTR_ERR(dac->gpio_reset), + "Error while getting gpio reset"); + + if (dac->gpio_reset) { + /* Perform hardware reset */ + usleep_range(10, 20); + gpiod_set_value_cansleep(dac->gpio_reset, 1); + } else { + /* Perform software reset if no GPIO provided */ + ret = ad3552r_update_reg_field(dac, + AD3552R_REG_ADDR_INTERFACE_CONFIG_A, + AD3552R_MASK_SOFTWARE_RESET, + AD3552R_MASK_SOFTWARE_RESET); + if (ret < 0) + return ret; + + } + + addr.dac = dac; + addr.addr = AD3552R_REG_ADDR_INTERFACE_CONFIG_B; + ret = readx_poll_timeout(ad3552r_read_reg_wrapper, &addr, val, + val == AD3552R_DEFAULT_CONFIG_B_VALUE || + val < 0, + 5000, 50000); + if (val < 0) + ret = val; + if (ret) { + dev_err(&dac->spi->dev, "Error while resetting"); + return ret; + } + + ret = readx_poll_timeout(ad3552r_read_reg_wrapper, &addr, val, + !(val & AD3552R_MASK_INTERFACE_NOT_READY) || + val < 0, + 5000, 50000); + if (val < 0) + ret = val; + if (ret) { + dev_err(&dac->spi->dev, "Error while resetting"); + return ret; + } + + return ad3552r_update_reg_field(dac, + addr_mask_map[AD3552R_ADDR_ASCENSION][0], + addr_mask_map[AD3552R_ADDR_ASCENSION][1], + val); +} + +static void ad3552r_get_custom_range(struct ad3552r_desc *dac, s32 i, s32 *v_min, + s32 *v_max) +{ + s64 vref, tmp, common, offset, gn, gp; + /* + * From datasheet formula (In Volts): + * Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03] + * Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03] + * Calculus are converted to milivolts + */ + vref = 2500; + /* 2.5 * 1.03 * 1000 (To mV) */ + common = 2575 * dac->ch_data[i].rfb; + offset = dac->ch_data[i].gain_offset; + + gn = gains_scaling_table[dac->ch_data[i].n]; + tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common; + tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); + *v_max = vref + tmp; + + gp = gains_scaling_table[dac->ch_data[i].p]; + tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common; + tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); + *v_min = vref - tmp; +} + +static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch) +{ + s32 idx, v_max, v_min, span, rem; + s64 tmp; + + if (dac->ch_data[ch].range_override) { + ad3552r_get_custom_range(dac, ch, &v_min, &v_max); + } else { + /* Normal range */ + idx = dac->ch_data[ch].range; + if (dac->chip_id == AD3542R_ID) { + v_min = ad3542r_ch_ranges[idx][0]; + v_max = ad3542r_ch_ranges[idx][1]; + } else { + v_min = ad3552r_ch_ranges[idx][0]; + v_max = ad3552r_ch_ranges[idx][1]; + } + } + + /* + * From datasheet formula: + * Vout = Span * (D / 65536) + Vmin + * Converted to scale and offset: + * Scale = Span / 65536 + * Offset = 65536 * Vmin / Span + * + * Reminders are in micros in order to be printed as + * IIO_VAL_INT_PLUS_MICRO + */ + span = v_max - v_min; + dac->ch_data[ch].scale_int = div_s64_rem(span, 65536, &rem); + /* Do operations in microvolts */ + dac->ch_data[ch].scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000, + 65536); + + dac->ch_data[ch].offset_int = div_s64_rem(v_min * 65536, span, &rem); + tmp = (s64)rem * 1000000; + dac->ch_data[ch].offset_dec = div_s64(tmp, span); +} + +static int ad3552r_find_range(u16 id, s32 *vals) +{ + int i, len; + const s32 (*ranges)[2]; + + if (id == AD3542R_ID) { + len = ARRAY_SIZE(ad3542r_ch_ranges); + ranges = ad3542r_ch_ranges; + } else { + len = ARRAY_SIZE(ad3552r_ch_ranges); + ranges = ad3552r_ch_ranges; + } + + for (i = 0; i < len; i++) + if (vals[0] == ranges[i][0] * 1000 && + vals[1] == ranges[i][1] * 1000) + return i; + + return -EINVAL; +} + +static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, + struct fwnode_handle *child, + u32 ch) +{ + struct device *dev = &dac->spi->dev; + struct fwnode_handle *gain_child; + u32 val; + int err; + u8 addr; + u16 reg = 0, offset; + + gain_child = fwnode_get_named_child_node(child, + "custom-output-range-config"); + if (IS_ERR(gain_child)) { + dev_err(dev, + "mandatory custom-output-range-config property missing\n"); + return PTR_ERR(gain_child); + } + + dac->ch_data[ch].range_override = 1; + reg |= ad3552r_field_prep(1, AD3552R_MASK_CH_RANGE_OVERRIDE); + + err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val); + if (err) { + dev_err(dev, "mandatory adi,gain-scaling-p property missing\n"); + goto put_child; + } + reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_P); + dac->ch_data[ch].p = val; + + err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val); + if (err) { + dev_err(dev, "mandatory adi,gain-scaling-n property missing\n"); + goto put_child; + } + reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_N); + dac->ch_data[ch].n = val; + + err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val); + if (err) { + dev_err(dev, "mandatory adi,rfb-ohms property missing\n"); + goto put_child; + } + dac->ch_data[ch].rfb = val; + + err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val); + if (err) { + dev_err(dev, "mandatory adi,gain-offset property missing\n"); + goto put_child; + } + dac->ch_data[ch].gain_offset = val; + + offset = abs((s32)val); + reg |= ad3552r_field_prep((offset >> 8), AD3552R_MASK_CH_OFFSET_BIT_8); + + reg |= ad3552r_field_prep((s32)val < 0, AD3552R_MASK_CH_OFFSET_POLARITY); + addr = AD3552R_REG_ADDR_CH_GAIN(ch); + err = ad3552r_write_reg(dac, addr, + offset & AD3552R_MASK_CH_OFFSET_BITS_0_7); + if (err) { + dev_err(dev, "Error writing register\n"); + goto put_child; + } + + err = ad3552r_write_reg(dac, addr, reg); + if (err) { + dev_err(dev, "Error writing register\n"); + goto put_child; + } + +put_child: + fwnode_handle_put(gain_child); + + return err; +} + +static void ad3552r_reg_disable(void *reg) +{ + regulator_disable(reg); +} + +static int ad3552r_configure_device(struct ad3552r_desc *dac) +{ + struct device *dev = &dac->spi->dev; + struct fwnode_handle *child; + struct regulator *vref; + int err, cnt = 0, voltage, delta = 100000; + u32 vals[2], val, ch; + + dac->gpio_ldac = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH); + if (IS_ERR(dac->gpio_ldac)) + return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac), + "Error getting gpio ldac"); + + vref = devm_regulator_get_optional(dev, "vref"); + if (IS_ERR(vref)) { + if (PTR_ERR(vref) != -ENODEV) + return dev_err_probe(dev, PTR_ERR(vref), + "Error getting vref"); + + if (device_property_read_bool(dev, "adi,vref-out-en")) + val = AD3552R_INTERNAL_VREF_PIN_2P5V; + else + val = AD3552R_INTERNAL_VREF_PIN_FLOATING; + } else { + err = regulator_enable(vref); + if (err) { + dev_err(dev, "Failed to enable external vref supply\n"); + return err; + } + + err = devm_add_action_or_reset(dev, ad3552r_reg_disable, vref); + if (err) { + regulator_disable(vref); + return err; + } + + voltage = regulator_get_voltage(vref); + if (voltage > 2500000 + delta || voltage < 2500000 - delta) { + dev_warn(dev, "vref-supply must be 2.5V"); + return -EINVAL; + } + val = AD3552R_EXTERNAL_VREF_PIN_INPUT; + } + + err = ad3552r_update_reg_field(dac, + addr_mask_map[AD3552R_VREF_SELECT][0], + addr_mask_map[AD3552R_VREF_SELECT][1], + val); + if (err) + return err; + + err = device_property_read_u32(dev, "adi,sdo-drive-strength", &val); + if (!err) { + if (val > 3) { + dev_err(dev, "adi,sdo-drive-strength must be less than 4\n"); + return -EINVAL; + } + + err = ad3552r_update_reg_field(dac, + addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][0], + addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][1], + val); + if (err) + return err; + } + + dac->num_ch = device_get_child_node_count(dev); + if (!dac->num_ch) { + dev_err(dev, "No channels defined\n"); + return -ENODEV; + } + + device_for_each_child_node(dev, child) { + err = fwnode_property_read_u32(child, "reg", &ch); + if (err) { + dev_err(dev, "mandatory reg property missing\n"); + goto put_child; + } + if (ch >= AD3552R_NUM_CH) { + dev_err(dev, "reg must be less than %d\n", + AD3552R_NUM_CH); + err = -EINVAL; + goto put_child; + } + + if (fwnode_property_present(child, "adi,output-range-microvolt")) { + err = fwnode_property_read_u32_array(child, + "adi,output-range-microvolt", + vals, + 2); + if (err) { + dev_err(dev, + "failed to parse adi,output-range-microvolt\n"); + goto put_child; + } + + err = ad3552r_find_range(dac->chip_id, vals); + if (err < 0) { + dev_err(dev, + "Invalid adi,output-range-microvolt value\n"); + goto put_child; + } + val = err; + err = ad3552r_set_ch_value(dac, + AD3552R_CH_OUTPUT_RANGE_SEL, + ch, val); + if (err) + goto put_child; + + dac->ch_data[ch].range = val; + } else if (dac->chip_id == AD3542R_ID) { + dev_err(dev, + "adi,output-range-microvolt is required for ad3542r\n"); + err = -EINVAL; + goto put_child; + } else { + err = ad3552r_configure_custom_gain(dac, child, ch); + if (err) + goto put_child; + } + + ad3552r_calc_gain_and_offset(dac, ch); + dac->enabled_ch |= BIT(ch); + + err = ad3552r_set_ch_value(dac, AD3552R_CH_SELECT, ch, 1); + if (err < 0) + goto put_child; + + dac->channels[cnt] = AD3552R_CH_DAC(ch); + ++cnt; + + } + + /* Disable unused channels */ + for_each_clear_bit(ch, &dac->enabled_ch, AD3552R_NUM_CH) { + err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN, + ch, 1); + if (err) + return err; + } + + dac->num_ch = cnt; + + return 0; +put_child: + fwnode_handle_put(child); + + return err; +} + +static int ad3552r_init(struct ad3552r_desc *dac) +{ + int err; + u16 val, id; + + err = ad3552r_reset(dac); + if (err) { + dev_err(&dac->spi->dev, "Reset failed\n"); + return err; + } + + err = ad3552r_check_scratch_pad(dac); + if (err) { + dev_err(&dac->spi->dev, "Scratch pad test failed\n"); + return err; + } + + err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_PRODUCT_ID_L, &val); + if (err) { + dev_err(&dac->spi->dev, "Fail read PRODUCT_ID_L\n"); + return err; + } + + id = val; + err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_PRODUCT_ID_H, &val); + if (err) { + dev_err(&dac->spi->dev, "Fail read PRODUCT_ID_H\n"); + return err; + } + + id |= val << 8; + if (id != dac->chip_id) { + dev_err(&dac->spi->dev, "Product id not matching\n"); + return -ENODEV; + } + + return ad3552r_configure_device(dac); +} + +static int ad3552r_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct ad3552r_desc *dac; + struct iio_dev *indio_dev; + int err; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*dac)); + if (!indio_dev) + return -ENOMEM; + + dac = iio_priv(indio_dev); + dac->spi = spi; + dac->chip_id = id->driver_data; + + mutex_init(&dac->lock); + + err = ad3552r_init(dac); + if (err) + return err; + + /* Config triggered buffer device */ + if (dac->chip_id == AD3552R_ID) + indio_dev->name = "ad3552r"; + else + indio_dev->name = "ad3542r"; + indio_dev->dev.parent = &spi->dev; + indio_dev->info = &ad3552r_iio_info; + indio_dev->num_channels = dac->num_ch; + indio_dev->channels = dac->channels; + indio_dev->modes = INDIO_DIRECT_MODE; + /* indio_dev->direction don't exist in 5.14 */ + indio_dev->direction = IIO_DEVICE_DIRECTION_OUT; + + /* In 5.14 devm_iio_triggered_buffer_setup_ext is used */ + //err = devm_iio_triggered_buffer_setup_ext(&indio_dev->dev, indio_dev, NULL, + // &ad3552r_trigger_handler, + // IIO_BUFFER_DIRECTION_OUT, + // NULL, + // NULL); + err = devm_iio_triggered_buffer_setup(&indio_dev->dev, indio_dev, NULL, + &ad3552r_trigger_handler, NULL); + if (err) + return err; + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct spi_device_id ad3552r_id[] = { + { "ad3542r", AD3542R_ID }, + { "ad3552r", AD3552R_ID }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad3552r_id); + +static const struct of_device_id ad3552r_of_match[] = { + { .compatible = "adi,ad3542r"}, + { .compatible = "adi,ad3552r"}, + { } +}; +MODULE_DEVICE_TABLE(of, ad3552r_of_match); + +static struct spi_driver ad3552r_driver = { + .driver = { + .name = "ad3552r", + .of_match_table = ad3552r_of_match, + }, + .probe = ad3552r_probe, + .id_table = ad3552r_id +}; +module_spi_driver(ad3552r_driver); + +MODULE_AUTHOR("Mihail Chindris "); +MODULE_DESCRIPTION("Analog Device AD3552R DAC"); +MODULE_LICENSE("GPL v2"); From a0671512357d8fccd86450b6c0c2d0aa8903982d Mon Sep 17 00:00:00 2001 From: Mihail Chindris Date: Tue, 16 Nov 2021 15:43:37 +0000 Subject: [PATCH 054/407] drivers:iio:Kconfig.adi: Add ad3552r driver Add driver to IIO_ALL_ADI_DRIVERS to build the driver with all other ADI devices Signed-off-by: Mihail Chindris --- drivers/iio/Kconfig.adi | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/Kconfig.adi b/drivers/iio/Kconfig.adi index 014433c05f47b6..ba97d1b21210d8 100644 --- a/drivers/iio/Kconfig.adi +++ b/drivers/iio/Kconfig.adi @@ -79,6 +79,7 @@ config IIO_ALL_ADI_DRIVERS select AD5380 select AD5421 select AD5624R_SPI if SPI + select AD3552R select AD5064 select AD5504 select AD5446 From f7504378dfd12dffc46ca2ae3feb4a98b545e672 Mon Sep 17 00:00:00 2001 From: Laszlo Nagy Date: Tue, 9 Nov 2021 07:42:54 +0000 Subject: [PATCH 055/407] arch: microblaze: dts: vcu128: FPGA carrier support for VCU128 This patch adds support for the Virtex UltraScale+ HBM VCU128 FPGA Evaluation Kit: - https://www.xilinx.com/products/boards-and-kits/vcu128.html Signed-off-by: Laszlo Nagy Signed-off-by: Michael Hennerich --- arch/microblaze/boot/dts/vcu128.dts | 4 + arch/microblaze/boot/dts/vcu128.dtsi | 418 +++++++++++++++++++++++++++ 2 files changed, 422 insertions(+) create mode 100644 arch/microblaze/boot/dts/vcu128.dts create mode 100644 arch/microblaze/boot/dts/vcu128.dtsi diff --git a/arch/microblaze/boot/dts/vcu128.dts b/arch/microblaze/boot/dts/vcu128.dts new file mode 100644 index 00000000000000..9d9704628b64ca --- /dev/null +++ b/arch/microblaze/boot/dts/vcu128.dts @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 + +/dts-v1/; +#include "vcu128.dtsi" diff --git a/arch/microblaze/boot/dts/vcu128.dtsi b/arch/microblaze/boot/dts/vcu128.dtsi new file mode 100644 index 00000000000000..b932c0f3db67f6 --- /dev/null +++ b/arch/microblaze/boot/dts/vcu128.dtsi @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,microblaze"; + model = "Xilinx MicroBlaze"; + chosen { + bootargs = "earlycon"; + stdout-path = "serial0:115200n8"; + }; + aliases { + ethernet0 = &axi_ethernet_0; + i2c0 = &axi_iic_main; + serial0 = &axi_uart; + serial1 = &sys_mb_debug; + spi0 = &axi_spi; + }; + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x80000000>; + }; + cpus { + #address-cells = <1>; + #cpus = <1>; + #size-cells = <0>; + sys_mb: cpu@0 { + bus-handle = <&amba_pl>; + clock-frequency = <100000000>; + clocks = <&clk_cpu>; + compatible = "xlnx,microblaze-11.0"; + d-cache-baseaddr = <0x80000000>; + d-cache-highaddr = <0xffffffff>; + d-cache-line-size = <0x10>; + d-cache-size = <0x4000>; + device_type = "cpu"; + i-cache-baseaddr = <0x80000000>; + i-cache-highaddr = <0xffffffff>; + i-cache-line-size = <0x20>; + i-cache-size = <0x4000>; + interrupt-handle = <&axi_intc>; + model = "microblaze,11.0"; + reg = <0>; + timebase-frequency = <100000000>; + xlnx,addr-size = <0x20>; + xlnx,addr-tag-bits = <0x11>; + xlnx,allow-dcache-wr = <0x1>; + xlnx,allow-icache-wr = <0x1>; + xlnx,area-optimized = <0x0>; + xlnx,async-interrupt = <0x1>; + xlnx,async-wakeup = <0x3>; + xlnx,avoid-primitives = <0x0>; + xlnx,base-vectors = <0x00000000 0x00000000>; + xlnx,branch-target-cache-size = <0x0>; + xlnx,cache-byte-size = <0x4000>; + xlnx,d-axi = <0x1>; + xlnx,d-lmb = <0x1>; + xlnx,d-lmb-mon = <0x0>; + xlnx,d-lmb-protocol = <0x0>; + xlnx,daddr-size = <0x20>; + xlnx,data-size = <0x20>; + xlnx,dc-axi-mon = <0x0>; + xlnx,dcache-addr-tag = <0x11>; + xlnx,dcache-always-used = <0x1>; + xlnx,dcache-byte-size = <0x4000>; + xlnx,dcache-data-width = <0x0>; + xlnx,dcache-force-tag-lutram = <0x0>; + xlnx,dcache-line-len = <0x4>; + xlnx,dcache-use-writeback = <0x0>; + xlnx,dcache-victims = <0x8>; + xlnx,debug-counter-width = <0x20>; + xlnx,debug-enabled = <0x1>; + xlnx,debug-event-counters = <0x5>; + xlnx,debug-external-trace = <0x0>; + xlnx,debug-interface = <0x0>; + xlnx,debug-latency-counters = <0x1>; + xlnx,debug-profile-size = <0x0>; + xlnx,debug-trace-async-reset = <0x0>; + xlnx,debug-trace-size = <0x2000>; + xlnx,div-zero-exception = <0x1>; + xlnx,dp-axi-mon = <0x0>; + xlnx,dynamic-bus-sizing = <0x0>; + xlnx,ecc-use-ce-exception = <0x0>; + xlnx,edge-is-positive = <0x1>; + xlnx,enable-discrete-ports = <0x0>; + xlnx,endianness = <0x1>; + xlnx,fault-tolerant = <0x0>; + xlnx,fpu-exception = <0x0>; + xlnx,freq = <0x5f5e100>; + xlnx,fsl-exception = <0x0>; + xlnx,fsl-links = <0x0>; + xlnx,i-axi = <0x0>; + xlnx,i-lmb = <0x1>; + xlnx,i-lmb-mon = <0x0>; + xlnx,i-lmb-protocol = <0x0>; + xlnx,iaddr-size = <0x20>; + xlnx,ic-axi-mon = <0x0>; + xlnx,icache-always-used = <0x1>; + xlnx,icache-data-width = <0x0>; + xlnx,icache-force-tag-lutram = <0x0>; + xlnx,icache-line-len = <0x8>; + xlnx,icache-streams = <0x1>; + xlnx,icache-victims = <0x8>; + xlnx,ill-opcode-exception = <0x1>; + xlnx,imprecise-exceptions = <0x0>; + xlnx,instr-size = <0x20>; + xlnx,interconnect = <0x2>; + xlnx,interrupt-is-edge = <0x0>; + xlnx,interrupt-mon = <0x0>; + xlnx,ip-axi-mon = <0x0>; + xlnx,lmb-data-size = <0x20>; + xlnx,lockstep-master = <0x0>; + xlnx,lockstep-select = <0x0>; + xlnx,lockstep-slave = <0x0>; + xlnx,mmu-dtlb-size = <0x4>; + xlnx,mmu-itlb-size = <0x2>; + xlnx,mmu-privileged-instr = <0x0>; + xlnx,mmu-tlb-access = <0x3>; + xlnx,mmu-zones = <0x2>; + xlnx,num-sync-ff-clk = <0x2>; + xlnx,num-sync-ff-clk-debug = <0x2>; + xlnx,num-sync-ff-clk-irq = <0x1>; + xlnx,num-sync-ff-dbg-clk = <0x1>; + xlnx,num-sync-ff-dbg-trace-clk = <0x2>; + xlnx,number-of-pc-brk = <0x1>; + xlnx,number-of-rd-addr-brk = <0x0>; + xlnx,number-of-wr-addr-brk = <0x0>; + xlnx,opcode-0x0-illegal = <0x1>; + xlnx,optimization = <0x0>; + xlnx,pc-width = <0x20>; + xlnx,piaddr-size = <0x20>; + xlnx,pvr = <0x2>; + xlnx,pvr-user1 = <0x00>; + xlnx,pvr-user2 = <0x00000000>; + xlnx,reset-msr = <0x00000000>; + xlnx,reset-msr-bip = <0x0>; + xlnx,reset-msr-dce = <0x0>; + xlnx,reset-msr-ee = <0x0>; + xlnx,reset-msr-eip = <0x0>; + xlnx,reset-msr-ice = <0x0>; + xlnx,reset-msr-ie = <0x0>; + xlnx,sco = <0x0>; + xlnx,trace = <0x0>; + xlnx,unaligned-exceptions = <0x1>; + xlnx,use-barrel = <0x1>; + xlnx,use-branch-target-cache = <0x0>; + xlnx,use-config-reset = <0x0>; + xlnx,use-dcache = <0x1>; + xlnx,use-div = <0x1>; + xlnx,use-ext-brk = <0x0>; + xlnx,use-ext-nm-brk = <0x0>; + xlnx,use-extended-fsl-instr = <0x0>; + xlnx,use-fpu = <0x0>; + xlnx,use-hw-mul = <0x2>; + xlnx,use-icache = <0x1>; + xlnx,use-interrupt = <0x1>; + xlnx,use-mmu = <0x3>; + xlnx,use-msr-instr = <0x1>; + xlnx,use-non-secure = <0x0>; + xlnx,use-pcmp-instr = <0x1>; + xlnx,use-reorder-instr = <0x1>; + xlnx,use-stack-protection = <0x0>; + }; + }; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clk_cpu: clk_cpu@0 { + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "clk_cpu"; + compatible = "fixed-clock"; + reg = <0>; + }; + clk_bus_0: clk_bus_0@1 { + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "clk_bus_0"; + compatible = "fixed-clock"; + reg = <1>; + }; + }; + amba_pl: amba_pl { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges ; + axi_ddr_cntrl: ddr4@45100000 { + compatible = "xlnx,ddr4-2.2"; + reg = <0x45100000 0x1000>; + }; + axi_ethernet_0: ethernet@40c00000 { + axistream-connected = <&axi_ethernet_dma>; + axistream-control-connected = <&axi_ethernet_dma>; + clock-frequency = <100000000>; + clocks = <&clk_bus_0>; + compatible = "xlnx,axi-ethernet-7.2", "xlnx,axi-ethernet-1.00.a"; + device_type = "network"; + interrupt-names = "interrupt"; + interrupt-parent = <&axi_intc>; + interrupts = <1 2>; + local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy1>; + phy-mode = "sgmii"; + reg = <0x40c00000 0x40000>; + xlnx = <0x0>; + xlnx,axiliteclkrate = <0x0>; + xlnx,axisclkrate = <0x0>; + xlnx,channel-ids = <0x1>; + xlnx,clockselection = <0x0>; + xlnx,enableasyncsgmii = <0x0>; + xlnx,gt-type = <0x0>; + xlnx,gtinex = <0x0>; + xlnx,gtlocation = <0x0>; + xlnx,gtrefclksrc = <0x0>; + xlnx,include-dre ; + xlnx,instantiatebitslice0 = <0x1>; + xlnx,num-queues = /bits/ 16 <0x1>; + xlnx,phyaddr = <0x1>; + xlnx,phyrst-board-interface-dummy-port = <0x0>; + xlnx,rable = <0x0>; + xlnx,rxcsum = <0x2>; + xlnx,rxlane0-placement = <0x0>; + xlnx,rxlane1-placement = <0x0>; + xlnx,rxmem = <0x2000>; + xlnx,rxnibblebitslice0used = <0x0>; + xlnx,tx-in-upper-nibble = <0x1>; + xlnx,txcsum = <0x2>; + xlnx,txlane0-placement = <0x0>; + xlnx,txlane1-placement = <0x0>; + xlnx,versal-gt-board-flow = <0x0>; + axi_ethernet_0_mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + phy1: phy@3 { + reg = <3>; + device_type = "ethernet-phy"; + ti,sgmii-ref-clock-output-enable; + ti,dp83867-rxctrl-strap-quirk; + ti,rx-internal-delay = <0x8>; + ti,tx-internal-delay = <0xa>; + ti,fifo-depth = <0x1>; + }; + }; + }; + axi_ethernet_dma: dma@41e10000 { + #dma-cells = <1>; + axistream-connected = <&axi_ethernet_0>; + axistream-control-connected = <&axi_ethernet_0>; + clock-frequency = <100000000>; + clock-names = "s_axi_lite_aclk"; + clocks = <&clk_bus_0>; + compatible = "xlnx,eth-dma"; + interrupt-names = "mm2s_introut", "s2mm_introut"; + interrupt-parent = <&axi_intc>; + interrupts = <2 2 3 2>; + reg = <0x41e10000 0x1000>; + xlnx,addrwidth = /bits/ 8 <0x20>; + xlnx,include-dre ; + xlnx,num-queues = /bits/ 16 <0x1>; + }; + axi_gpio: gpio@40000000 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + clock-frequency = <100000000>; + clock-names = "s_axi_aclk"; + clocks = <&clk_bus_0>; + compatible = "xlnx,axi-gpio-2.0", "xlnx,xps-gpio-1.00.a"; + gpio-controller ; + interrupt-controller ; + interrupt-names = "ip2intc_irpt"; + interrupt-parent = <&axi_intc>; + interrupts = <11 2>; + reg = <0x40000000 0x1000>; + xlnx,all-inputs = <0x0>; + xlnx,all-inputs-2 = <0x0>; + xlnx,all-outputs = <0x0>; + xlnx,all-outputs-2 = <0x0>; + xlnx,dout-default = <0x00000000>; + xlnx,dout-default-2 = <0x00000000>; + xlnx,gpio-width = <0x20>; + xlnx,gpio2-width = <0x20>; + xlnx,interrupt-present = <0x1>; + xlnx,is-dual = <0x1>; + xlnx,tri-default = <0xFFFFFFFF>; + xlnx,tri-default-2 = <0xFFFFFFFF>; + }; + axi_iic_main: i2c@41600000 { + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000000>; + clocks = <&clk_bus_0>; + compatible = "xlnx,axi-iic-2.1", "xlnx,xps-iic-2.00.a"; + interrupt-names = "iic2intc_irpt"; + interrupt-parent = <&axi_intc>; + interrupts = <9 2>; + reg = <0x41600000 0x1000>; + + tca6416_u65:gpio@20 { + compatible = "ti,tca6416"; + reg = <0x20>; + //gpio-controller; /* IRQ not connected */ + #gpio-cells = <2>; + gpio-line-names = "MAX6643_OT_B", "MAX6643_FANFAIL_B", + "VCCINT_VCCBRAM_HOT_N", "PMIC_INTR", + "SI5328_INT_ALM", "IIC_MUX_RESET_B", + "GEM3_EXP_RESET_B", "MAX6643_FULL_SPEED", + "", "", "", "", "", "", "", ""; + }; + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + fmcp_hspc_iic: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + eeprom@50 { + compatible = "at24,24c02"; + reg = <0x50>; + }; + }; + }; + }; + axi_intc: interrupt-controller@41200000 { + #interrupt-cells = <2>; + compatible = "xlnx,axi-intc-4.1", "xlnx,xps-intc-1.00.a"; + interrupt-controller ; + reg = <0x41200000 0x1000>; + xlnx,kind-of-intr = <0x5f0>; + xlnx,num-intr-inputs = <0x10>; + }; + axi_spi: spi@44a70000 { + #address-cells = <1>; + #size-cells = <0>; + bits-per-word = <8>; + compatible = "xlnx,axi-quad-spi-3.2", "xlnx,xps-spi-2.00.a"; + fifo-size = <16>; + interrupt-names = "ip2intc_irpt"; + interrupt-parent = <&axi_intc>; + interrupts = <10 0>; + num-cs = <0x8>; + reg = <0x44a70000 0x1000>; + xlnx,num-ss-bits = <0x8>; + xlnx,spi-mode = <0>; + }; + axi_timer: timer@41c00000 { + clock-frequency = <100000000>; + clocks = <&clk_bus_0>; + compatible = "xlnx,axi-timer-2.0", "xlnx,xps-timer-1.00.a"; + interrupt-names = "interrupt"; + interrupt-parent = <&axi_intc>; + interrupts = <0 2>; + reg = <0x41c00000 0x1000>; + xlnx,count-width = <0x20>; + xlnx,gen0-assert = <0x1>; + xlnx,gen1-assert = <0x1>; + xlnx,one-timer-only = <0x0>; + xlnx,trig0-assert = <0x1>; + xlnx,trig1-assert = <0x1>; + }; + axi_uart: serial@40600000 { + clock-frequency = <100000000>; + clocks = <&clk_bus_0>; + compatible = "xlnx,axi-uartlite-2.0", "xlnx,xps-uartlite-1.00.a"; + current-speed = <115200>; + device_type = "serial"; + interrupt-names = "interrupt"; + interrupt-parent = <&axi_intc>; + interrupts = <4 0>; + port-number = <0>; + reg = <0x40600000 0x1000>; + xlnx,baudrate = <0x1c200>; + xlnx,data-bits = <0x8>; + xlnx,odd-parity = <0x0>; + xlnx,s-axi-aclk-freq-hz-d = "100.0"; + xlnx,use-parity = <0x0>; + }; + sys_mb_debug: serial@41400000 { + clock-frequency = <100000000>; + clocks = <&clk_bus_0>; + compatible = "xlnx,mdm-3.2", "xlnx,xps-uartlite-1.00.a"; + device_type = "serial"; + port-number = <1>; + reg = <0x41400000 0x1000>; + xlnx,addr-size = <0x20>; + xlnx,avoid-primitives = <0x0>; + xlnx,brk = <0x0>; + xlnx,bscanid = <0x4900500>; + xlnx,data-size = <0x20>; + xlnx,dbg-mem-access = <0x0>; + xlnx,dbg-reg-access = <0x0>; + xlnx,debug-interface = <0x0>; + xlnx,ext-trig-reset-value = <0xF1234>; + xlnx,interconnect = <0x2>; + xlnx,jtag-chain = <0x2>; + xlnx,lmb-protocol = <0x0>; + xlnx,mb-dbg-ports = <0x1>; + xlnx,trace-async-reset = <0x0>; + xlnx,trace-clk-out-phase = <0x5a>; + xlnx,trace-data-width = <0x20>; + xlnx,trace-id = <0x6e>; + xlnx,trace-output = <0x0>; + xlnx,trace-protocol = <0x1>; + xlnx,trig-in-ports = <0x1>; + xlnx,trig-out-ports = <0x1>; + xlnx,use-bscan = <0x0>; + xlnx,use-config-reset = <0x0>; + xlnx,use-cross-trigger = <0x0>; + xlnx,use-uart = <0x1>; + xlnx,xmtc = <0x0>; + }; + }; +}; From b0db96e0fb77ff8883573caf7cdfd485cc0704e6 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 20 Dec 2021 08:55:43 +0100 Subject: [PATCH 056/407] arch: microblaze: dts: vcu128_ad9081.dts: Support for AD9081 on VCU128 This adds support for the AD9081-FMCA-EBZ on VCU128 (Virtex UltraScale+ HBM VCU128 FPGA Evaluation Kit) Signed-off-by: Laszlo Nagy Signed-off-by: Michael Hennerich --- arch/microblaze/boot/dts/vcu128_ad9081.dts | 217 ++++++++++++++ .../boot/dts/vcu128_ad9081_m8_l4.dts | 268 ++++++++++++++++++ 2 files changed, 485 insertions(+) create mode 100644 arch/microblaze/boot/dts/vcu128_ad9081.dts create mode 100644 arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts diff --git a/arch/microblaze/boot/dts/vcu128_ad9081.dts b/arch/microblaze/boot/dts/vcu128_ad9081.dts new file mode 100644 index 00000000000000..96cc4874b6ee1e --- /dev/null +++ b/arch/microblaze/boot/dts/vcu128_ad9081.dts @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD9081-FMC-EBZ + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 + * https://wiki.analog.com/resources/eval/user-guides/ad9081_fmca_ebz/ad9081_fmca_ebz_hdl + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2021 Analog Devices Inc. + */ +/dts-v1/; + +#include "vcu128.dtsi" +#include +#include + +#define fmc_i2c fmcp_hspc_iic +#define fmc_spi axi_spi + +/ { + model = "Analog Devices AD9081-FMCA-EBZ @Xilinx/vcu128"; +}; + +/* ad9081_fmca_ebz_vcu128: updated master */ +&axi_intc { + xlnx,kind-of-intr = <0xffff05f0>; +}; + +&axi_ethernet_0 { + local-mac-address = [00 0a 35 01 90 81]; +}; + +&amba_pl { + rx_dma: dma@7c420000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x7c420000 0x10000>; + #dma-cells = <1>; + #clock-cells = <0>; + interrupt-parent = <&axi_intc>; + interrupts = <12 2>; + + clocks = <&clk_bus_0>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <256>; + adi,source-bus-type = <2>; + adi,destination-bus-width = <256>; + adi,destination-bus-type = <0>; + }; + }; + }; + + tx_dma: dma@7c430000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x7c430000 0x10000>; + #dma-cells = <1>; + #clock-cells = <0>; + interrupt-parent = <&axi_intc>; + interrupts = <13 2>; + clocks = <&clk_bus_0>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <256>; + adi,source-bus-type = <0>; + adi,destination-bus-width = <256>; + adi,destination-bus-type = <2>; + }; + }; + }; + + axi_ad9081_core_rx: axi-ad9081-rx-hpc@44a10000 { + compatible = "adi,axi-ad9081-rx-1.0"; + reg = <0x44a10000 0x8000>; + dmas = <&rx_dma 0>; + dma-names = "rx"; + spibus-connected = <&trx0_ad9081>; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9081_rx_jesd 0 FRAMER_LINK0_RX>; + }; + + axi_ad9081_core_tx: axi-ad9081-tx-hpc@44b10000 { + compatible = "adi,axi-ad9081-tx-1.0"; + reg = <0x44b10000 0x4000>; + dmas = <&tx_dma 0>; + dma-names = "tx"; + clocks = <&trx0_ad9081 1>; + clock-names = "sampl_clk"; + spibus-connected = <&trx0_ad9081>; + adi,axi-pl-fifo-enable; + adi,axi-data-offload-connected = <&axi_data_offload_tx>; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9081_tx_jesd 0 DEFRAMER_LINK0_TX>; + }; + + axi_ad9081_rx_jesd: axi-jesd204-rx@44a90000 { + compatible = "adi,axi-jesd204-rx-1.0"; + reg = <0x44a90000 0x4000>; + interrupt-parent = <&axi_intc>; + interrupts = <14 2>; + + clocks = <&clk_bus_0>, <&axi_ad9081_adxcvr_rx 1>, <&hmc7044 8>, <&axi_ad9081_adxcvr_rx 0>; + clock-names = "s_axi_aclk", "link_clk", "device_clk", "lane_clk"; + + #clock-cells = <0>; + clock-output-names = "jesd_rx_lane_clk"; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9081_adxcvr_rx 0 FRAMER_LINK0_RX>; + }; + + axi_ad9081_tx_jesd: axi-jesd204-tx@44b90000 { + compatible = "adi,axi-jesd204-tx-1.0"; + reg = <0x44b90000 0x4000>; + + interrupt-parent = <&axi_intc>; + interrupts = <15 2>; + + clocks = <&clk_bus_0>, <&axi_ad9081_adxcvr_tx 1>, <&hmc7044 6>, <&axi_ad9081_adxcvr_tx 0>; + clock-names = "s_axi_aclk", "link_clk", "device_clk", "lane_clk"; + + #clock-cells = <0>; + clock-output-names = "jesd_tx_lane_clk"; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9081_adxcvr_tx 0 DEFRAMER_LINK0_TX>; + }; + + axi_ad9081_adxcvr_rx: axi-adxcvr-rx@44a60000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,axi-adxcvr-1.0"; + reg = <0x44a60000 0x1000>; + + clocks = <&hmc7044 12>; /* div40 is controlled by axi_ad9081_rx_jesd */ + clock-names = "conv"; + + #clock-cells = <1>; + clock-output-names = "rx_gt_clk", "rx_out_clk"; + + adi,sys-clk-select = ; + adi,out-clk-select = ; + adi,use-lpm-enable; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&hmc7044 0 FRAMER_LINK0_RX>; + }; + + axi_ad9081_adxcvr_tx: axi-adxcvr-tx@44b60000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,axi-adxcvr-1.0"; + reg = <0x44b60000 0x1000>; + + clocks = <&hmc7044 12>; /* div40 is controlled by axi_ad9081_tx_jesd */ + clock-names = "conv"; + + #clock-cells = <1>; + clock-output-names = "tx_gt_clk", "tx_out_clk"; + + adi,sys-clk-select = ; + adi,out-clk-select = ; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&hmc7044 0 DEFRAMER_LINK0_TX>; + }; + + axi_sysid_0: axi-sysid-0@45000000 { + compatible = "adi,axi-sysid-1.00.a"; + reg = <0x45000000 0x10000>; + }; + + axi_data_offload_rx: data_offload@7c450000 { + compatible = "adi,axi-data-offload-1.0.a"; + reg = <0x7c450000 0x10000>; + }; + + axi_data_offload_tx: data_offload@7c440000 { + compatible = "adi,axi-data-offload-1.0.a"; + reg = <0x7c440000 0x10000>; + }; +}; + +#include "adi-ad9081-fmc-ebz.dtsi" + +&trx0_ad9081 { + reset-gpios = <&axi_gpio 55 0>; + irqb0-gpios = <&axi_gpio 52 0>; + irqb1-gpios = <&axi_gpio 53 0>; + sysref-req-gpios = <&axi_gpio 43 0>; + rx2-enable-gpios = <&axi_gpio 57 0>; + rx1-enable-gpios = <&axi_gpio 56 0>; + tx2-enable-gpios = <&axi_gpio 59 0>; + tx1-enable-gpios = <&axi_gpio 58 0>; +}; + +&axi_ad9081_core_tx { + plddrbypass-gpios = <&axi_gpio 60 0>; +}; diff --git a/arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts b/arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts new file mode 100644 index 00000000000000..c5bfec03637e73 --- /dev/null +++ b/arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD9081-FMC-EBZ + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 + * https://wiki.analog.com/resources/eval/user-guides/ad9081_fmca_ebz/ad9081_fmca_ebz_hdl + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2019-2020 Analog Devices Inc. + */ + +#include "vcu128_ad9081.dts" + +&rx_dma { + adi,channels { + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <128>; /* Needs to be 32 * JESD_L */ + adi,source-bus-type = <2>; + adi,destination-bus-width = <128>; /* Needs to be 32 * JESD_L */ + adi,destination-bus-type = <0>; + }; + }; +}; + +&tx_dma { + adi,channels { + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <128>; /* Needs to be 32 * JESD_L */ + adi,source-bus-type = <0>; + adi,destination-bus-width = <128>; /* Needs to be 32 * JESD_L */ + adi,destination-bus-type = <2>; + }; + }; +}; + +&axi_ad9081_adxcvr_rx { + adi,sys-clk-select = ; +}; + +&hmc7044 { + + adi,pll2-output-frequency = <3000000000>; + + hmc7044_c0: channel@0 { + reg = <0>; + adi,extended-name = "CORE_CLK_RX"; + adi,divider = <12>; // 387.5 + adi,driver-mode = ; // LVDS + }; + hmc7044_c2: channel@2 { + reg = <2>; + adi,extended-name = "DEV_REFCLK"; + adi,divider = <12>; // 387.5 + adi,driver-mode = ; // LVDS + }; + hmc7044_c3: channel@3 { + reg = <3>; + adi,extended-name = "DEV_SYSREF"; + adi,divider = <1536>; // 12.109375 + adi,driver-mode = ; // LVDS + }; + hmc7044_c6: channel@6 { + reg = <6>; + adi,extended-name = "CORE_CLK_TX"; + adi,divider = <12>; // 122880000 + adi,driver-mode = ; // LVDS + }; + hmc7044_c8: channel@8 { + reg = <8>; + adi,extended-name = "CORE_CLK_RX_ALT2"; + adi,divider = <12>; // 250 + adi,driver-mode = ; // LVDS + }; + hmc7044_c10: channel@10 { + reg = <10>; + adi,extended-name = "CORE_CLK_RX_ALT"; + adi,divider = <12>; // 387.5 + adi,driver-mode = ; // LVDS + }; + hmc7044_c12: channel@12 { + reg = <12>; + adi,extended-name = "FPGA_REFCLK2"; + adi,divider = <6>; // 775 + adi,driver-mode = ; // LVDS + }; + hmc7044_c13: channel@13 { + reg = <13>; + adi,extended-name = "FPGA_SYSREF"; + adi,divider = <1536>; // 12.109375 + adi,driver-mode = ; // LVDS + }; +}; + +&trx0_ad9081 { + adi,tx-dacs { + #size-cells = <0>; + #address-cells = <1>; + adi,dac-frequency-hz = /bits/ 64 <12000000000>; + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = <6>; + ad9081_dac0: dac@0 { + reg = <0>; + adi,crossbar-select = <&ad9081_tx_fddc_chan0>; + adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 100 MHz */ + }; + ad9081_dac1: dac@1 { + reg = <1>; + adi,crossbar-select = <&ad9081_tx_fddc_chan1>; + adi,nco-frequency-shift-hz = /bits/ 64 <1100000000>; /* 200 MHz */ + }; + ad9081_dac2: dac@2 { + reg = <2>; + adi,crossbar-select = <&ad9081_tx_fddc_chan2>; /* All 4 channels @ dac2 */ + adi,nco-frequency-shift-hz = /bits/ 64 <1200000000>; /* 300 MHz */ + }; + ad9081_dac3: dac@3 { + reg = <3>; + adi,crossbar-select = <&ad9081_tx_fddc_chan3>; /* All 4 channels @ dac2 */ + adi,nco-frequency-shift-hz = /bits/ 64 <1300000000>; /* 400 MHz */ + }; + }; + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = <8>; + ad9081_tx_fddc_chan0: channel@0 { + reg = <0>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + }; + ad9081_tx_fddc_chan1: channel@1 { + reg = <1>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + }; + ad9081_tx_fddc_chan2: channel@2 { + reg = <2>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + }; + ad9081_tx_fddc_chan3: channel@3 { + reg = <3>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + }; + }; + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + ad9081_tx_jesd_l0: link@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + adi,logical-lane-mapping = /bits/ 8 <0 2 7 7 1 7 7 3>; + adi,link-mode = <9>; /* JESD Quick Configuration Mode */ + adi,subclass = <1>; /* JESD SUBCLASS 0,1,2 */ + adi,version = <1>; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,converters-per-device = <8>; /* JESD M */ + adi,octets-per-frame = <4>; /* JESD F */ + adi,frames-per-multiframe = <32>; /* JESD K */ + adi,converter-resolution = <16>; /* JESD N */ + adi,bits-per-sample = <16>; /* JESD NP' */ + adi,control-bits-per-sample = <0>; /* JESD CS */ + adi,lanes-per-device = <4>; /* JESD L */ + adi,samples-per-converter-per-frame = <1>; /* JESD S */ + adi,high-density = <0>; /* JESD HD */ + }; + }; + }; + adi,rx-adcs { + #size-cells = <0>; + #address-cells = <1>; + adi,adc-frequency-hz = /bits/ 64 <4000000000>; + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + ad9081_adc0: adc@0 { + reg = <0>; + adi,decimation = <4>; + adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ + }; + ad9081_adc1: adc@1 { + reg = <1>; + adi,decimation = <4>; + adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ + }; + ad9081_adc2: adc@2 { + reg = <2>; + adi,decimation = <4>; + adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan4>, <&ad9081_rx_fddc_chan6>; /* Static for now */ + }; + ad9081_adc3: adc@3 { + reg = <3>; + adi,decimation = <4>; + adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; + adi,nco-mode = ; + //adi,crossbar-select = <&ad9081_rx_fddc_chan5>, <&ad9081_rx_fddc_chan7>; /* Static for now */ + }; + }; + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + ad9081_rx_fddc_chan0: channel@0 { + reg = <0>; + adi,decimation = <4>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + }; + ad9081_rx_fddc_chan1: channel@1 { + reg = <1>; + adi,decimation = <4>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + }; + ad9081_rx_fddc_chan4: channel@4 { + reg = <4>; + adi,decimation = <4>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + }; + ad9081_rx_fddc_chan5: channel@5 { + reg = <5>; + adi,decimation = <4>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + }; + }; + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + ad9081_rx_jesd_l0: link@0 { + reg = <0>; + adi,converter-select = + <&ad9081_rx_fddc_chan0 FDDC_I>, <&ad9081_rx_fddc_chan0 FDDC_Q>, + <&ad9081_rx_fddc_chan1 FDDC_I>, <&ad9081_rx_fddc_chan1 FDDC_Q>, + <&ad9081_rx_fddc_chan4 FDDC_I>, <&ad9081_rx_fddc_chan4 FDDC_Q>, + <&ad9081_rx_fddc_chan5 FDDC_I>, <&ad9081_rx_fddc_chan5 FDDC_Q>; + adi,logical-lane-mapping = /bits/ 8 <2 0 7 7 7 7 3 1>; + adi,link-mode = <10>; /* JESD Quick Configuration Mode */ + adi,subclass = <1>; /* JESD SUBCLASS 0,1,2 */ + adi,version = <1>; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,converters-per-device = <8>; /* JESD M */ + adi,octets-per-frame = <4>; /* JESD F */ + adi,frames-per-multiframe = <32>; /* JESD K */ + adi,converter-resolution = <16>; /* JESD N */ + adi,bits-per-sample = <16>; /* JESD NP' */ + adi,control-bits-per-sample = <0>; /* JESD CS */ + adi,lanes-per-device = <4>; /* JESD L */ + adi,samples-per-converter-per-frame = <1>; /* JESD S */ + adi,high-density = <0>; /* JESD HD */ + }; + }; + }; +}; + From 80f37026fde907a2339d5b9404ae9cac2dc7808e Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 11 Nov 2021 16:43:16 +0100 Subject: [PATCH 057/407] microblaze: adi_mb_defconfig: Update for VCU128 Add gpio/clock chip support for gpio/clock chips found on the VCU128 Signed-off-by: Michael Hennerich --- arch/microblaze/configs/adi_mb_defconfig | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/microblaze/configs/adi_mb_defconfig b/arch/microblaze/configs/adi_mb_defconfig index dc4d5bfe9d4267..24147f2cf65f41 100644 --- a/arch/microblaze/configs/adi_mb_defconfig +++ b/arch/microblaze/configs/adi_mb_defconfig @@ -10,7 +10,6 @@ CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="rootfs.cpio.gz" CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_SYSCTL_SYSCALL=y # CONFIG_BASE_FULL is not set CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y @@ -23,8 +22,6 @@ CONFIG_XILINX_MICROBLAZE0_USE_DIV=1 CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL=2 CONFIG_XILINX_MICROBLAZE0_USE_FPU=2 CONFIG_HZ_100=y -CONFIG_MMU=y -# CONFIG_SECCOMP is not set CONFIG_ADVANCED_OPTIONS=y CONFIG_HIGHMEM=y CONFIG_LOWMEM_SIZE_BOOL=y @@ -32,6 +29,7 @@ CONFIG_KERNEL_START_BOOL=y CONFIG_KERNEL_START=0x80000000 CONFIG_TASK_SIZE_BOOL=y CONFIG_PCI_XILINX=y +# CONFIG_SECCOMP is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set @@ -70,6 +68,7 @@ CONFIG_XILINX_SYSACE=y CONFIG_AD525X_DPOT=y CONFIG_AD525X_DPOT_I2C=y CONFIG_AD525X_DPOT_SPI=y +CONFIG_ADI_AXI_DATA_OFFLOAD=y CONFIG_XLNX_LCD=y CONFIG_EEPROM_AT24=y CONFIG_NETDEVICES=y @@ -88,8 +87,8 @@ CONFIG_NETDEVICES=y CONFIG_XILINX_EMACLITE=y CONFIG_XILINX_AXI_EMAC=y CONFIG_XILINX_LL_TEMAC=y -CONFIG_DP83867_PHY=y CONFIG_MARVELL_PHY=y +CONFIG_DP83867_PHY=y CONFIG_XILINX_PHY=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set @@ -115,6 +114,8 @@ CONFIG_SPI_XILINX=y CONFIG_SPI_SPIDEV=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_XILINX=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y CONFIG_POWER_RESET=y CONFIG_POWER_RESET_GPIO_RESTART=y # CONFIG_HWMON is not set @@ -126,6 +127,8 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_DMADEVICES=y CONFIG_AXI_DMAC=y CONFIG_STAGING=y +CONFIG_COMMON_CLK_SI570=y +CONFIG_COMMON_CLK_SI5324=y CONFIG_COMMON_CLK_AXI_CLKGEN=y CONFIG_IIO=y CONFIG_IIO_KFIFO_BUF=y From 212d4b4736e35e70195554f3fcac5044e66833eb Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 20 Dec 2021 16:33:03 +0100 Subject: [PATCH 058/407] nvmem: adi_axi_sysid: Fix custom info stack corruption This fixes following kernel panic seen with the sysid on the ad40xx_fmc project: Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: axi_sysid_probe+0x704/0x71c Increase custom_info buffer and use snprintf() to truncate in case the string doesn't fit the reserved buffer space. Fixes 64ea0d3503ee ("nvmem: adi_axi_sysid: Print System Custom String") Signed-off-by: Michael Hennerich --- drivers/nvmem/adi_axi_sysid.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/nvmem/adi_axi_sysid.c b/drivers/nvmem/adi_axi_sysid.c index d257234f03d306..03b27aa4086d94 100644 --- a/drivers/nvmem/adi_axi_sysid.c +++ b/drivers/nvmem/adi_axi_sysid.c @@ -116,7 +116,7 @@ static int axi_sysid_validate_v1_1(struct platform_device *pdev, struct build_info_header_v1_1 *build) { struct sysid_header_v1 *header; - char custom_info[48]; + char custom_info[128]; struct tm tm; time64_t t = 0; @@ -131,7 +131,8 @@ static int axi_sysid_validate_v1_1(struct platform_device *pdev, time64_to_tm(t, 0, &tm); if (axi_sysid_get_str(st, header->custom_info_offs)) - sprintf(custom_info, "%s%s%s", " [", axi_sysid_get_str(st, header->custom_info_offs), "]"); + snprintf(custom_info, sizeof(custom_info), "%s%s%s", + " [", axi_sysid_get_str(st, header->custom_info_offs), "]"); else custom_info[0] = 0; @@ -154,7 +155,7 @@ static int axi_sysid_validate_v1(struct platform_device *pdev, struct build_info_header_v1 *build) { struct sysid_header_v1 *header; - char custom_info[48]; + char custom_info[128]; struct tm tm; time64_t t = 0; @@ -169,7 +170,8 @@ static int axi_sysid_validate_v1(struct platform_device *pdev, time64_to_tm(t, 0, &tm); if (axi_sysid_get_str(st, header->custom_info_offs)) - sprintf(custom_info, "%s%s%s", " [", axi_sysid_get_str(st, header->custom_info_offs), "]"); + snprintf(custom_info, sizeof(custom_info), "%s%s%s", + " [", axi_sysid_get_str(st, header->custom_info_offs), "]"); else custom_info[0] = 0; From bd26a4148b4bad9aa86fe72266cad1c18878ba2e Mon Sep 17 00:00:00 2001 From: Liviu Adace Date: Wed, 22 Dec 2021 13:52:42 +0200 Subject: [PATCH 059/407] arch:arm:configs Add DEBUG_SOCFPGA_ARRIA10_UART1 Add DEBUG_SOCFPGA_ARRIA10_UART1 kernel low-level debugging support on SOCFPGA(Arria 10) based platforms Signed-off-by: Liviu Adace --- arch/arm/configs/socfpga_adi_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/socfpga_adi_defconfig b/arch/arm/configs/socfpga_adi_defconfig index f7f713e2b12459..0d5dc65d262fe5 100644 --- a/arch/arm/configs/socfpga_adi_defconfig +++ b/arch/arm/configs/socfpga_adi_defconfig @@ -152,4 +152,5 @@ CONFIG_DETECT_HUNG_TASK=y CONFIG_FUNCTION_TRACER=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_LL=y +CONFIG_DEBUG_SOCFPGA_ARRIA10_UART1=y CONFIG_EARLY_PRINTK=y From 5d2580e300fd0729cd5cd4ced682ae1215ee8590 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 15 Dec 2021 18:07:12 +0200 Subject: [PATCH 060/407] arch:arm64: add dts for fmcbridge xmw Add adrv9009-zu11eg-fmcbridge device tree used for production tests of the XMicrowave fmcbridge. Signed-off-by: Antoniu Miclaus --- ...drv2crr-fmc-revb-jesd204-fsm-fmcbridge.dts | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-fmcbridge.dts diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-fmcbridge.dts b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-fmcbridge.dts new file mode 100644 index 00000000000000..b4b3118e3d6e81 --- /dev/null +++ b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-fmcbridge.dts @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ADRV2CRR-FMC using ADRV9009-ZU11EG Rev.B System on Module + * + * https://wiki.analog.com/resources/eval/user-guides/adrv9009 + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-transceiver/adrv9009 + * https://wiki.analog.com/resources/tools-software/linux-software/adrv9009_advanced_plugin + * https://wiki.analog.com/resources/eval/user-guides/adrv9009-zu11eg/adrv2crr-fmc_carrier_board + * + * hdl_project: + * board_revision: + * + * Copyright (C) 2021 Analog Devices Inc. + */ + +#include "zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm.dts" + +&fpga_axi { + axi_i2c_1: i2c@83000000 { + #address-cells = <1>; + #size-cells = <0>; + clock-names = "s_axi_aclk"; + clocks = <&zynqmp_clk 71>; + compatible = "xlnx,axi-iic-2.0", "xlnx,xps-iic-2.00.a"; + interrupt-names = "iic2intc_irpt"; + interrupt-parent = <&gic>; + interrupts = <0 90 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x0 0x83000000 0x1000>; + }; + + axi_i2c_2: i2c@83100000 { + #address-cells = <1>; + #size-cells = <0>; + clock-names = "s_axi_aclk"; + clocks = <&zynqmp_clk 71>; + compatible = "xlnx,axi-iic-2.0", "xlnx,xps-iic-2.00.a"; + interrupt-names = "iic2intc_irpt"; + interrupt-parent = <&gic>; + interrupts = <0 91 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x0 0x83100000 0x1000>; + }; + + axi_spi_1: spi@84000000 { + #address-cells = <1>; + #size-cells = <0>; + bits-per-word = <8>; + compatible = "xlnx,xps-spi-2.00.a"; + reg = <0x0 0x84000000 0x1000>; + fifo-size = <16>; + interrupts = <0 92 IRQ_TYPE_EDGE_RISING>; + num-cs = <0x8>; + xlnx,num-ss-bits = <0x8>; + xlnx,spi-mode = <0>; + }; + + axi_spi_2: spi@84500000 { + #address-cells = <1>; + #size-cells = <0>; + bits-per-word = <8>; + compatible = "xlnx,xps-spi-2.00.a"; + reg = <0x0 0x84500000 0x1000>; + fifo-size = <16>; + interrupts = <0 93 IRQ_TYPE_EDGE_RISING>; + num-cs = <0x8>; + xlnx,num-ss-bits = <0x8>; + xlnx,spi-mode = <0>; + }; + + axi_gpio: gpio@86000000 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + clock-names = "s_axi_aclk"; + clocks = <&zynqmp_clk 71>; + compatible = "xlnx,axi-gpio-2.0", "xlnx,xps-gpio-1.00.a"; + gpio-controller; + interrupt-controller; + interrupt-names = "ip2intc_irpt"; + interrupt-parent = <&gic>; + interrupts = <0 9 4>; + reg = <0x0 0x86000000 0x1000>; + xlnx,all-inputs = <0x0>; + xlnx,all-inputs-2 = <0x0>; + xlnx,all-outputs = <0x0>; + xlnx,all-outputs-2 = <0x0>; + xlnx,dout-default = <0x00000000>; + xlnx,dout-default-2 = <0x00000000>; + xlnx,gpio-width = <0x20>; + xlnx,gpio2-width = <0x20>; + xlnx,interrupt-present = <0x1>; + xlnx,is-dual = <0x1>; + xlnx,tri-default = <0xFFFFFFFF>; + xlnx,tri-default-2 = <0xFFFFFFFF>; + }; +}; + +&axi_i2c_1 { + ad7291_1@2f { + label = "ADC_I2C_1"; + compatible = "adi,ad7291"; + reg = <0x2f>; + }; +}; + +&axi_i2c_2 { + ad7291_2@2f { + label = "ADC_I2C_2"; + compatible = "adi,ad7291"; + reg = <0x2f>; + }; +}; + +&axi_spi_1 { + ad5721r_1@0 { + label = "DAC_SPI_1"; + compatible = "adi,ad5721r"; + reg = <0>; + spi-max-frequency = <500000>; + }; +}; + +&axi_spi_2 { + ad5721r_2@0 { + label = "DAC_SPI_2"; + compatible = "adi,ad5721r"; + reg = <0>; + spi-max-frequency = <500000>; + }; +}; From 98ec42175aafb22c5785a00ddc8d83d41a10e386 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 22 Dec 2021 12:37:13 +0200 Subject: [PATCH 061/407] arch:arm64:dts:adi-adar3002-longs-peak.dts: Fix chip revision SC18IS602 and SC18IS603 do not support SS2 function as SPI slave select signal; this pin can only be used as GPIO2. Use SC18IS602B version to add support for SS2. Fixes: 32b7bcd ("arch: arm64: dts: longs-peack: Add support for rx back plane.") Signed-off-by: Cristian Pop --- arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts index 1f4280604bf282..9b4732b07e17cd 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts @@ -77,12 +77,12 @@ #address-cells = <1>; #size-cells = <0>; i2c_to_spi_1: spi@28 { - compatible = "nxp,sc18is602"; + compatible = "nxp,sc18is602b"; reg = <0x28>; }; i2c_to_spi_2: spi@29 { - compatible = "nxp,sc18is602"; + compatible = "nxp,sc18is602b"; reg = <0x29>; }; }; From 28cd4075ff3965da03fb353199ee3b993212c1ac Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 22 Dec 2021 13:07:50 +0200 Subject: [PATCH 062/407] arch:arm64:dts:adi-adar3002-longs-peak.dts: Reverse SC18IS602B children This fixes communication with children chips in the receive down converter path. Fixes: 32b7bcd ("arch: arm64: dts: longs-peack: Add support for rx back plane.") Signed-off-by: Cristian Pop --- arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts index 9b4732b07e17cd..edfbbe23f5be18 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts @@ -87,7 +87,7 @@ }; }; -&i2c_to_spi_1 { +&i2c_to_spi_2 { #address-cells = <1>; #size-cells = <0>; ad5760@0 { @@ -108,7 +108,7 @@ }; }; -&i2c_to_spi_2 { +&i2c_to_spi_1 { #address-cells = <1>; #size-cells = <0>; adrf5720@0 { From ba54ed514b89537f1241e808153673412987a356 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 22 Dec 2021 13:21:48 +0200 Subject: [PATCH 063/407] arch:arm64:dts:adi-adar3002-longs-peak.dts: Add device labels This is useful to better identify devices. Signed-off-by: Cristian Pop --- arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts index edfbbe23f5be18..879e31302a4c03 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts @@ -92,6 +92,7 @@ #size-cells = <0>; ad5760@0 { compatible = "adi,ad5760"; + label = "ad5760_SYNC1"; reg = <0>; spi-max-frequency = <5000000>; spi-cpha; @@ -100,6 +101,7 @@ }; ad5760@1 { compatible = "adi,ad5760"; + label = "ad5760_SYNC2"; reg = <1>; spi-max-frequency = <5000000>; spi-cpha; @@ -113,22 +115,26 @@ #size-cells = <0>; adrf5720@0 { compatible = "adi,adrf5720"; + label = "adrf5720_LE2"; reg = <0>; spi-max-frequency = <10000000>; }; adrf5720@1 { compatible = "adi,adrf5720"; + label = "adrf5720_LE1"; reg = <1>; spi-max-frequency = <10000000>; }; adl5240@2 { compatible = "adi,adl5240"; + label = "adl5240_LE1"; reg = <2>; spi-3wire; spi-max-frequency = <10000000>; }; adl5240@3 { compatible = "adi,adl5240"; + label = "adl5240_LE2"; reg = <3>; spi-3wire; spi-max-frequency = <10000000>; From 8d0bb6b324020b9248e18a0f6a83b0d5a2d530da Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 22 Dec 2021 13:31:08 +0200 Subject: [PATCH 064/407] arch:arm64:dts:adi-adar3002-longs-peak.dts: Reduce SPI frequency. This is necessary since the SC18IS602B SPI operates at a maximum frequency of 1.8Mhz Fixes: 32b7bcd("arch: arm64: dts: longs-peack: Add support for rx back plane.") Signed-off-by: Cristian Pop --- .../boot/dts/xilinx/adi-adar3002-longs-peak.dts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts index 879e31302a4c03..1d17f67081ac2b 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts @@ -94,7 +94,7 @@ compatible = "adi,ad5760"; label = "ad5760_SYNC1"; reg = <0>; - spi-max-frequency = <5000000>; + spi-max-frequency = <1000000>; spi-cpha; vss-supply = <&dac_vss>; vdd-supply = <&dac_vdd>; @@ -103,7 +103,7 @@ compatible = "adi,ad5760"; label = "ad5760_SYNC2"; reg = <1>; - spi-max-frequency = <5000000>; + spi-max-frequency = <1000000>; spi-cpha; vss-supply = <&dac_vss>; vdd-supply = <&dac_vdd>; @@ -117,27 +117,27 @@ compatible = "adi,adrf5720"; label = "adrf5720_LE2"; reg = <0>; - spi-max-frequency = <10000000>; + spi-max-frequency = <1000000>; }; adrf5720@1 { compatible = "adi,adrf5720"; label = "adrf5720_LE1"; reg = <1>; - spi-max-frequency = <10000000>; + spi-max-frequency = <1000000>; }; adl5240@2 { compatible = "adi,adl5240"; label = "adl5240_LE1"; reg = <2>; spi-3wire; - spi-max-frequency = <10000000>; + spi-max-frequency = <1000000>; }; adl5240@3 { compatible = "adi,adl5240"; label = "adl5240_LE2"; reg = <3>; spi-3wire; - spi-max-frequency = <10000000>; + spi-max-frequency = <1000000>; }; }; From d2662c364c9404c9def66b9f74ec2311aa744e49 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 22 Dec 2021 13:35:15 +0200 Subject: [PATCH 065/407] arch:arm64:dts:adi-adar3002-longs-peak.dts: Fix ADL5240 SPI config Chip doesn't have a SDO pin and is not 3 wire, it only has write capability. Fixes: 32b7bcd ("arch: arm64: dts: longs-peack: Add support for rx back plane.") Signed-off-by: Cristian Pop --- arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts index 1d17f67081ac2b..6c57ec0568f6fe 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts @@ -129,14 +129,12 @@ compatible = "adi,adl5240"; label = "adl5240_LE1"; reg = <2>; - spi-3wire; spi-max-frequency = <1000000>; }; adl5240@3 { compatible = "adi,adl5240"; label = "adl5240_LE2"; reg = <3>; - spi-3wire; spi-max-frequency = <1000000>; }; }; From 513dfc934abc871712c310da703c308bd808ebdb Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 22 Dec 2021 13:39:59 +0200 Subject: [PATCH 066/407] arch:arm64:dts:adi-adar3002-longs-peak.dts: Rename devices Better naming for devices that specifies the chip select where they are connected. Signed-off-by: Cristian Pop --- .../dts/xilinx/adi-adar3002-longs-peak.dts | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts index 6c57ec0568f6fe..e575589133a535 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts @@ -140,7 +140,7 @@ }; &axi_spi_pmod { - adar3002_T0: adar3002_0@0 { + adar3002_csb_0@0 { compatible = "adi,adar3002"; reg = <0>; spi-max-frequency = <1000000>; @@ -149,76 +149,76 @@ #size-cells = <0>; reset-gpios = <&gpio 139 0>; - adar3002_0@0 { + adar3002_csb_0_0@0 { reg = <0>; label = "adar3002_U1E"; }; - adar3002_1@1 { + adar3002_csb_0_1@1 { reg = <1>; label = "adar3002_U2E"; }; - adar3002_2@2 { + adar3002_csb_0_2@2 { reg = <2>; label = "adar3002_U3E"; }; - adar3002_3@3 { + adar3002_csb_0_3@3 { reg = <3>; label = "adar3002_U4E"; }; - adar3002_4@4 { + adar3002_csb_0_4@4 { reg = <4>; label = "adar3002_U1F"; }; - adar3002_5@5 { + adar3002_csb_0_5@5 { reg = <5>; label = "adar3002_U2F"; }; - adar3002_6@6 { + adar3002_csb_0_6@6 { reg = <6>; label = "adar3002_U3F"; }; - adar3002_7@7 { + adar3002_csb_0_7@7 { reg = <7>; label = "adar3002_U4F"; }; - adar3002_8@8 { + adar3002_csb_0_8@8 { reg = <8>; label = "adar3002_U1G"; }; - adar3002_9@9 { + adar3002_csb_0_9@9 { reg = <9>; label = "adar3002_U2G"; }; - adar3002_10@10 { + adar3002_csb_0_10@10 { reg = <10>; label = "adar3002_U3G"; }; - adar3002_11@11 { + adar3002_csb_0_11@11 { reg = <11>; label = "adar3002_U4G"; }; - adar3002_12@12 { + adar3002_csb_0_12@12 { reg = <12>; label = "adar3002_U1H"; }; - adar3002_13@13 { + adar3002_csb_0_13@13 { reg = <13>; label = "adar3002_U2H"; }; - adar3002_14@14 { + adar3002_csb_0_14@14 { reg = <14>; label = "adar3002_U3H"; }; - adar3002_15@15 { + adar3002_csb_0_15@15 { reg = <15>; label = "adar3002_U4H"; }; }; - adar3002_T1: adar3002_1@1 { + adar3002_csb_1@1 { compatible = "adi,adar3002"; reg = <1>; spi-max-frequency = <1000000>; @@ -227,76 +227,76 @@ #size-cells = <0>; reset-gpios = <&gpio 139 0>; - adar3002_0@0 { + adar3002_csb_1_0@0 { reg = <0>; label = "adar3002_U1E"; }; - adar3002_1@1 { + adar3002_csb_1_1@1 { reg = <1>; label = "adar3002_U2E"; }; - adar3002_2@2 { + adar3002_csb_1_2@2 { reg = <2>; label = "adar3002_U3E"; }; - adar3002_3@3 { + adar3002_csb_1_3@3 { reg = <3>; label = "adar3002_U4E"; }; - adar3002_4@4 { + adar3002_csb_1_4@4 { reg = <4>; label = "adar3002_U1F"; }; - adar3002_5@5 { + adar3002_csb_1_5@5 { reg = <5>; label = "adar3002_U2F"; }; - adar3002_6@6 { + adar3002_csb_1_6@6 { reg = <6>; label = "adar3002_U3F"; }; - adar3002_7@7 { + adar3002_csb_1_7@7 { reg = <7>; label = "adar3002_U4F"; }; - adar3002_8@8 { + adar3002_csb_1_8@8 { reg = <8>; label = "adar3002_U1G"; }; - adar3002_9@9 { + adar3002_csb_1_9@9 { reg = <9>; label = "adar3002_U2G"; }; - adar3002_10@10 { + adar3002_csb_1_10@10 { reg = <10>; label = "adar3002_U3G"; }; - adar3002_11@11 { + adar3002_csb_1_11@11 { reg = <11>; label = "adar3002_U4G"; }; - adar3002_12@12 { + adar3002_csb_1_12@12 { reg = <12>; label = "adar3002_U1H"; }; - adar3002_13@13 { + adar3002_csb_1_13@13 { reg = <13>; label = "adar3002_U2H"; }; - adar3002_14@14 { + adar3002_csb_1_14@14 { reg = <14>; label = "adar3002_U3H"; }; - adar3002_15@15 { + adar3002_csb_1_15@15 { reg = <15>; label = "adar3002_U4H"; }; }; - adar3002_T2: adar3002_2@2 { + adar3002_csb_2@2 { compatible = "adi,adar3002"; reg = <2>; spi-max-frequency = <1000000>; @@ -305,76 +305,76 @@ #size-cells = <0>; reset-gpios = <&gpio 139 0>; - adar3002_0@0 { + adar3002_csb_2_0@0 { reg = <0>; label = "adar3002_U1E"; }; - adar3002_1@1 { + adar3002_csb_2_1@1 { reg = <1>; label = "adar3002_U2E"; }; - adar3002_2@2 { + adar3002_csb_2_2@2 { reg = <2>; label = "adar3002_U3E"; }; - adar3002_3@3 { + adar3002_csb_2_3@3 { reg = <3>; label = "adar3002_U4E"; }; - adar3002_4@4 { + adar3002_csb_2_4@4 { reg = <4>; label = "adar3002_U1F"; }; - adar3002_5@5 { + adar3002_csb_2_5@5 { reg = <5>; label = "adar3002_U2F"; }; - adar3002_6@6 { + adar3002_csb_2_6@6 { reg = <6>; label = "adar3002_U3F"; }; - adar3002_7@7 { + adar3002_csb_2_7@7 { reg = <7>; label = "adar3002_U4F"; }; - adar3002_8@8 { + adar3002_csb_2_8@8 { reg = <8>; label = "adar3002_U1G"; }; - adar3002_9@9 { + adar3002_csb_2_9@9 { reg = <9>; label = "adar3002_U2G"; }; - adar3002_10@10 { + adar3002_csb_2_10@10 { reg = <10>; label = "adar3002_U3G"; }; - adar3002_11@11 { + adar3002_csb_2_11@11 { reg = <11>; label = "adar3002_U4G"; }; - adar3002_12@12 { + adar3002_csb_2_12@12 { reg = <12>; label = "adar3002_U1H"; }; - adar3002_13@13 { + adar3002_csb_2_13@13 { reg = <13>; label = "adar3002_U2H"; }; - adar3002_14@14 { + adar3002_csb_2_14@14 { reg = <14>; label = "adar3002_U3H"; }; - adar3002_15@15 { + adar3002_csb_2_15@15 { reg = <15>; label = "adar3002_U4H"; }; }; - adar3002_T3: adar3002_3@3 { + adar3002_csb_3@3 { compatible = "adi,adar3002"; reg = <3>; spi-max-frequency = <1000000>; @@ -383,70 +383,70 @@ #size-cells = <0>; reset-gpios = <&gpio 139 0>; - adar3002_0@0 { + adar3002_csb_3_0@0 { reg = <0>; label = "adar3002_U1E"; }; - adar3002_1@1 { + adar3002_csb_3_1@1 { reg = <1>; label = "adar3002_U2E"; }; - adar3002_2@2 { + adar3002_csb_3_2@2 { reg = <2>; label = "adar3002_U3E"; }; - adar3002_3@3 { + adar3002_csb_3_3@3 { reg = <3>; label = "adar3002_U4E"; }; - adar3002_4@4 { + adar3002_csb_3_4@4 { reg = <4>; label = "adar3002_U1F"; }; - adar3002_5@5 { + adar3002_csb_3_5@5 { reg = <5>; label = "adar3002_U2F"; }; - adar3002_6@6 { + adar3002_csb_3_6@6 { reg = <6>; label = "adar3002_U3F"; }; - adar3002_7@7 { + adar3002_csb_3_7@7 { reg = <7>; label = "adar3002_U4F"; }; - adar3002_8@8 { + adar3002_csb_3_8@8 { reg = <8>; label = "adar3002_U1G"; }; - adar3002_9@9 { + adar3002_csb_3_9@9 { reg = <9>; label = "adar3002_U2G"; }; - adar3002_10@10 { + adar3002_csb_3_10@10 { reg = <10>; label = "adar3002_U3G"; }; - adar3002_11@11 { + adar3002_csb_3_11@11 { reg = <11>; label = "adar3002_U4G"; }; - adar3002_12@12 { + adar3002_csb_3_12@12 { reg = <12>; label = "adar3002_U1H"; }; - adar3002_13@13 { + adar3002_csb_3_13@13 { reg = <13>; label = "adar3002_U2H"; }; - adar3002_14@14 { + adar3002_csb_3_14@14 { reg = <14>; label = "adar3002_U3H"; }; - adar3002_15@15 { + adar3002_csb_3_15@15 { reg = <15>; label = "adar3002_U4H"; }; From 9ed6209ae574d03db0ee6e592018ecae32603d7f Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 26 Oct 2021 10:53:16 +0300 Subject: [PATCH 067/407] iio:addac:ad7293: add support for AD7293 Add support for 12-Bit Power Amplifier Current Controller with ADC, DACs, Temperature and Current Sensors. Datasheet: https://www.analog.com/en/products/ad7293.html Signed-off-by: Antoniu Miclaus --- drivers/iio/dac/Kconfig | 11 + drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ad7293.c | 935 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 947 insertions(+) create mode 100644 drivers/iio/dac/ad7293.c diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 07ceef61abe8a7..72e489704280c6 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -240,6 +240,17 @@ config AD5791 To compile this driver as a module, choose M here: the module will be called ad5791. +config AD7293 + tristate "Analog Devices AD7293 Power Amplifier Current Controller" + depends on SPI + help + Say yes here to build support for Analog Devices AD7293 + Power Amplifier Current Controller with + ADC, DACs, and Temperature and Current Sensors + + To compile this driver as a module, choose M here: the + module will be called ad7293. + config AD7303 tristate "Analog Devices AD7303 DAC driver" depends on SPI diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index bb4c40cf8e7261..a13a06682bd398 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_AD5791) += ad5791.o obj-$(CONFIG_AD5686) += ad5686.o obj-$(CONFIG_AD5686_SPI) += ad5686-spi.o obj-$(CONFIG_AD5696_I2C) += ad5696-i2c.o +obj-$(CONFIG_AD7293) += ad7293.o obj-$(CONFIG_AD7303) += ad7303.o obj-$(CONFIG_AD8801) += ad8801.o obj-$(CONFIG_CIO_DAC) += cio-dac.o diff --git a/drivers/iio/dac/ad7293.c b/drivers/iio/dac/ad7293.c new file mode 100644 index 00000000000000..e21ab3e94862ee --- /dev/null +++ b/drivers/iio/dac/ad7293.c @@ -0,0 +1,935 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * AD7293 driver + * + * Copyright 2021 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define AD7293_R1B BIT(16) +#define AD7293_R2B BIT(17) +#define AD7293_PAGE_ADDR_MSK GENMASK(15, 8) +#define AD7293_PAGE(x) FIELD_PREP(AD7293_PAGE_ADDR_MSK, x) + +/* AD7293 Register Map Common */ +#define AD7293_REG_NO_OP (AD7293_R1B | AD7293_PAGE(0x0) | 0x0) +#define AD7293_REG_PAGE_SELECT (AD7293_R1B | AD7293_PAGE(0x0) | 0x1) +#define AD7293_REG_CONV_CMD (AD7293_R2B | AD7293_PAGE(0x0) | 0x2) +#define AD7293_REG_RESULT (AD7293_R1B | AD7293_PAGE(0x0) | 0x3) +#define AD7293_REG_DAC_EN (AD7293_R1B | AD7293_PAGE(0x0) | 0x4) +#define AD7293_REG_DEVICE_ID (AD7293_R2B | AD7293_PAGE(0x0) | 0xC) +#define AD7293_REG_SOFT_RESET (AD7293_R2B | AD7293_PAGE(0x0) | 0xF) + +/* AD7293 Register Map Page 0x0 */ +#define AD7293_REG_VIN0 (AD7293_R2B | AD7293_PAGE(0x0) | 0x10) +#define AD7293_REG_VIN1 (AD7293_R2B | AD7293_PAGE(0x0) | 0x11) +#define AD7293_REG_VIN2 (AD7293_R2B | AD7293_PAGE(0x0) | 0x12) +#define AD7293_REG_VIN3 (AD7293_R2B | AD7293_PAGE(0x0) | 0x13) +#define AD7293_REG_TSENSE_INT (AD7293_R2B | AD7293_PAGE(0x0) | 0x20) +#define AD7293_REG_TSENSE_D0 (AD7293_R2B | AD7293_PAGE(0x0) | 0x21) +#define AD7293_REG_TSENSE_D1 (AD7293_R2B | AD7293_PAGE(0x0) | 0x22) +#define AD7293_REG_ISENSE_0 (AD7293_R2B | AD7293_PAGE(0x0) | 0x28) +#define AD7293_REG_ISENSE_1 (AD7293_R2B | AD7293_PAGE(0x0) | 0x29) +#define AD7293_REG_ISENSE_2 (AD7293_R2B | AD7293_PAGE(0x0) | 0x2A) +#define AD7293_REG_ISENSE_3 (AD7293_R2B | AD7293_PAGE(0x0) | 0x2B) +#define AD7293_REG_UNI_VOUT0 (AD7293_R2B | AD7293_PAGE(0x0) | 0x30) +#define AD7293_REG_UNI_VOUT1 (AD7293_R2B | AD7293_PAGE(0x0) | 0x31) +#define AD7293_REG_UNI_VOUT2 (AD7293_R2B | AD7293_PAGE(0x0) | 0x32) +#define AD7293_REG_UNI_VOUT3 (AD7293_R2B | AD7293_PAGE(0x0) | 0x33) +#define AD7293_REG_BI_VOUT0 (AD7293_R2B | AD7293_PAGE(0x0) | 0x34) +#define AD7293_REG_BI_VOUT1 (AD7293_R2B | AD7293_PAGE(0x0) | 0x35) +#define AD7293_REG_BI_VOUT2 (AD7293_R2B | AD7293_PAGE(0x0) | 0x36) +#define AD7293_REG_BI_VOUT3 (AD7293_R2B | AD7293_PAGE(0x0) | 0x37) + +/* AD7293 Register Map Page 0x2 */ +#define AD7293_REG_DIGITAL_OUT_EN (AD7293_R2B | AD7293_PAGE(0x2) | 0x11) +#define AD7293_REG_DIGITAL_INOUT_FUNC (AD7293_R2B | AD7293_PAGE(0x2) | 0x12) +#define AD7293_REG_DIGITAL_FUNC_POL (AD7293_R2B | AD7293_PAGE(0x2) | 0x13) +#define AD7293_REG_GENERAL (AD7293_R2B | AD7293_PAGE(0x2) | 0x14) +#define AD7293_REG_VINX_RANGE0 (AD7293_R2B | AD7293_PAGE(0x2) | 0x15) +#define AD7293_REG_VINX_RANGE1 (AD7293_R2B | AD7293_PAGE(0x2) | 0x16) +#define AD7293_REG_VINX_DIFF_SE (AD7293_R2B | AD7293_PAGE(0x2) | 0x17) +#define AD7293_REG_VINX_FILTER (AD7293_R2B | AD7293_PAGE(0x2) | 0x18) +#define AD7293_REG_BG_EN (AD7293_R2B | AD7293_PAGE(0x2) | 0x19) +#define AD7293_REG_CONV_DELAY (AD7293_R2B | AD7293_PAGE(0x2) | 0x1A) +#define AD7293_REG_TSENSE_BG_EN (AD7293_R2B | AD7293_PAGE(0x2) | 0x1B) +#define AD7293_REG_ISENSE_BG_EN (AD7293_R2B | AD7293_PAGE(0x2) | 0x1C) +#define AD7293_REG_ISENSE_GAIN (AD7293_R2B | AD7293_PAGE(0x2) | 0x1D) +#define AD7293_REG_DAC_SNOOZE_O (AD7293_R2B | AD7293_PAGE(0x2) | 0x1F) +#define AD7293_REG_DAC_SNOOZE_1 (AD7293_R2B | AD7293_PAGE(0x2) | 0x20) +#define AD7293_REG_RSX_MON_BG_EN (AD7293_R2B | AD7293_PAGE(0x2) | 0x23) +#define AD7293_REG_INTEGR_CL (AD7293_R2B | AD7293_PAGE(0x2) | 0x28) +#define AD7293_REG_PA_ON_CTRL (AD7293_R2B | AD7293_PAGE(0x2) | 0x29) +#define AD7293_REG_RAMP_TIME_0 (AD7293_R2B | AD7293_PAGE(0x2) | 0x2A) +#define AD7293_REG_RAMP_TIME_1 (AD7293_R2B | AD7293_PAGE(0x2) | 0x2B) +#define AD7293_REG_RAMP_TIME_2 (AD7293_R2B | AD7293_PAGE(0x2) | 0x2C) +#define AD7293_REG_RAMP_TIME_3 (AD7293_R2B | AD7293_PAGE(0x2) | 0x2D) +#define AD7293_REG_CL_FR_IT (AD7293_R2B | AD7293_PAGE(0x2) | 0x2E) +#define AD7293_REG_INTX_AVSS_AVDD (AD7293_R2B | AD7293_PAGE(0x2) | 0x2F) + +/* AD7293 Register Map Page 0x3 */ +#define AD7293_REG_VINX_SEQ (AD7293_R2B | AD7293_PAGE(0x3) | 0x10) +#define AD7293_REG_ISENSEX_TSENSEX_SEQ (AD7293_R2B | AD7293_PAGE(0x3) | 0x11) +#define AD7293_REG_RSX_MON_BI_VOUTX_SEQ (AD7293_R2B | AD7293_PAGE(0x3) | 0x12) + +/* AD7293 Register Map Page 0xE */ +#define AD7293_REG_VIN0_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x10) +#define AD7293_REG_VIN1_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x11) +#define AD7293_REG_VIN2_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x12) +#define AD7293_REG_VIN3_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x13) +#define AD7293_REG_TSENSE_INT_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x20) +#define AD7293_REG_TSENSE_D0_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x21) +#define AD7293_REG_TSENSE_D1_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x22) +#define AD7293_REG_ISENSE0_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x28) +#define AD7293_REG_ISENSE1_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x29) +#define AD7293_REG_ISENSE2_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x2A) +#define AD7293_REG_ISENSE3_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x2B) +#define AD7293_REG_UNI_VOUT0_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x30) +#define AD7293_REG_UNI_VOUT1_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x31) +#define AD7293_REG_UNI_VOUT2_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x32) +#define AD7293_REG_UNI_VOUT3_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x33) +#define AD7293_REG_BI_VOUT0_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x34) +#define AD7293_REG_BI_VOUT1_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x35) +#define AD7293_REG_BI_VOUT2_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x36) +#define AD7293_REG_BI_VOUT3_OFFSET (AD7293_R1B | AD7293_PAGE(0xE) | 0x37) + +/* AD7293 Miscellaneous Definitions */ +#define AD7293_READ BIT(7) +#define AD7293_TRANSF_LEN_MSK GENMASK(17, 16) + +#define AD7293_REG_ADDR_MSK GENMASK(7, 0) +#define AD7293_REG_VOUT_OFFSET_MSK GENMASK(5, 4) +#define AD7293_REG_DATA_RAW_MSK GENMASK(15, 4) +#define AD7293_REG_VINX_RANGE_GET_CH_MSK(x, ch) (((x) >> (ch)) & 0x1) +#define AD7293_REG_VINX_RANGE_SET_CH_MSK(x, ch) (((x) & 0x1) << (ch)) +#define AD7293_CHIP_ID 0x18 + +enum ad7293_ch_type { + AD7293_ADC_VINX, + AD7293_ADC_TSENSE, + AD7293_ADC_ISENSE, + AD7293_DAC, +}; + +enum ad7293_max_offset { + AD7293_TSENSE_MIN_OFFSET_CH = 4, + AD7293_ISENSE_MIN_OFFSET_CH = 7, + AD7293_VOUT_MIN_OFFSET_CH = 11, + AD7293_VOUT_MAX_OFFSET_CH = 18, +}; + +static const int dac_offset_table[] = {0, 1, 2}; + +static const int isense_gain_table[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + +static const int adc_range_table[] = {0, 1, 2, 3}; + +struct ad7293_state { + struct spi_device *spi; + /* Protect against concurrent accesses to the device, page selection and data content */ + struct mutex lock; + struct gpio_desc *gpio_reset; + struct regulator *reg_avdd; + struct regulator *reg_vdrive; + u8 page_select; + u8 data[3] ____cacheline_aligned; +}; + +static int ad7293_page_select(struct ad7293_state *st, unsigned int reg) +{ + int ret; + + if (st->page_select != FIELD_GET(AD7293_PAGE_ADDR_MSK, reg)) { + st->data[0] = FIELD_GET(AD7293_REG_ADDR_MSK, AD7293_REG_PAGE_SELECT); + st->data[1] = FIELD_GET(AD7293_PAGE_ADDR_MSK, reg); + + ret = spi_write(st->spi, &st->data[0], 2); + if (ret) + return ret; + + st->page_select = FIELD_GET(AD7293_PAGE_ADDR_MSK, reg); + } + + return 0; +} + +static int __ad7293_spi_read(struct ad7293_state *st, unsigned int reg, + u16 *val) +{ + int ret; + unsigned int length; + struct spi_transfer t = {0}; + + length = FIELD_GET(AD7293_TRANSF_LEN_MSK, reg); + + ret = ad7293_page_select(st, reg); + if (ret) + return ret; + + st->data[0] = AD7293_READ | FIELD_GET(AD7293_REG_ADDR_MSK, reg); + st->data[1] = 0x0; + st->data[2] = 0x0; + + t.tx_buf = &st->data[0]; + t.rx_buf = &st->data[0]; + t.len = length + 1; + + ret = spi_sync_transfer(st->spi, &t, 1); + if (ret) + return ret; + + if (length == 1) + *val = st->data[1]; + else + *val = get_unaligned_be16(&st->data[1]); + + return 0; +} + +static int ad7293_spi_read(struct ad7293_state *st, unsigned int reg, + u16 *val) +{ + int ret; + + mutex_lock(&st->lock); + ret = __ad7293_spi_read(st, reg, val); + mutex_unlock(&st->lock); + + return ret; +} + +static int __ad7293_spi_write(struct ad7293_state *st, unsigned int reg, + u16 val) +{ + int ret; + unsigned int length; + + length = FIELD_GET(AD7293_TRANSF_LEN_MSK, reg); + + ret = ad7293_page_select(st, reg); + if (ret) + return ret; + + st->data[0] = FIELD_GET(AD7293_REG_ADDR_MSK, reg); + + if (length == 1) + st->data[1] = val; + else + put_unaligned_be16(val, &st->data[1]); + + return spi_write(st->spi, &st->data[0], length + 1); +} + +static int ad7293_spi_write(struct ad7293_state *st, unsigned int reg, + u16 val) +{ + int ret; + + mutex_lock(&st->lock); + ret = __ad7293_spi_write(st, reg, val); + mutex_unlock(&st->lock); + + return ret; +} + +static int __ad7293_spi_update_bits(struct ad7293_state *st, unsigned int reg, + u16 mask, u16 val) +{ + int ret; + u16 data, temp; + + ret = __ad7293_spi_read(st, reg, &data); + if (ret) + return ret; + + temp = (data & ~mask) | (val & mask); + + return __ad7293_spi_write(st, reg, temp); +} + +static int ad7293_spi_update_bits(struct ad7293_state *st, unsigned int reg, + u16 mask, u16 val) +{ + int ret; + + mutex_lock(&st->lock); + ret = __ad7293_spi_update_bits(st, reg, mask, val); + mutex_unlock(&st->lock); + + return ret; +} + +static int ad7293_adc_get_scale(struct ad7293_state *st, unsigned int ch, + u16 *range) +{ + int ret; + u16 data; + + mutex_lock(&st->lock); + + ret = __ad7293_spi_read(st, AD7293_REG_VINX_RANGE1, &data); + if (ret) + goto exit; + + *range = AD7293_REG_VINX_RANGE_GET_CH_MSK(data, ch); + + ret = __ad7293_spi_read(st, AD7293_REG_VINX_RANGE0, &data); + if (ret) + goto exit; + + *range |= AD7293_REG_VINX_RANGE_GET_CH_MSK(data, ch) << 1; + +exit: + mutex_unlock(&st->lock); + + return ret; +} + +static int ad7293_adc_set_scale(struct ad7293_state *st, unsigned int ch, + u16 range) +{ + int ret; + unsigned int ch_msk = BIT(ch); + + mutex_lock(&st->lock); + ret = __ad7293_spi_update_bits(st, AD7293_REG_VINX_RANGE1, ch_msk, + AD7293_REG_VINX_RANGE_SET_CH_MSK(range, ch)); + if (ret) + goto exit; + + ret = __ad7293_spi_update_bits(st, AD7293_REG_VINX_RANGE0, ch_msk, + AD7293_REG_VINX_RANGE_SET_CH_MSK((range >> 1), ch)); + +exit: + mutex_unlock(&st->lock); + + return ret; +} + +static int ad7293_get_offset(struct ad7293_state *st, unsigned int ch, + u16 *offset) +{ + if (ch < AD7293_TSENSE_MIN_OFFSET_CH) + return ad7293_spi_read(st, AD7293_REG_VIN0_OFFSET + ch, offset); + else if (ch < AD7293_ISENSE_MIN_OFFSET_CH) + return ad7293_spi_read(st, AD7293_REG_TSENSE_INT_OFFSET + (ch - 4), offset); + else if (ch < AD7293_VOUT_MIN_OFFSET_CH) + return ad7293_spi_read(st, AD7293_REG_ISENSE0_OFFSET + (ch - 7), offset); + else if (ch <= AD7293_VOUT_MAX_OFFSET_CH) + return ad7293_spi_read(st, AD7293_REG_UNI_VOUT0_OFFSET + (ch - 11), offset); + + return -EINVAL; +} + +static int ad7293_set_offset(struct ad7293_state *st, unsigned int ch, + u16 offset) +{ + if (ch < AD7293_TSENSE_MIN_OFFSET_CH) + return ad7293_spi_write(st, AD7293_REG_VIN0_OFFSET + ch, + offset); + else if (ch < AD7293_ISENSE_MIN_OFFSET_CH) + return ad7293_spi_write(st, + AD7293_REG_TSENSE_INT_OFFSET + + (ch - AD7293_TSENSE_MIN_OFFSET_CH), + offset); + else if (ch < AD7293_VOUT_MIN_OFFSET_CH) + return ad7293_spi_write(st, + AD7293_REG_ISENSE0_OFFSET + + (ch - AD7293_ISENSE_MIN_OFFSET_CH), + offset); + else if (ch <= AD7293_VOUT_MAX_OFFSET_CH) + return ad7293_spi_update_bits(st, + AD7293_REG_UNI_VOUT0_OFFSET + + (ch - AD7293_VOUT_MIN_OFFSET_CH), + AD7293_REG_VOUT_OFFSET_MSK, + FIELD_PREP(AD7293_REG_VOUT_OFFSET_MSK, offset)); + + return -EINVAL; +} + +static int ad7293_isense_set_scale(struct ad7293_state *st, unsigned int ch, + u16 gain) +{ + unsigned int ch_msk = (0xf << (4 * ch)); + + return ad7293_spi_update_bits(st, AD7293_REG_ISENSE_GAIN, ch_msk, + gain << (4 * ch)); +} + +static int ad7293_isense_get_scale(struct ad7293_state *st, unsigned int ch, + u16 *gain) +{ + int ret; + + ret = ad7293_spi_read(st, AD7293_REG_ISENSE_GAIN, gain); + if (ret) + return ret; + + *gain = (*gain >> (4 * ch)) & 0xf; + + return ret; +} + +static int ad7293_dac_write_raw(struct ad7293_state *st, unsigned int ch, + u16 raw) +{ + int ret; + + mutex_lock(&st->lock); + + ret = __ad7293_spi_update_bits(st, AD7293_REG_DAC_EN, BIT(ch), BIT(ch)); + if (ret) + goto exit; + + ret = __ad7293_spi_write(st, AD7293_REG_UNI_VOUT0 + ch, + FIELD_PREP(AD7293_REG_DATA_RAW_MSK, raw)); + +exit: + mutex_unlock(&st->lock); + + return ret; +} + +static int ad7293_ch_read_raw(struct ad7293_state *st, enum ad7293_ch_type type, + unsigned int ch, u16 *raw) +{ + int ret; + unsigned int reg_wr, reg_rd, data_wr; + + switch (type) { + case AD7293_ADC_VINX: + reg_wr = AD7293_REG_VINX_SEQ; + reg_rd = AD7293_REG_VIN0 + ch; + data_wr = BIT(ch); + + break; + case AD7293_ADC_TSENSE: + reg_wr = AD7293_REG_ISENSEX_TSENSEX_SEQ; + reg_rd = AD7293_REG_TSENSE_INT + ch; + data_wr = BIT(ch); + + break; + case AD7293_ADC_ISENSE: + reg_wr = AD7293_REG_ISENSEX_TSENSEX_SEQ; + reg_rd = AD7293_REG_ISENSE_0 + ch; + data_wr = BIT(ch) << 8; + + break; + case AD7293_DAC: + reg_rd = AD7293_REG_UNI_VOUT0 + ch; + + break; + default: + return -EINVAL; + } + + mutex_lock(&st->lock); + + if (type != AD7293_DAC) { + if (type == AD7293_ADC_TSENSE) { + ret = __ad7293_spi_write(st, AD7293_REG_TSENSE_BG_EN, + BIT(ch)); + if (ret) + goto exit; + + usleep_range(9000, 9900); + } else if (type == AD7293_ADC_ISENSE) { + ret = __ad7293_spi_write(st, AD7293_REG_ISENSE_BG_EN, + BIT(ch)); + if (ret) + goto exit; + + usleep_range(2000, 7000); + } + + ret = __ad7293_spi_write(st, reg_wr, data_wr); + if (ret) + goto exit; + + ret = __ad7293_spi_write(st, AD7293_REG_CONV_CMD, 0x82); + if (ret) + goto exit; + } + + ret = __ad7293_spi_read(st, reg_rd, raw); + + *raw = FIELD_GET(AD7293_REG_DATA_RAW_MSK, *raw); + +exit: + mutex_unlock(&st->lock); + + return ret; +} + +static int ad7293_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct ad7293_state *st = iio_priv(indio_dev); + int ret; + u16 data; + + switch (info) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_VOLTAGE: + if (chan->output) + ret = ad7293_ch_read_raw(st, AD7293_DAC, + chan->channel, &data); + else + ret = ad7293_ch_read_raw(st, AD7293_ADC_VINX, + chan->channel, &data); + + break; + case IIO_CURRENT: + ret = ad7293_ch_read_raw(st, AD7293_ADC_ISENSE, + chan->channel, &data); + + break; + case IIO_TEMP: + ret = ad7293_ch_read_raw(st, AD7293_ADC_TSENSE, + chan->channel, &data); + + break; + default: + return -EINVAL; + } + + if (ret) + return ret; + + *val = data; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_VOLTAGE: + if (chan->output) { + ret = ad7293_get_offset(st, + chan->channel + AD7293_VOUT_MIN_OFFSET_CH, + &data); + + data = FIELD_GET(AD7293_REG_VOUT_OFFSET_MSK, data); + } else { + ret = ad7293_get_offset(st, chan->channel, &data); + } + + break; + case IIO_CURRENT: + ret = ad7293_get_offset(st, + chan->channel + AD7293_ISENSE_MIN_OFFSET_CH, + &data); + + break; + case IIO_TEMP: + ret = ad7293_get_offset(st, + chan->channel + AD7293_TSENSE_MIN_OFFSET_CH, + &data); + + break; + default: + return -EINVAL; + } + if (ret) + return ret; + + *val = data; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + ret = ad7293_adc_get_scale(st, chan->channel, &data); + if (ret) + return ret; + + *val = data; + + return IIO_VAL_INT; + case IIO_CURRENT: + ret = ad7293_isense_get_scale(st, chan->channel, &data); + if (ret) + return ret; + + *val = data; + + return IIO_VAL_INT; + case IIO_TEMP: + *val = 1; + *val2 = 8; + + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ad7293_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct ad7293_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_VOLTAGE: + if (!chan->output) + return -EINVAL; + + return ad7293_dac_write_raw(st, chan->channel, val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_VOLTAGE: + if (chan->output) + return ad7293_set_offset(st, + chan->channel + + AD7293_VOUT_MIN_OFFSET_CH, + val); + else + return ad7293_set_offset(st, chan->channel, val); + case IIO_CURRENT: + return ad7293_set_offset(st, + chan->channel + + AD7293_ISENSE_MIN_OFFSET_CH, + val); + case IIO_TEMP: + return ad7293_set_offset(st, + chan->channel + + AD7293_TSENSE_MIN_OFFSET_CH, + val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + return ad7293_adc_set_scale(st, chan->channel, val); + case IIO_CURRENT: + return ad7293_isense_set_scale(st, chan->channel, val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ad7293_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int write_val, + unsigned int *read_val) +{ + struct ad7293_state *st = iio_priv(indio_dev); + int ret; + + if (read_val) { + u16 temp; + + ret = ad7293_spi_read(st, reg, &temp); + *read_val = temp; + } else { + ret = ad7293_spi_write(st, reg, (u16)write_val); + } + + return ret; +} + +static int ad7293_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + switch (info) { + case IIO_CHAN_INFO_OFFSET: + *vals = dac_offset_table; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(dac_offset_table); + + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_INT; + + switch (chan->type) { + case IIO_VOLTAGE: + *vals = adc_range_table; + *length = ARRAY_SIZE(adc_range_table); + return IIO_AVAIL_LIST; + case IIO_CURRENT: + *vals = isense_gain_table; + *length = ARRAY_SIZE(isense_gain_table); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +#define AD7293_CHAN_ADC(_channel) { \ + .type = IIO_VOLTAGE, \ + .output = 0, \ + .indexed = 1, \ + .channel = _channel, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) \ +} + +#define AD7293_CHAN_DAC(_channel) { \ + .type = IIO_VOLTAGE, \ + .output = 1, \ + .indexed = 1, \ + .channel = _channel, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_OFFSET) \ +} + +#define AD7293_CHAN_ISENSE(_channel) { \ + .type = IIO_CURRENT, \ + .output = 0, \ + .indexed = 1, \ + .channel = _channel, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) \ +} + +#define AD7293_CHAN_TEMP(_channel) { \ + .type = IIO_TEMP, \ + .output = 0, \ + .indexed = 1, \ + .channel = _channel, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ +} + +static const struct iio_chan_spec ad7293_channels[] = { + AD7293_CHAN_ADC(0), + AD7293_CHAN_ADC(1), + AD7293_CHAN_ADC(2), + AD7293_CHAN_ADC(3), + AD7293_CHAN_ISENSE(0), + AD7293_CHAN_ISENSE(1), + AD7293_CHAN_ISENSE(2), + AD7293_CHAN_ISENSE(3), + AD7293_CHAN_TEMP(0), + AD7293_CHAN_TEMP(1), + AD7293_CHAN_TEMP(2), + AD7293_CHAN_DAC(0), + AD7293_CHAN_DAC(1), + AD7293_CHAN_DAC(2), + AD7293_CHAN_DAC(3), + AD7293_CHAN_DAC(4), + AD7293_CHAN_DAC(5), + AD7293_CHAN_DAC(6), + AD7293_CHAN_DAC(7) +}; + +static int ad7293_soft_reset(struct ad7293_state *st) +{ + int ret; + + ret = __ad7293_spi_write(st, AD7293_REG_SOFT_RESET, 0x7293); + if (ret) + return ret; + + return __ad7293_spi_write(st, AD7293_REG_SOFT_RESET, 0x0000); +} + +static int ad7293_reset(struct ad7293_state *st) +{ + if (st->gpio_reset) { + gpiod_set_value(st->gpio_reset, 0); + usleep_range(100, 1000); + gpiod_set_value(st->gpio_reset, 1); + usleep_range(100, 1000); + + return 0; + } + + /* Perform a software reset */ + return ad7293_soft_reset(st); +} + +static int ad7293_properties_parse(struct ad7293_state *st) +{ + struct spi_device *spi = st->spi; + + st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_reset)) + return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_reset), + "failed to get the reset GPIO\n"); + + st->reg_avdd = devm_regulator_get(&spi->dev, "avdd"); + if (IS_ERR(st->reg_avdd)) + return dev_err_probe(&spi->dev, PTR_ERR(st->reg_avdd), + "failed to get the AVDD voltage\n"); + + st->reg_vdrive = devm_regulator_get(&spi->dev, "vdrive"); + if (IS_ERR(st->reg_vdrive)) + return dev_err_probe(&spi->dev, PTR_ERR(st->reg_vdrive), + "failed to get the VDRIVE voltage\n"); + + return 0; +} + +static void ad7293_reg_disable(void *data) +{ + regulator_disable(data); +} + +static int ad7293_init(struct ad7293_state *st) +{ + int ret; + u16 chip_id; + struct spi_device *spi = st->spi; + + ret = ad7293_properties_parse(st); + if (ret) + return ret; + + ret = ad7293_reset(st); + if (ret) + return ret; + + ret = regulator_enable(st->reg_avdd); + if (ret) { + dev_err(&spi->dev, + "Failed to enable specified AVDD Voltage!\n"); + return ret; + } + + ret = devm_add_action_or_reset(&spi->dev, ad7293_reg_disable, + st->reg_avdd); + if (ret) + return ret; + + ret = regulator_enable(st->reg_vdrive); + if (ret) { + dev_err(&spi->dev, + "Failed to enable specified VDRIVE Voltage!\n"); + return ret; + } + + ret = devm_add_action_or_reset(&spi->dev, ad7293_reg_disable, + st->reg_vdrive); + if (ret) + return ret; + + ret = regulator_get_voltage(st->reg_avdd); + if (ret < 0) { + dev_err(&spi->dev, "Failed to read avdd regulator: %d\n", ret); + return ret; + } + + if (ret > 5500000 || ret < 4500000) + return -EINVAL; + + ret = regulator_get_voltage(st->reg_vdrive); + if (ret < 0) { + dev_err(&spi->dev, + "Failed to read vdrive regulator: %d\n", ret); + return ret; + } + if (ret > 5500000 || ret < 1700000) + return -EINVAL; + + /* Check Chip ID */ + ret = __ad7293_spi_read(st, AD7293_REG_DEVICE_ID, &chip_id); + if (ret) + return ret; + + if (chip_id != AD7293_CHIP_ID) { + dev_err(&spi->dev, "Invalid Chip ID.\n"); + return -EINVAL; + } + + return 0; +} + +static const struct iio_info ad7293_info = { + .read_raw = ad7293_read_raw, + .write_raw = ad7293_write_raw, + .read_avail = &ad7293_read_avail, + .debugfs_reg_access = &ad7293_reg_access, +}; + +static int ad7293_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct ad7293_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + indio_dev->info = &ad7293_info; + indio_dev->name = "ad7293"; + indio_dev->channels = ad7293_channels; + indio_dev->num_channels = ARRAY_SIZE(ad7293_channels); + + st->spi = spi; + st->page_select = 0; + + mutex_init(&st->lock); + + ret = ad7293_init(st); + if (ret) + return ret; + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct spi_device_id ad7293_id[] = { + { "ad7293", 0 }, + {} +}; +MODULE_DEVICE_TABLE(spi, ad7293_id); + +static const struct of_device_id ad7293_of_match[] = { + { .compatible = "adi,ad7293" }, + {} +}; +MODULE_DEVICE_TABLE(of, ad7293_of_match); + +static struct spi_driver ad7293_driver = { + .driver = { + .name = "ad7293", + .of_match_table = ad7293_of_match, + }, + .probe = ad7293_probe, + .id_table = ad7293_id, +}; +module_spi_driver(ad7293_driver); + +MODULE_AUTHOR("Antoniu Miclaus Date: Tue, 26 Oct 2021 11:20:11 +0300 Subject: [PATCH 068/407] iio: Kconfig.adi: Add AD7293 Add AD7293 to the IIO_ALL_ADI_DRIVERS kconfig option. Signed-off-by: Antoniu Miclaus --- drivers/iio/Kconfig.adi | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/Kconfig.adi b/drivers/iio/Kconfig.adi index ba97d1b21210d8..9357d65d55b081 100644 --- a/drivers/iio/Kconfig.adi +++ b/drivers/iio/Kconfig.adi @@ -36,6 +36,7 @@ config IIO_ALL_ADI_DRIVERS select AD7173 select AD7266 select AD7291 + select AD7293 select AD7298 select AD738X select AD7923 From fc747a3e830cf828f2f6c207c07cb06eb1fd330f Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 26 Oct 2021 11:27:46 +0300 Subject: [PATCH 069/407] dt-bindings: iio: addac: add ad7293 doc Add device tree bindings for the AD7293 PA. Signed-off-by: Antoniu Miclaus --- .../bindings/iio/dac/adi,ad7293.yaml | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml new file mode 100644 index 00000000000000..5ee80bf6aa11b4 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,ad7293.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AD7293 12-Bit Power Amplifier Current Controller with ADC, + DACs, Temperature and Current Sensors + +maintainers: + - Antoniu Miclaus + +description: | + Power Amplifier drain current controller containing functionality + for general-purpose monitoring and control of current, voltage, + and temperature, integrated into a single chip solution with an + SPI-compatible interface. + + https://www.analog.com/en/products/ad7293.html + +properties: + compatible: + enum: + - adi,ad7293 + + avdd-supply: true + + vdrive-supply: true + + reset-gpios: + maxItems: 1 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 1000000 + +required: + - compatible + - reg + - avdd-supply + - vdrive-supply + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + ad7293@0 { + compatible = "adi,ad7293"; + reg = <0>; + spi-max-frequency = <1000000>; + avdd-supply = <&avdd>; + vdrive-supply = <&vdrive>; + reset-gpios = <&gpio 10 0>; + }; + }; +... From 7972e7a1ce48ad80be92eeac2fe8b85a2cda934e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Wed, 22 Dec 2021 12:06:36 +0100 Subject: [PATCH 070/407] iio: adrv9002: add support for BBDC loop gain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for manipulating RX BBDC loop gain. Note that this is being supported with raw values because the loop gain is represented as a fractional value with 31bits representing the fractional part. This means that the resolution is pretty low and thus making it very hard to handle in the kernel. Hence, support this as raw and defer the floating point handling to userspace. Signed-off-by: Nuno Sá --- drivers/iio/adc/navassa/adrv9002.c | 22 +++++++++++++++++++++- drivers/iio/adc/navassa/adrv9002.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/navassa/adrv9002.c b/drivers/iio/adc/navassa/adrv9002.c index b3b3bb18c68348..2f341cc640905d 100644 --- a/drivers/iio/adc/navassa/adrv9002.c +++ b/drivers/iio/adc/navassa/adrv9002.c @@ -1142,6 +1142,7 @@ static ssize_t adrv9002_phy_rx_write(struct iio_dev *indio_dev, struct adrv9002_rx_chan *rx = &phy->rx_channels[channel]; struct adi_adrv9001_RxChannelCfg *rx_cfg = &phy->curr_profile->rx.rxChannelCfg[channel]; bool enable; + u32 val; mutex_lock(&phy->lock); if (!rx->channel.enabled && port == ADI_RX) { @@ -1230,6 +1231,15 @@ static ssize_t adrv9002_phy_rx_write(struct iio_dev *indio_dev, if (ret) ret = adrv9002_dev_err(phy); break; + case RX_BBDC_LOOP_GAIN: + ret = kstrtou32(buf, 10, &val); + if (ret) + goto unlock; + + ret = adi_adrv9010_bbdc_LoopGain_Set(phy->adrv9001, rx->channel.number, val); + if (ret) + ret = adrv9002_dev_err(phy); + break; default: ret = -EINVAL; } @@ -1247,7 +1257,7 @@ static ssize_t adrv9002_phy_rx_read(struct iio_dev *indio_dev, struct adrv9002_rf_phy *phy = iio_priv(indio_dev); int ret = 0; u16 dec_pwr_mdb; - u32 rssi_pwr_mdb; + u32 rssi_pwr_mdb, val; struct adi_adrv9001_TrackingCals tracking_cals; const u32 *calls_mask = tracking_cals.chanTrackingCalMask; const int channel = ADRV_ADDRESS_CHAN(chan->address); @@ -1346,6 +1356,15 @@ static ssize_t adrv9002_phy_rx_read(struct iio_dev *indio_dev, ret = sprintf(buf, "%d\n", bbdc); break; + case RX_BBDC_LOOP_GAIN: + ret = adi_adrv9010_bbdc_LoopGain_Get(phy->adrv9001, rx->channel.number, &val); + if (ret) { + mutex_unlock(&phy->lock); + return adrv9002_dev_err(phy); + } + + ret = sysfs_emit(buf, "%u\n", val); + break; default: ret = -EINVAL; } @@ -1659,6 +1678,7 @@ static const struct iio_chan_spec_ext_info adrv9002_phy_rx_ext_info[] = { _ADRV9002_EXT_RX_INFO("rfdc_tracking_en", RX_RFDC), _ADRV9002_EXT_RX_INFO("dynamic_adc_switch_en", RX_ADC_SWITCH), _ADRV9002_EXT_RX_INFO("bbdc_rejection_en", RX_BBDC), + _ADRV9002_EXT_RX_INFO("bbdc_loop_gain_raw", RX_BBDC_LOOP_GAIN), { }, }; diff --git a/drivers/iio/adc/navassa/adrv9002.h b/drivers/iio/adc/navassa/adrv9002.h index 7258569fe09522..0ee27facc7429f 100644 --- a/drivers/iio/adc/navassa/adrv9002.h +++ b/drivers/iio/adc/navassa/adrv9002.h @@ -81,6 +81,7 @@ enum adrv9002_rx_ext_info { RX_NCO_FREQUENCY, RX_ADC_SWITCH, RX_BBDC, + RX_BBDC_LOOP_GAIN, }; enum adrv9002_tx_ext_info { From 9c03014250ce0a1271abb534be486cf08dfba15a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Wed, 22 Dec 2021 18:25:33 +0100 Subject: [PATCH 071/407] iio: adrv9002: Update API to 48.42.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDK is taken as is which means that compilation will likely fail. The following patches will integrate the new SDK with linux and the existing driver code Signed-off-by: Nuno Sá --- .../adrv9001/private/include/adrv9001_arm.h | 32 + .../private/include/adrv9001_fh_types.h | 41 ++ .../bitfields/c0/adrv9001_nvs_regmap_core_2.h | 16 +- .../adrv9001/private/include/object_ids.h | 4 + .../adrv9001/private/src/adrv9001_arm.c | 186 +++++- .../public/include/adi_adrv9001_arm.h | 58 +- .../public/include/adi_adrv9001_arm_types.h | 2 +- .../public/include/adi_adrv9001_cals_types.h | 3 +- .../adi_adrv9001_deviceSysConfig_types.h | 1 + .../public/include/adi_adrv9001_dpd.h | 2 - .../public/include/adi_adrv9001_dpd_types.h | 8 +- .../adrv9001/public/include/adi_adrv9001_fh.h | 7 +- .../public/include/adi_adrv9001_fh_types.h | 17 +- .../public/include/adi_adrv9001_gpio.h | 49 +- .../public/include/adi_adrv9001_gpio_types.h | 74 +-- .../adi_adrv9001_powersavingandmonitormode.h | 2 +- ...adrv9001_powersavingandmonitormode_types.h | 1 + .../public/include/adi_adrv9001_radio_types.h | 3 +- .../adrv9001/public/include/adi_adrv9001_rx.h | 38 +- .../include/adi_adrv9001_rxSettings_types.h | 2 +- .../public/include/adi_adrv9001_rx_types.h | 34 +- .../public/include/adi_adrv9001_spi.h | 26 + .../public/include/adi_adrv9001_spi_types.h | 44 ++ .../adrv9001/public/include/adi_adrv9001_tx.h | 5 +- .../public/include/adi_adrv9001_tx_types.h | 3 + .../public/include/adi_adrv9001_types.h | 11 +- .../public/include/adi_adrv9001_user.h | 3 +- .../public/include/adi_adrv9001_version.h | 2 +- .../public/include/adrv9001_Init_t_parser.h | 7 +- .../adrv9001/public/src/adi_adrv9001_arm.c | 140 ++--- .../adrv9001/public/src/adi_adrv9001_dpd.c | 62 +- .../adrv9001/public/src/adi_adrv9001_fh.c | 573 +++++++++++------- .../adrv9001/public/src/adi_adrv9001_gpio.c | 60 +- .../adi_adrv9001_powersavingandmonitormode.c | 9 +- .../adrv9001/public/src/adi_adrv9001_radio.c | 1 + .../adrv9001/public/src/adi_adrv9001_rx.c | 227 ++++--- .../adrv9001/public/src/adi_adrv9001_spi.c | 94 +++ .../adrv9001/public/src/adi_adrv9001_ssi.c | 42 +- .../adrv9001/public/src/adi_adrv9001_tx.c | 91 ++- 39 files changed, 1347 insertions(+), 633 deletions(-) create mode 100644 drivers/iio/adc/navassa/devices/adrv9001/private/include/adrv9001_fh_types.h diff --git a/drivers/iio/adc/navassa/devices/adrv9001/private/include/adrv9001_arm.h b/drivers/iio/adc/navassa/devices/adrv9001/private/include/adrv9001_arm.h index 0310e0a73112e5..9bfa63bfd09c15 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/private/include/adrv9001_arm.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/private/include/adrv9001_arm.h @@ -27,6 +27,7 @@ extern "C" { /* ADI specific header files */ #include "adi_adrv9001.h" +#include "adi_adrv9001_fh_types.h" #include "adi_adrv9001_arm_types.h" /** @@ -69,6 +70,37 @@ int32_t adrv9001_DmaMemRead(adi_adrv9001_Device_t *device, uint32_t address, uin */ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, const uint8_t data[], uint32_t byteCount, adi_adrv9001_ArmSingleSpiWriteMode_e spiWriteMode); +/** +* \brief Write to the ADRV9001 ARM program or data memory +* +* The user must make sure the memory addresses are valid. +* +* \pre This function is private and is not called directly by the user. +* +* \param device Structure pointer to the ADRV9001 data structure containing settings +* \param[in] hopSignal Hop signal to configure appropriate tableId +* \param[in] tableId FH_HOP_TABLE_A or FH_HOP_TABLE_B. Used for ping-pong hop tables. +* \param hopTableAddress The 32-bit ARM address to write +* \param numHopTableEntries Byte Array (uint8_t) containing data to be written to ARM memory +* \param numHopTableEntriesByteCount Number of bytes in the data array to be written +* \param hopTableBufferAddress The 32-bit ARM address to write +* \param hopTableBufferData Byte Array (uint8_t) containing data to be written to ARM memory +* \param hopTableBufferDataByteCount Number of bytes in the data array to be written +* +* \retval ADI_COMMON_ACT_WARN_RESET_LOG Recovery action for log reset +* \retval ADI_COMMON_ACT_ERR_CHECK_PARAM Recovery action for bad parameter check +* \retval ADI_COMMON_ACT_ERR_RESET_INTERFACE Recovery action for SPI reset required +* \retval ADI_COMMON_ACT_NO_ACTION Function completed successfully, no action required +*/ +int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, + adi_adrv9001_FhHopSignal_e hopSignal, + adi_adrv9001_FhHopTable_e tableId, + uint32_t hopTableAddress, + const uint8_t numHopTableEntries[], + uint32_t numHopTableEntriesByteCount, + uint32_t hopTableBufferAddress, + const uint8_t hopTableBufferData[], + uint32_t hopTableBufferDataByteCount); /** * \brief Write to the ADRV9001 Flex Stream Processor(0 - 3) memory * diff --git a/drivers/iio/adc/navassa/devices/adrv9001/private/include/adrv9001_fh_types.h b/drivers/iio/adc/navassa/devices/adrv9001/private/include/adrv9001_fh_types.h new file mode 100644 index 00000000000000..f2b0bc579b459f --- /dev/null +++ b/drivers/iio/adc/navassa/devices/adrv9001/private/include/adrv9001_fh_types.h @@ -0,0 +1,41 @@ +/** + * \file + * \brief Contains ADRV9001 Frequency Hopping related private data types + * + * ADRV9001 API Version: $ADI_ADRV9001_API_VERSION$ + */ + + /** + * Copyright 2021 Analog Devices Inc. + * Released under the ADRV9001 API license, for more information + * see the "LICENSE.txt" file in this zip file. + */ + +#ifndef _ADRV9001_FH_TYPES_H_ +#define _ADRV9001_FH_TYPES_H_ + +#include "adi_adrv9001.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Settings for HOP frame information to match ARM firmware struct type + */ +typedef struct { + uint32_t hopFrequencyHz_LSB; /*!< Lower 32-bits of Operating frequency in Hz */ + uint32_t hopFrequencyHz_MSB; /*!< Upper 32-bits of Operating frequency in Hz */ + int32_t rx1OffsetFrequencyHz; /*!< Rx1 Offset frequency. This field is ignored by firmware if frame is not Rx, or if profile does not operate with an IF */ + int32_t rx2OffsetFrequencyHz; /*!< Rx2 Offset frequency. This field is ignored by firmware if frame is not Rx, or if profile does not operate with an IF */ + uint8_t tx1Attenuation_fifthdB; /*!< Tx1 attenuation expressed in 0.2dBs. LSB = 0.2dB. Range 0 to 209 (0 to 41.8 dB). This field is ignored if frame is Rx */ + uint8_t tx2Attenuation_fifthdB; /*!< Tx2 attenuation expressed in 0.2dBs. Range 0 to 209 (0 to 41.8 dB). This field is ignored if frame is Rx */ + uint8_t rx1GainIndex; /*!< Starting Rx1 gain index for hop frame. This field is ignored if frame is Tx */ + uint8_t rx2GainIndex; /*!< Starting Rx2 gain index for hop frame. This field is ignored if frame is Tx */ +} adrv9001_FhHopFrame_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _ADRV9001_FH_TYPES_H_ */ diff --git a/drivers/iio/adc/navassa/devices/adrv9001/private/include/bitfields/c0/adrv9001_nvs_regmap_core_2.h b/drivers/iio/adc/navassa/devices/adrv9001/private/include/bitfields/c0/adrv9001_nvs_regmap_core_2.h index d142d567da998a..a6b9ada97bea41 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/private/include/bitfields/c0/adrv9001_nvs_regmap_core_2.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/private/include/bitfields/c0/adrv9001_nvs_regmap_core_2.h @@ -161,10 +161,10 @@ static inline int32_t adrv9001_NvsRegmapCore2_Auxdac0_Set(void *const device, { int32_t status = 0; - status = adi_bf_hal_Field_Write(device, (0x400 + 0x1), (value >> 8), 0xf, 0x0); + status = adi_bf_hal_Register_Write(device, (0x400 + 0x0), (value >> 0)); if (0 != status) return status; - status = adi_bf_hal_Register_Write(device, (0x400 + 0x0), (value >> 0)); + status = adi_bf_hal_Field_Write(device, (0x400 + 0x1), (value >> 8), 0xf, 0x0); return status; } @@ -255,10 +255,10 @@ static inline int32_t adrv9001_NvsRegmapCore2_Auxdac1_Set(void *const device, { int32_t status = 0; - status = adi_bf_hal_Field_Write(device, (0x400 + 0x3), (value >> 8), 0xf, 0x0); + status = adi_bf_hal_Register_Write(device, (0x400 + 0x2), (value >> 0)); if (0 != status) return status; - status = adi_bf_hal_Register_Write(device, (0x400 + 0x2), (value >> 0)); + status = adi_bf_hal_Field_Write(device, (0x400 + 0x3), (value >> 8), 0xf, 0x0); return status; } @@ -349,10 +349,10 @@ static inline int32_t adrv9001_NvsRegmapCore2_Auxdac2_Set(void *const device, { int32_t status = 0; - status = adi_bf_hal_Field_Write(device, (0x400 + 0x5), (value >> 8), 0xf, 0x0); + status = adi_bf_hal_Register_Write(device, (0x400 + 0x4), (value >> 0)); if (0 != status) return status; - status = adi_bf_hal_Register_Write(device, (0x400 + 0x4), (value >> 0)); + status = adi_bf_hal_Field_Write(device, (0x400 + 0x5), (value >> 8), 0xf, 0x0); return status; } @@ -443,10 +443,10 @@ static inline int32_t adrv9001_NvsRegmapCore2_Auxdac3_Set(void *const device, { int32_t status = 0; - status = adi_bf_hal_Field_Write(device, (0x400 + 0x7), (value >> 8), 0xf, 0x0); + status = adi_bf_hal_Register_Write(device, (0x400 + 0x6), (value >> 0)); if (0 != status) return status; - status = adi_bf_hal_Register_Write(device, (0x400 + 0x6), (value >> 0)); + status = adi_bf_hal_Field_Write(device, (0x400 + 0x7), (value >> 8), 0xf, 0x0); return status; } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/private/include/object_ids.h b/drivers/iio/adc/navassa/devices/adrv9001/private/include/object_ids.h index 6980aeca6051fe..0fc026366f4742 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/private/include/object_ids.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/private/include/object_ids.h @@ -185,6 +185,7 @@ typedef enum OBJID_GS_DYNAMIC_PROFILE = GENERATE_OBJID(OBJ_GROUP_ID_GS, 0x1Au), /*!< 0x9A: Preload dynamic components of device profile */ OBJID_GS_FREQ_HOP_CONFIGURE = GENERATE_OBJID(OBJ_GROUP_ID_GS, 0x1Bu), /*!< 0x9B: Frequency Hopping commands */ OBJID_GS_TDD_TIMING_PARAMS = GENERATE_OBJID(OBJ_GROUP_ID_GS, 0x1Cu), /*!< 0x9C: Set TDD Timing parameters */ + OBJID_GS_LOID = GENERATE_OBJID(OBJ_GROUP_ID_GS, 0x1Du), /*!< 0x9d: set LO ID command parameters */ /* Configuration objects ids in OBJ_GROUP_ID_CFG group 1-to-1 mapping to IDs defined in cfgId_e @@ -211,6 +212,9 @@ typedef enum OBJID_CFG_GPIO_DEBUG_IN_STREAM = GENERATE_OBJID(OBJ_GROUP_ID_CFG, 0x13u), /*!< 0xB3: Configure GPIO debug in stream */ OBJID_CFG_CLK_PLL_TYPE = GENERATE_OBJID(OBJ_GROUP_ID_CFG, 0x14u), /*!< 0xB4: Configure clock PLL type */ OBJID_CFG_RX_GAIN_OVER_SSI = GENERATE_OBJID(OBJ_GROUP_ID_CFG, 0x15u), /*!< 0xB5: Configure RX slicer gain or agc gain, and gain index delay for 32-bit SSI */ + OBJID_CFG_SPI_MASTER_CONFIG = GENERATE_OBJID(OBJ_GROUP_ID_CFG, 0x16u), /*!< 0xB6: Configure SPI master to perform read/write transaction with slave device */ + OBJID_CFG_REFERENCE_TIMER_CONFIG = GENERATE_OBJID(OBJ_GROUP_ID_CFG, 0x17u), /*!< 0xB7: Configure Reference Timer */ + OBJID_CFG_REFERENCE_TIMER_START = GENERATE_OBJID(OBJ_GROUP_ID_CFG, 0x18u), /*!< 0xB8: Start Reference Timer */ /* Driver objects in OBJ_GROUP_ID_DRV group */ OBJID_DRV_NCO = GENERATE_OBJID(OBJ_GROUP_ID_DRV, 0x0u), /*!< 0xC0: NCO driver */ diff --git a/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c b/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c index 293b9bf563d26f..70265f5341d423 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c @@ -35,6 +35,7 @@ #include "adrv9001_init.h" #include "adrv9001_reg_addr_macros.h" #include "adrv9001_bf.h" +#include "adi_adrv9001_hal.h" /* Header files related to libraries */ @@ -67,6 +68,7 @@ #define ADRV9001_PROFILE_CHUNK_MAX 256u #define ADRV9001_DYNAMIC_PROFILE_BLOB_SIZE 164 +#define ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES 1536u const char* const adrv9001_error_table_ArmBootStatus[] = { "ARM is powering up", @@ -1155,8 +1157,7 @@ static void adrv9001_LoadRxByte(adi_adrv9001_Device_t *device, /* 'rxOffsetLo_kHz' is referred as 'offsetLo_Hz' in FW */ adrv9001_LoadFourBytes(&tempOffset, cfgData, KILO_TO_BASE_UNIT(rxProfile->rxOffsetLo_kHz)); - /* 'rxSignalOnLo' is referred as 'signalOnLo' in FW */ - cfgData[tempOffset++] = rxProfile->rxSignalOnLo; + cfgData[tempOffset++] = rxProfile->rxNcoEnable; cfgData[tempOffset++] = (uint8_t)(rxProfile->outputSignaling & 0xFF); @@ -1559,16 +1560,16 @@ typedef struct { duplexMode_e duplexMode; uint8_t fhModeOn; - uint8_t reserved1[1u]; //< Reserved for future feature - uint8_t numDynamicProfile; // Number of Profile. =1 means only one profile and no switching - mcsMode_e mcsMode; // MCS mode selection: 0 - Disable, 1 - MCS Only, 2 - MCS + RFPLL phase sync - adcType_e adcTypeMonitor; // ADC type used in Monitor Mode - uint16_t pllLockTime_us; // Required lock time in microseconds for PLLs, based on ref_clk and loop bandwidth - pllModulus_t pllModuli; // PLL moduli + uint8_t reserved1[1u]; //< Reserved for future feature + uint8_t numDynamicProfile; // Number of Profile. =1 means only one profile and no switching + mcsMode_e mcsMode; // MCS mode selection: 0 - Disable, 1 - MCS Only, 2 - MCS + RFPLL phase sync + adcType_e adcTypeMonitor; // ADC type used in Monitor Mode + uint16_t pllLockTime_us; // Required lock time in microseconds for PLLs, based on ref_clk and loop bandwidth + pllModulus_t pllModuli; // PLL moduli uint16_t pllPhaseSyncWait_us; // Worst case phase sync wait time in FH - mcsInf_e mcsInterfaceType; // NEW 0-Disabled, 1-CMOS, 2-LVDS - uint8_t padding[1u]; // 32 bit alignment - uint32_t reserved[1u]; // Reserved for future feature + mcsInf_e mcsInterfaceType; // 0-Disabled, 1-CMOS, 2-LVDS + uint8_t warmBootEnable; // Enable WarmBoot - Load initCal cefficients instead of running initCals + uint32_t reserved[1u]; // Reserved for future feature } deviceSysConfig_t; */ static void adrv9001_DeviceSysConfigWrite(adi_adrv9001_Device_t *device, const adi_adrv9001_DeviceSysConfig_t *sysConfig, uint8_t cfgData[], uint32_t *offset) @@ -1611,9 +1612,9 @@ static void adrv9001_DeviceSysConfigWrite(adi_adrv9001_Device_t *device, const a adrv9001_LoadTwoBytes(&tempOffset, cfgData, sysConfig->pllPhaseSyncWait_us); cfgData[tempOffset++] = sysConfig->mcsInterfaceType; + cfgData[tempOffset++] = sysConfig->warmBootEnable; - /* 8 bytes padding; Reserved for future use */ - tempOffset += 1; + /* 4 bytes padding; Reserved for future use */ tempOffset += 4; *offset = tempOffset; @@ -1955,6 +1956,9 @@ static __maybe_unused int32_t adrv9001_PfirFilterCoeffWrite(adi_adrv9001_Device_ &tempProfileAddr, &tempChecksum); + /* Needed for final checksum calculation */ + tempChecksum = adrv9001_Crc32ForChunk(&cfgData[0], 0, tempChecksum, 1); + adrv9001_LoadFourBytes(&offset, &cfgData[0], tempChecksum); /* Copy final Checksum in 'cfgData'*/ recoveryAction = adi_adrv9001_arm_Memory_Write(device, tempProfileAddr, &cfgData[0], offset, ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); ADI_ERROR_REPORT(&device->common, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, recoveryAction, NULL, "Error from adi_adrv9001_arm_Memory_Write()"); @@ -2161,7 +2165,161 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co ADI_API_RETURN(device); } - +int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHopSignal_e hopSignal, adi_adrv9001_FhHopTable_e tableId, uint32_t hopTableAddress, const uint8_t numHopTableEntries[], uint32_t numHopTableEntriesByteCount, uint32_t hopTableBufferAddress, const uint8_t hopTableBufferData[], uint32_t hopTableBufferDataByteCount) +{ + uint32_t i = 0; + uint32_t j = 0; + uint8_t regWrite = 0; + uint8_t bitmSwInt; + uint8_t autoInc = ADI_ADRV9001_ARM_MEM_AUTO_INCR; + uint32_t addrIndex = 0; + uint32_t dataIndex = 0; + uint32_t spiBufferSize = ((HAL_SPIWRITEARRAY_BUFFERSIZE / 3) - 1); + uint8_t spiWriteArrray[HAL_SPIWRITEARRAY_BUFFERSIZE] = { 0 }; + uint8_t addrMsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; + uint8_t addrLsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; + uint8_t dataArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; + uint32_t ADDR_ARM_DMA_DATA[4] = { ADRV9001_ADDR_ARM_DMA_DATA3, ADRV9001_ADDR_ARM_DMA_DATA2, ADRV9001_ADDR_ARM_DMA_DATA1, ADRV9001_ADDR_ARM_DMA_DATA0 }; + uint32_t index = 0; + + ADI_ENTRY_PTR_ARRAY_EXPECT(device, numHopTableEntries, numHopTableEntriesByteCount); + ADI_ENTRY_PTR_ARRAY_EXPECT(device, hopTableBufferData, hopTableBufferDataByteCount); + + /* Trigger appropriate SPI Interrupt upon table load */ + if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) + { + /* Set bit 0 to SW_INTERRUPT_4 to trigger SWInt4 to load FH table A + Set bit 1 to SW_INTERRUPT_4 to trigger SWInt11 to load FH table B */ + bitmSwInt = (tableId == ADI_ADRV9001_FHHOPTABLE_A) ? 0x1 : 0x2; + } + else + { + /* Set bit 7 to SW_INTERRUPT_4 to trigger SWInt5 to load FH table A + Set bit 6 to SW_INTERRUPT_4 to trigger SWInt6 to load FH table B */ + bitmSwInt = (tableId == ADI_ADRV9001_FHHOPTABLE_A) ? 0x80 : 0x40; + } + + ADRV9001_DMAINFO("ARM_MEM_WRITE", armMemAddress, byteCount); + + regWrite &= ~ADRV9001_DMA_CTL_RD_WRB; + regWrite |= ADRV9001_DMA_CTL_SYS_CODEB; + regWrite |= ADRV9001_BF_ENCODE(2, ADRV9001_DMA_CTL_BUS_SIZE_MASK, ADRV9001_DMA_CTL_BUS_SIZE_SHIFT); + /* address auto incremental, 1'b0=no; 1'b1=yes */ + /* core_bf.auto_incr.write(bf_status, 1'b0); */ + if (autoInc != 0) + { + regWrite |= ADRV9001_DMA_CTL_AUTO_INCR; + } + /* setting up the DMA control register for a write */ + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_CTL >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_CTL; + dataArray[addrIndex] = regWrite; + addrIndex++; + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR3 >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR3; + dataArray[addrIndex] = (uint8_t)((hopTableAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR3_BYTE_SHIFT); + addrIndex++; + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR2 >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR2; + dataArray[addrIndex] = (uint8_t)((hopTableAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR2_BYTE_SHIFT); + addrIndex++; + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR1 >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR1; + dataArray[addrIndex] = (uint8_t)((hopTableAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR1_BYTE_SHIFT); + addrIndex++; + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR0 >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR0; + dataArray[addrIndex] = (uint8_t)((hopTableAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR0_BYTE_SHIFT); + addrIndex++; + /* Cache Enable and Auto Inc */ + for (i = 0; i < numHopTableEntriesByteCount; i++) + { + /* Writing byte order: 3,2,1,0 */ + if (i == 0) + { + dataIndex = i + 3; + } + else + { + dataIndex--; + } + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADDR_ARM_DMA_DATA[i] >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADDR_ARM_DMA_DATA[i]; + dataArray[addrIndex] = numHopTableEntries[dataIndex]; + addrIndex++; + } + + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR3 >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR3; + dataArray[addrIndex] = (uint8_t)((hopTableBufferAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR3_BYTE_SHIFT); + addrIndex++; + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR2 >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR2; + dataArray[addrIndex] = (uint8_t)((hopTableBufferAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR2_BYTE_SHIFT); + addrIndex++; + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR1 >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR1; + dataArray[addrIndex] = (uint8_t)((hopTableBufferAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR1_BYTE_SHIFT); + addrIndex++; + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR0 >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR0; + dataArray[addrIndex] = (uint8_t)((hopTableBufferAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR0_BYTE_SHIFT); + addrIndex++; + + /* Cache Enable and Auto Inc */ + for (i = 0; i < hopTableBufferDataByteCount; i++) + { + index = hopTableBufferAddress % 4; + /* Writing byte order: 3,2,1,0 */ + if (index == 0) + { + dataIndex = i + 3; + } + else + { + dataIndex--; + } + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADDR_ARM_DMA_DATA[index] >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADDR_ARM_DMA_DATA[index]; + dataArray[addrIndex] = hopTableBufferData[dataIndex]; + if (addrIndex >= spiBufferSize) + { + for(j = 0 ; j <= addrIndex ; j++) + { + spiWriteArrray[3 * j] = addrMsbArray[j]; + spiWriteArrray[3 * j + 1] = addrLsbArray[j]; + spiWriteArrray[3 * j + 2] = dataArray[j]; + } + adi_hal_SpiWrite(device->common.devHalInfo, spiWriteArrray, 3 * j + 2); + addrIndex = 0; + } + else + { + addrIndex++; + } + hopTableBufferAddress++; + } + if (addrIndex > 0) + { + /* Issue SW interrupt 4 or 11 to load FH table A or B. The SPI reg is self-cleared so there is no need to do read/mod/write. */ + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_SW_INTERRUPT_4 >> 8) & 0x7F)); + addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_SW_INTERRUPT_4; + dataArray[addrIndex] = bitmSwInt; + for(j = 0 ; j <= addrIndex ; j++) + { + spiWriteArrray[3 * j] = addrMsbArray[j]; + spiWriteArrray[3 * j + 1] = addrLsbArray[j]; + spiWriteArrray[3 * j + 2] = dataArray[j]; + } + adi_hal_SpiWrite(device->common.devHalInfo, spiWriteArrray, 3 * j + 2); + } + else + { + ADRV9001_SPIWRITEBYTE(device, "ADRV9001_ADDR_SW_INTERRUPT_4", ADRV9001_ADDR_SW_INTERRUPT_4, bitmSwInt); + } + + ADI_API_RETURN(device); +} int32_t adrv9001_DmaMemRead(adi_adrv9001_Device_t *device, uint32_t address, uint8_t returnData[], uint32_t byteCount, uint8_t autoIncrement) { int32_t recoveryAction = ADI_COMMON_ACT_NO_ACTION; diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_arm.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_arm.h index 1a32c16ee0ba9a..7683e754d18241 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_arm.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_arm.h @@ -214,7 +214,29 @@ int32_t adi_adrv9001_arm_Memory_Read(adi_adrv9001_Device_t *adrv9001, uint8_t returnData[], uint32_t byteCount, uint8_t autoIncrement); - +/** + * \brief Read from the ADRV9001 ARM program or data memory + * + * Valid memory addresses are: Program Memory (0x01000000 - 0x0101C000), + * Data Memory (0x20000000 - 0x20014000). + * + * \note Message type: \ref timing_direct "Direct register access" + * + * \pre This function is private and is not called directly by the user. + * + * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure + * \param[in] address The 32bit ARM address to read from. + * \param[out] returnData Byte array containing the data read from the ARM memory. + * \param[in] byteCount Number of bytes in the returnData array. + * \param[in] autoIncrement Boolean flag to enable or disable auto-increment of ARM register address + * + * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover + */ +int32_t adi_adrv9001_arm_Memory_Read32(adi_adrv9001_Device_t *adrv9001, + uint32_t address, + uint32_t returnData[], + uint32_t byteCount, + uint8_t autoIncrement); /** * \brief Write to the ADRV9001 ARM program or data memory * 'ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252' and 'ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4' @@ -241,6 +263,40 @@ int32_t adi_adrv9001_arm_Memory_Write(adi_adrv9001_Device_t *adrv9001, uint32_t byteCount, adi_adrv9001_ArmSingleSpiWriteMode_e spiWriteMode); +/** +* \brief Write to the ADRV9001 ARM program or data memory +* 'ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252' and 'ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4' +* are supported only if byteCount is a multiple of 4 +* +* Valid memory addresses are: Program Memory (0x01000000 - 0x0101C000), +* Data Memory (0x20000000 - 0x20014000). +* +* \note Message type: \ref timing_direct "Direct register access" +* +* \pre This function is private and is not called directly by the user. +* +* \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure +* \param[in] hopSignal Hop signal to configure appropriate tableId +* \param[in] tableId FH_HOP_TABLE_A or FH_HOP_TABLE_B. Used for ping-pong hop tables. +* \param[in] hopTableAddress The 32-bit ARM address to write +* \param[in] numHopTableEntries Byte Array (uint8_t) containing data to be written to ARM memory +* \param[in] numHopTableEntriesByteCount Number of bytes in the data array to be written +* \param[in] hopTableBufferAddress The 32-bit ARM address to write +* \param[in] hopTableBufferData Byte Array (uint8_t) containing data to be written to ARM memory +* \param[in] hopTableBufferDataByteCount Number of bytes in the data array to be written +* +* \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover +*/ +int32_t adi_adrv9001_arm_Memory_WriteFH(adi_adrv9001_Device_t *adrv9001, + adi_adrv9001_FhHopSignal_e hopSignal, + adi_adrv9001_FhHopTable_e tableId, + uint32_t hopTableAddress, + const uint8_t numHopTableEntries[], + uint32_t numHopTableEntriesByteCount, + uint32_t hopTableBufferAddress, + const uint8_t hopTableBufferData[], + uint32_t hopTableBufferDataByteCount); + /** * \brief Low level helper function used by ADRV9001 API to write the ARM memory config structures * diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_arm_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_arm_types.h index 839dcf92714fa9..d5d72c49244b09 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_arm_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_arm_types.h @@ -129,7 +129,7 @@ typedef struct adi_adrv9001_ChecksumTable adi_adrv9001_Checksum_t fwCheckSums; adi_adrv9001_Checksum_t streamsCheckSum[ADRV9001_MAX_NUM_STREAM]; adi_adrv9001_Checksum_t deviceProfileCheckSum; - adi_adrv9001_Checksum_t adcProfilefwCheckSum; + adi_adrv9001_Checksum_t pfirProfileCheckSum; uint32_t fwError; uint32_t fwErrorCode; } adi_adrv9001_ChecksumTable_t; diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals_types.h index 75629e7bccbe95..ad2ff7cc021af8 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals_types.h @@ -63,8 +63,7 @@ typedef enum adi_adrv9001_TrackingCalibrations ADI_ADRV9001_TRACKING_CAL_TX_LO_LEAKAGE = 0x00000002, //!< Tx LO Leakage ADI_ADRV9001_TRACKING_CAL_TX_LB_PD = 0x00000004, //!< Tx Loopback path delay ADI_ADRV9001_TRACKING_CAL_TX_PAC = 0x00000008, //!< Tx Power Amplifier Correction - ADI_ADRV9001_TRACKING_CAL_TX_DPD = 0x00000010, //!< Tx Digital Pre Distortion - ADI_ADRV9001_TRACKING_CAL_TX_CLGC = 0x00000020, //!< Tx Close Loop Gain Control + ADI_ADRV9001_TRACKING_CAL_TX_DPD_CLGC = 0x00000010, //!< Tx Digital Pre Distortion and Close Loop Gain Control /* Bit 6-7: Not used (Reserved for future purpose) */ ADI_ADRV9001_TRACKING_CAL_RX_HD2 = 0x00000100, //!< Rx Harmonic Distortion ADI_ADRV9001_TRACKING_CAL_RX_QEC_WBPOLY = 0x00000200, //!< Rx Quadrature Error Correction Wideband Poly diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_deviceSysConfig_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_deviceSysConfig_types.h index 6a1c47ed9c62a4..4c75fa4e39640a 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_deviceSysConfig_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_deviceSysConfig_types.h @@ -71,6 +71,7 @@ typedef struct adi_adrv9001_DeviceSysConfig uint16_t pllLockTime_us; /*!< Required lock time in microseconds for PLLs, based on ref_clk and loop bandwidth */ uint16_t pllPhaseSyncWait_us; /*!< Worst case phase sync wait time in FH */ adi_adrv9001_pllModulus_t pllModulus; /*!< PLL modulus */ + bool warmBootEnable; /*!< Enable WarmBoot - Load initCal cefficients instead of running initCals */ } adi_adrv9001_DeviceSysConfig_t; #endif /* _ADI_ADRV9001_DEVICESYSCONFIG_TYPES_H_ */ diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd.h index 468e2d0d9e4f9b..d26e0dc7b0eb1b 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd.h @@ -57,8 +57,6 @@ int32_t adi_adrv9001_dpd_Initial_Inspect(adi_adrv9001_Device_t *adrv9001, * * \note Message type: \ref timing_mailbox "Mailbox command" * - * \pre Channel state is CALIBRATED - * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] channel The channel to configure * \param[in] dpdConfig The desired DPD configuration diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd_types.h index 6e12293c382496..7dadd74819fd81 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd_types.h @@ -77,7 +77,7 @@ typedef enum adi_adrv9001_DpdModel typedef struct adi_adrv9001_DpdInitCfg { bool enable; /*!< When true, the DPD actuator is placed in the datapath and - * ADI_ADRV9001_TRACKING_CAL_TX_DPD may be used to enable DPD */ + * ADI_ADRV9001_TRACKING_CAL_TX_DPD_CLGC may be used to enable DPD */ adi_adrv9001_DpdAmplifier_e amplifierType; //!< Type of Power Amplifier adi_adrv9001_DpdLutSize_e lutSize; //!< Bit size of the DPD LUT adi_adrv9001_DpdModel_e model; //!< DPD Model to be used @@ -86,6 +86,7 @@ typedef struct adi_adrv9001_DpdInitCfg * terms are included in the model (and thus the auto-correlation * matrix). Used when #changeModelTapOrders is true */ uint8_t preLutScale; //!< Prescaler for the LUT (U2.2; min = 0; max = 3.75) */ + uint8_t clgcEnable; //!< CLGC Enable */ } adi_adrv9001_DpdInitCfg_t; /** @@ -131,6 +132,11 @@ typedef struct adi_adrv9001_DpdCfg uint32_t timeFilterCoefficient; /*!< Time filter coefficient in U1.31 format */ uint32_t dpdSamplingRate_Hz; /*!< sampling rate in Hz for the DPD actuator and capture. 'dpdSamplingRate_Hz' is read only and is ignored in adi_adrv9001_dpd_Configure() */ + uint8_t clgcLoopOpen; /*!< If true, the loop is open and the TX attenuators are not updated. Used to measure a target gain. */ + int32_t clgcGainTarget_HundredthdB; /*!< Sent in 1/100 dB. */ + uint32_t clgcFilterAlpha; /*!< filter coefficient for the filtered gain values. */ + int32_t clgcLastGain_HundredthdB; /*!< last gain. Only valid during Get. */ + int32_t clgcFilteredGain_HundredthdB; /*!< filtered gain. Only valid during Get. */ } adi_adrv9001_DpdCfg_t; typedef struct adi_adrv9001_DpdCoefficients diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh.h index e8c8fcc9079a3f..c01b1500c55a23 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh.h @@ -160,7 +160,7 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, /** * \brief Trigger the hop signal by either SPI or mailbox * - * Thia API will have no effect if it is called before any channel, + * This API will have no effect if it is called before any channel, * enabled for frequency hopping, is in PRIMED state. * * \pre Channel state is PRIMED RF_ENABLED @@ -175,7 +175,10 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, int32_t adi_adrv9001_fh_Hop(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal); /** - * \brief Load a frequency hopping table into ARM memory dynamically + * \brief Generate a spiPackedFhTable array containing the SPI Transactions necessary to load FH Tables Dynamically from FPGA Memory to ADRV9001 ARM Memory + * + * This function does not send the SPI Transactions to load ADRV9001 ARM Memory, instead it generates a spiPackedFhTable + * that can be used by FPGA to dynamically load FH Tables based on TDD signal activity * * \pre This function can be called by the user anytime after initialization. * diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h index 7a4a300774cced..a6c5a972371008 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h @@ -97,7 +97,7 @@ typedef enum { } adi_adrv9001_FhFrameIndex_e; /** - * \brief Enumeration of FH per dynamic load type + * \brief Enumeration of FH per dynamic load type used by FPGA in ADI eval system, not necesary in customer application */ typedef enum adi_adrv9001_FhPerDynamicLoad { @@ -127,12 +127,13 @@ typedef enum { * \brief Settings for HOP frame information */ typedef struct { - uint64_t hopFrequencyHz; /*!< Operating frequency in Hz */ - int32_t rx1OffsetFrequencyHz; /*!< Rx1 Offset frequency. This field is ignored by firmware if frame is not Rx, or if profile does not operate with an IF */ - int32_t rx2OffsetFrequencyHz; /*!< Rx2 Offset frequency. This field is ignored by firmware if frame is not Rx, or if profile does not operate with an IF */ - uint8_t rxGainIndex; /*!< Starting gain index for hop frame. This field is ignored if frame is Tx */ - uint8_t reserved; /*!< For word alignment */ - uint16_t txAttenuation_mdB; /*!< Tx attenuation index. This field is ignored if frame is Rx */ + int32_t rx1OffsetFrequencyHz; /*!< Rx1 Offset frequency. This field is ignored by firmware if frame is not Rx */ + int32_t rx2OffsetFrequencyHz; /*!< Rx2 Offset frequency. This field is ignored by firmware if frame is not Rx */ + uint8_t tx1Attenuation_fifthdB; /*!< Tx1 attenuation expressed in 0.2dBs. LSB = 0.2dB. Range 0 to 209 (0 to 41.8 dB). This field is ignored if frame is Rx */ + uint8_t tx2Attenuation_fifthdB; /*!< Tx2 attenuation expressed in 0.2dBs. Range 0 to 209 (0 to 41.8 dB). This field is ignored if frame is Rx */ + uint8_t rx1GainIndex; /*!< Starting Rx1 gain index for hop frame. This field is ignored if frame is Tx */ + uint8_t rx2GainIndex; /*!< Starting Rx2 gain index for hop frame. This field is ignored if frame is Tx */ + uint64_t hopFrequencyHz; /*!< Operating frequency in Hz */ } adi_adrv9001_FhHopFrame_t; /** @@ -192,7 +193,7 @@ typedef struct { adi_adrv9001_GpioCfg_t tableIndexGpioConfig[ADI_ADRV9001_FH_MAX_NUM_FREQ_SELECT_PINS]; /*!< Pin configuration for table index select. Ignored if tableIndexCtrl is not ADI_ADRV9001_TABLEINDEXCTRL_GPIO */ bool gainSetupByPin; /*!< Use GPIO Pins to provide a Tx/Rx gain index for next hop frame. If false, gain information is provided in hop table*/ - adi_adrv9001_FhGainSetupByPinCfg_t gainSetupByPinConfig; /*!< Configuration information for gain setup by pin. This structure is ignored if gainSetupByPin is false */ + adi_adrv9001_FhGainSetupByPinCfg_t gainSetupByPinConfig[ADI_ADRV9001_NUM_CHANNELS]; /*!< Configuration information for gain setup by pin. This structure is ignored if gainSetupByPin is false */ } adi_adrv9001_FhCfg_t; #ifdef __cplusplus diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h index a3eb3ff0d59b57..68f201360348d8 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h @@ -120,7 +120,7 @@ int32_t adi_adrv9001_gpio_GpIntStatus_Get(adi_adrv9001_Device_t *adrv9001, uint3 * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_OutputPinLevel_Set(adi_adrv9001_Device_t *adrv9001, - adi_adrv9001_GpioPin_e pin, + adi_adrv9001_GpioPin_e pin, adi_adrv9001_GpioPinLevel_e level); /** @@ -158,75 +158,58 @@ int32_t adi_adrv9001_gpio_OutputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin, adi_adrv9001_GpioPinLevel_e *gpioInPinLevels); - -/** - * \brief Reads the ADRV9001 GPIO pin direction for BITBANG mode - * - * This function allows reading the direction of the GPIO - * - * \note Message type: \ref timing_direct "Direct register access" - * - * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure - * \param[in] pin The pin for which to get the direction - * \param[out] direction Current direction of the pin - * - * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover - */ -int32_t adi_adrv9001_gpio_PinDirection_Get(adi_adrv9001_Device_t *device, - adi_adrv9001_GpioPin_e pin, - adi_adrv9001_GpioPinDirection_e *direction); - + /** * \brief Configure specified pin as manual input - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] pin The GPIO pin to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_ManualInput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin); - + /** * \brief Configure specified pin crumb as manual output - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] crumb The GPIO pin crumb to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_ManualOutput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPinCrumbSel_e crumb); /** * \brief Configure specified analog GPIO pin as manual input - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] pin The analog GPIO pin to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin); /** * \brief Configure specified analog GPIO pin nibble as manual output - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] nibble The analog GPIO pin nibble to configure * \param[in] source The source signal to be output on the pins - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioAnalogPinNibbleSel_e nibble); /** @@ -241,7 +224,7 @@ int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *ad */ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioCtrlInitCfg_t *gpioCtrlInitCfg); - + /** * \brief Configure the ADRV9001 GPIO for the specified signal * @@ -258,7 +241,7 @@ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, int32_t adi_adrv9001_gpio_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioSignal_e signal, adi_adrv9001_GpioCfg_t *gpioConfig); - + /** * \brief Retrieve the ADRV9001 GPIO configuration for the requested signal * diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h index b5fddb856b41ea..6a1baf0c3d7194 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h @@ -150,23 +150,26 @@ typedef enum adi_adrv9001_GpioPinLevel typedef enum adi_adrv9001_GpioSignal { /* Digital GPIO Functions */ - ADI_ADRV9001_GPIO_SIGNAL_ORX_ENABLE_1, /*!< ORx Enable signal channel 1 */ - ADI_ADRV9001_GPIO_SIGNAL_ORX_ENABLE_2, /*!< ORx Enable signal channel 2 */ - ADI_ADRV9001_GPIO_SIGNAL_MON_ENABLE_SPS, /*!< Monitor mode enable and System Power Saving request signal */ - ADI_ADRV9001_GPIO_SIGNAL_MON_BBIC_WAKEUP, /*!< Monitor mode signal to wake up the BBIC */ - ADI_ADRV9001_GPIO_SIGNAL_POWER_SAVING_CHANNEL1, /*!< Power saving signal for channel 1 */ - ADI_ADRV9001_GPIO_SIGNAL_POWER_SAVING_CHANNEL2, /*!< Power saving signal for channel 2 */ - ADI_ADRV9001_GPIO_SIGNAL_FH_HOP, /*!< Frequency hopping hop request signal */ - ADI_ADRV9001_GPIO_SIGNAL_FH_GAIN_SEL_0, /*!< Frequency hopping gain select bit 0 */ - ADI_ADRV9001_GPIO_SIGNAL_FH_GAIN_SEL_1, /*!< Frequency hopping gain select bit 1 */ - ADI_ADRV9001_GPIO_SIGNAL_FH_GAIN_SEL_2, /*!< Frequency hopping gain select bit 2 */ - ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_0, /*!< Frequency hopping frequency index select bit 0 */ - ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_1, /*!< Frequency hopping frequency index select bit 1 */ - ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_2, /*!< Frequency hopping frequency index select bit 2 */ - ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_3, /*!< Frequency hopping frequency index select bit 3 */ - ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_4, /*!< Frequency hopping frequency index select bit 4 */ - ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_5, /*!< Frequency hopping frequency index select bit 5 */ - ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_TABLE_SELECT, /*!< Frequency hopping Hop table select signal */ + ADI_ADRV9001_GPIO_SIGNAL_ORX_ENABLE_1, /*!< ORx Enable signal channel 1 */ + ADI_ADRV9001_GPIO_SIGNAL_ORX_ENABLE_2, /*!< ORx Enable signal channel 2 */ + ADI_ADRV9001_GPIO_SIGNAL_MON_ENABLE_SPS, /*!< Monitor mode enable and System Power Saving request signal */ + ADI_ADRV9001_GPIO_SIGNAL_MON_BBIC_WAKEUP, /*!< Monitor mode signal to wake up the BBIC */ + ADI_ADRV9001_GPIO_SIGNAL_POWER_SAVING_CHANNEL1, /*!< Power saving signal for channel 1 */ + ADI_ADRV9001_GPIO_SIGNAL_POWER_SAVING_CHANNEL2, /*!< Power saving signal for channel 2 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_HOP, /*!< Frequency hopping hop request signal */ + ADI_ADRV9001_GPIO_SIGNAL_FH_CH1_GAIN_ATTEN_SEL_0, /*!< Frequency hopping Channel1 gain/atten select bit 0 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_CH1_GAIN_ATTEN_SEL_1, /*!< Frequency hopping Channel1 gain/atten select bit 1 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_CH1_GAIN_ATTEN_SEL_2, /*!< Frequency hopping Channel1 gain/atten select bit 2 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_CH2_GAIN_ATTEN_SEL_0, /*!< Frequency hopping Channel2 gain/atten select bit 0 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_CH2_GAIN_ATTEN_SEL_1, /*!< Frequency hopping Channel2 gain/atten select bit 1 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_CH2_GAIN_ATTEN_SEL_2, /*!< Frequency hopping Channel2 gain/atten select bit 2 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_0, /*!< Frequency hopping frequency index select bit 0 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_1, /*!< Frequency hopping frequency index select bit 1 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_2, /*!< Frequency hopping frequency index select bit 2 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_3, /*!< Frequency hopping frequency index select bit 3 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_4, /*!< Frequency hopping frequency index select bit 4 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_5, /*!< Frequency hopping frequency index select bit 5 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_TABLE_SELECT, /*!< Frequency hopping Hop table select signal */ ADI_ADRV9001_GPIO_SIGNAL_TX1_PA_RAMP_CTRL, /*!< Tx1 Aux DAC ramp control request signal*/ ADI_ADRV9001_GPIO_SIGNAL_TX2_PA_RAMP_CTRL, /*!< Tx2 Aux DAC ramp control request signal*/ @@ -194,41 +197,10 @@ typedef enum adi_adrv9001_GpioSignal ADI_ADRV9001_GPIO_SIGNAL_AUX_ADC_3, /*!< Aux ADC control 3 signal */ ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2, /*!< Frequency hopping hop request signal */ - ADI_ADRV9001_GPIO_SIGNAL_TX_CAL_EN, /*!< Tx channel 1 and 2 calibration enable signal */ - ADI_ADRV9001_GPIO_SIGNAL_CAL_UPDATE, /*!< Calibration update selection signal */ - ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2_TABLE_SELECT, /*!< Frequency hopping table select for HOP 2 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2_TABLE_SELECT = 42, /*!< Frequency hopping table select for HOP 2 */ - ADI_ADRV9001_GPIO_SIGNAL_RX1_LNA_ATTENUATION_1, /*!< Rx1 LNA attenuation control 1 */ - ADI_ADRV9001_GPIO_SIGNAL_RX1_LNA_ATTENUATION_2, /*!< Rx1 LNA attenuation control 2 */ - ADI_ADRV9001_GPIO_SIGNAL_RX2_LNA_ATTENUATION_1, /*!< Rx2 LNA attenuation control 1 */ - ADI_ADRV9001_GPIO_SIGNAL_RX2_LNA_ATTENUATION_2, /*!< Rx1 LNA attenuation control 2 */ - ADI_ADRV9001_GPIO_SIGNAL_TX1_ATTN_INCREMENT, /*!< Tx1 Attenuation Increment request signal */ - ADI_ADRV9001_GPIO_SIGNAL_TX1_ATTN_DECREMENT, /*!< Tx1 Attenuation Decrement request signal */ - ADI_ADRV9001_GPIO_SIGNAL_TX2_ATTN_INCREMENT, /*!< Tx2 Attenuation Increment request signal */ - ADI_ADRV9001_GPIO_SIGNAL_TX2_ATTN_DECREMENT, /*!< Tx2 Attenuation Decrement request signal */ - - ADI_ADRV9001_GPIO_SIGNAL_RX1_GAIN_CTRL_FEEDBACK_LSBS, /*!< Rx1 AGC Feedback Signals Least Significant Bits */ - ADI_ADRV9001_GPIO_SIGNAL_RX2_GAIN_CTRL_FEEDBACK_LSBS, /*!< Rx2 AGC Feedback Signals Least Significant Bits */ - ADI_ADRV9001_GPIO_SIGNAL_RX1_GAIN_CTRL_FEEDBACK_MSBS, /*!< Rx1 AGC Feedback Signals Most Significant Bits */ - ADI_ADRV9001_GPIO_SIGNAL_RX2_GAIN_CTRL_FEEDBACK_MSBS, /*!< Rx2 AGC Feedback Signals Most Significant Bits */ - ADI_ADRV9001_GPIO_SIGNAL_TX1_SSI_REF_CLK, /*!< Tx1 Synchronous Serial Interface Reference Clock Signal */ - ADI_ADRV9001_GPIO_SIGNAL_TX2_SSI_REF_CLK, /*!< Tx2 Synchronous Serial Interface Reference Clock Signal */ - ADI_ADRV9001_GPIO_SIGNAL_DIGITAL_GPIO_MANUAL_INPUT, /*!< Digital GPIO Input Signal */ - ADI_ADRV9001_GPIO_SIGNAL_DIGITAL_GPIO_MANUAL_OUTPUT, /*!< Digital GPIO Output Signal */ - ADI_ADRV9001_GPIO_SIGNAL_ANALOG_GPIO_MANUAL_INPUT, /*!< Analog GPIO Input Signal */ - ADI_ADRV9001_GPIO_SIGNAL_ANALOG_GPIO_MANUAL_OUTPUT, /*!< Analog GPIO Output Signal */ - ADI_ADRV9001_GPIO_SIGNAL_ANALOG_GPIO_MIRROR, /*!< Mirror the value of a Digital GPIO signal as the source for the Analog GPIO Output signal */ - ADI_ADRV9001_GPIO_SIGNAL_MODE_CTRL, /*!< MODE control Signal */ - ADI_ADRV9001_GPIO_SIGNAL_JTAG_CTRL, /*!< JTAG control Signal */ - - /* TODO: Remove? */ - ADI_ADRV9001_GPIO_SIGNAL_RX1_GAIN_INCREMENT, /*!< Rx1 Gain Increment request signal */ - ADI_ADRV9001_GPIO_SIGNAL_RX1_GAIN_DECREMENT, /*!< Rx1 Gain Decrement request signal */ - ADI_ADRV9001_GPIO_SIGNAL_RX2_GAIN_INCREMENT, /*!< Rx2 Gain Increment request signal */ - ADI_ADRV9001_GPIO_SIGNAL_RX2_GAIN_DECREMENT, /*!< Rx2 Gain Decrement request signal */ - - ADI_ADRV9001_GPIO_NUM_SIGNALS, /*!< Total Number of signals from BBIC */ + ADI_ADRV9001_GPIO_NUM_SIGNALS = 43, /*!< Total Number of signals from BBIC */ } adi_adrv9001_GpioSignal_e; /** @@ -282,8 +254,6 @@ typedef struct adi_adrv9001_GpioCtrlInitCfg adi_adrv9001_GpioCfg_t channelPowerSaving[ADI_ADRV9001_NUM_CHANNELS]; /*!< (DGPIO) Channel Power Saving Enables */ adi_adrv9001_GpioCfg_t systemPowerSavingAndMonitorEnable; /*!< (DGPIO) System Power Saving and Monitor Enable */ adi_adrv9001_GpioCfg_t systemPowerSavingAndMonitorWakeUp; /*!< (DGPIO) Monitor WakeUp */ - adi_adrv9001_GpioCfg_t rx1ExternalLnaPinCfg[2]; /*!< (AGPIO) Rx1 External LNA attenuation control 1 and 2 */ - adi_adrv9001_GpioCfg_t rx2ExternalLnaPinCfg[2]; /*!< (AGPIO) Rx2 External LNA attenuation control 1 and 2 */ } adi_adrv9001_GpioCtrlInitCfg_t; diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_powersavingandmonitormode.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_powersavingandmonitormode.h index 66d261078fa673..52770675e0ffb7 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_powersavingandmonitormode.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_powersavingandmonitormode.h @@ -168,7 +168,7 @@ int32_t adi_adrv9001_powerSavingAndMonitorMode_MonitorMode_Vector_Inspect(adi_ad * * \note Message type: \ref timing_mailbox "Mailbox command" * - * \pre Channel state is STANDBY + * \pre Channel state is STANDBY, CALIBRATED or PRIMED * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] monitorModeRssiCfg The desired monitor mode RSSI configuration settings diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_powersavingandmonitormode_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_powersavingandmonitormode_types.h index ad49a0e173bf3a..e342d5090cafc9 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_powersavingandmonitormode_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_powersavingandmonitormode_types.h @@ -88,6 +88,7 @@ typedef struct adi_adrv9001_PowerSavingAndMonitorMode_SystemPowerSavingAndMonito uint32_t sleepTime_us; /*!< Timer for sleep state (us) */ uint8_t detectionFirst; /*!< Select first state when entering Monitor Mode, 0-sleep first, 1-detection first */ adi_adrv9001_PowerSavingAndMonitorMode_MonitorDetectionMode_e detectionMode; /*!< Mode of detection in the detect state */ + bool bbicWakeupLevelEnable; /*!< Enable ADI_ADRV9001_GPIO_SIGNAL_MON_BBIC_WAKEUP as a Level instead of Pulse (0 = Pulse, 1 = Level) */ bool externalPllEnable; /*!< External PLL Enable, 0-disable, 1-enable */ } adi_adrv9001_PowerSavingAndMonitorMode_SystemPowerSavingAndMonitorModeCfg_t; diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_radio_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_radio_types.h index e95e1d772a5b4f..ef34f58fc4b824 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_radio_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_radio_types.h @@ -70,8 +70,9 @@ typedef struct adi_adrv9001_Carrier */ adi_adrv9001_LoGenOptimization_e loGenOptimization; uint64_t carrierFrequency_Hz; /*!< Carrier frequency, denoted in Hz. Valid range: 30MHz to 6 GHz*/ - int32_t intermediateFrequency_Hz; /*!< Intermediate frequency, denoted in Hz. + int32_t intermediateFrequency_Hz; /*!< Intermediate frequency, denoted in Hz. Valid range: between +/- min(20 MHz, rfChannelBandwidth_Hz /2)) */ + adi_adrv9001_RxRfInputSel_e manualRxport; /*!< Port selection to manually switch Rx port */ } adi_adrv9001_Carrier_t; /** diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx.h index 8bbe6be1213cae..d04dfa308a6fce 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx.h @@ -125,9 +125,6 @@ int32_t adi_adrv9001_Rx_GainTable_Read(adi_adrv9001_Device_t *adrv9001, * Clocks are disabled in the following transitions: * RF_ENABLED->PRIMED * - * \pre If gain control mode is ADI_ADRV9001_RX_GAIN_CONTROL_MODE_PIN: - * channel state is any of CALIBRATED, PRIMED, RF_ENABLED - * and can only take action in RF_ENABLED * \pre If gain control mode is ADI_ADRV9001_RX_GAIN_CONTROL_MODE_SPI: * channel state is any of STANDBY, CALIBRATED, PRIMED, RF_ENABLED * @@ -488,7 +485,42 @@ int32_t adi_adrv9001_Rx_ExternalLna_DigitalGainDelay_Set(adi_adrv9001_Device_t * int32_t adi_adrv9001_Rx_ExternalLna_DigitalGainDelay_Get(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, uint16_t *lnaDigitalGainDelay); + +/** + * \brief Configure LOID settings + * + * \note Message type: \ref timing_mailbox "Mailbox command" + * + * \pre channel state is any of STANDBY, CALIBRATED + * + * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure + * \param[in] channel The channel to configure + * \param[in] loidConfig The desired LOID configuration + * + * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover + */ +int32_t adi_adrv9001_Rx_Loid_Configure(adi_adrv9001_Device_t *adrv9001, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxrfdcLoidCfg_t *loidConfig); + +/** + * \brief Inspect LOID settings + * + * \note Message type: \ref timing_mailbox "Mailbox command" + * + * \pre channel state is any of STANDBY, CALIBRATED, PRIMED, RF_ENABLED + * + * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure + * \param[in] channel The channel to configure + * \param[out] loidConfig The current LOID configuration + * + * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover + */ +int32_t adi_adrv9001_Rx_Loid_Inspect(adi_adrv9001_Device_t *adrv9001, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxrfdcLoidCfg_t *loidConfig); + #ifdef __cplusplus } #endif diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rxSettings_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rxSettings_types.h index eeb1c07a1b7e57..bf0b59c2071417 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rxSettings_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rxSettings_types.h @@ -400,7 +400,7 @@ typedef struct adi_adrv9001_RxProfile uint32_t rxOutputRate_Hz; /*!< Rx output data rate in Hz */ uint32_t rxInterfaceSampleRate_Hz; /*!< Rx sample rate at serial interface */ int32_t rxOffsetLo_kHz; /*!< Offset in kHz. 0: On LO */ - uint8_t rxSignalOnLo; /*!< !0: Signal on LO 0: no signal on LO */ + bool rxNcoEnable; /*!< Enable NCO in Rx datapath. NCO must be enabled if rxOffsetLo_kHz > 0 */ adi_adrv9001_RxSignalType_e outputSignaling; /*!< Output to BBIC signal type */ uint8_t filterOrder; /*!< 1st or 2nd order ABBF filter */ uint8_t filterOrderLp; /*!< 1st or 2nd order ABBF filter Low Power ADC*/ diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h index 982bd06b7957fb..d780384ff4c2ae 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h @@ -128,8 +128,13 @@ typedef enum adi_adrv9001_rxManualGainPeakPowerSignalSel typedef struct adi_adrv9001_RxInterfaceGainCtrl { adi_adrv9001_RxInterfaceGainUpdateTiming_e updateInstance; - adi_adrv9001_RxInterfaceGainCtrlMode_e controlMode; - adi_adrv9001_RxInterfaceGain_e gain; + adi_adrv9001_RxInterfaceGainCtrlMode_e controlMode; + adi_adrv9001_RxInterfaceGain_e gain; + uint8_t rssiDuration; /* Duration of RSSI measurement (unit = 1ms/255 ) */ + uint8_t rssiMovingAverageDuration; /* Number of measurements in RSSI Moving-Average window */ + uint8_t reserved1; + uint8_t reserved2; + } adi_adrv9001_RxInterfaceGainCtrl_t; typedef enum adi_adrv9001_AdcTypeSwitchMode @@ -170,8 +175,31 @@ typedef struct adi_adrv9001_RxPortSwitchCfg uint64_t minFreqPortB_Hz; uint64_t maxFreqPortB_Hz; bool enable; + bool manualRxPortSwitch; } adi_adrv9001_RxPortSwitchCfg_t; - + +/** + * \brief Supported LOID intervals + */ +typedef enum adi_adrv9001_LoidInterval +{ + ADI_ADRV9001_LOIDINTERVAL_RFDCINTERVAL_DIV_2 = 0, /* 1/2 rfdc estimation interval */ + ADI_ADRV9001_LOIDINTERVAL_RFDCINTERVAL_DIV_4 = 1, /* 1/4 rfdc estimation interval */ + ADI_ADRV9001_LOIDINTERVAL_RFDCINTERVAL_DIV_8 = 2, /* 1/8 rfdc estimation interval */ + ADI_ADRV9001_LOIDINTERVAL_RFDCINTERVAL_DIV_16 = 3 /* 1/16 rfdc estimation interval */ +} adi_adrv9001_LoidInterval_e; + +/** + * \brief Structure which holds the LOID configuration parameters + */ +typedef struct adi_adrv9001_RxrfdcLoidCfg +{ + bool loidEnable; /* LOID enable flag for RX1 and RX2 */ + adi_adrv9001_LoidInterval_e loidInterval; /* Estimation interval */ + uint8_t loidThLow; /* Lower threshold for LO detection (in -dB) */ + uint8_t loidThHigh; /* Upper threshold for LO detection (in -dB) */ +} adi_adrv9001_RxrfdcLoidCfg_t ; + #ifdef __cplusplus } #endif diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi.h index cd16ace6b5123b..8805b3a00cba04 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi.h @@ -195,6 +195,32 @@ int32_t adi_adrv9001_spi_Cache_Write(adi_adrv9001_Device_t *adrv9001, const uint */ int32_t adi_adrv9001_spi_Cache_Read(adi_adrv9001_Device_t *adrv9001, const uint32_t rdCache[], uint8_t readData[], uint32_t count); +/** +* \brief Configure SPI Master +* +* \note Message type: \ref timing_mailbox "Mailbox command" +* +* \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure +* \param[in] spiMasterConfig The SPI Master configuration +* +* \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover +*/ +int32_t adi_adrv9001_spi_Master_Configure(adi_adrv9001_Device_t *adrv9001, + adi_adrv9001_spiMasterConfig_t *spiMasterConfig); + +/** +* \brief Inspect SPI Master +* +* \note Message type: \ref timing_mailbox "Mailbox command" +* +* \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure +* \param[out] spiMasterConfig The SPI Master configuration +* +* \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover +*/ +int32_t adi_adrv9001_spi_Master_Inspect(adi_adrv9001_Device_t *adrv9001, + adi_adrv9001_spiMasterConfig_t *spiMasterConfig); + #ifdef __cplusplus } #endif diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi_types.h index 76c9e13748bbd4..d284d0d9a7c758 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi_types.h @@ -23,6 +23,8 @@ #include "adi_adrv9001.h" #include "adi_common_hal.h" +#include "adi_adrv9001_gpio_types.h" + #ifdef __cplusplus extern "C" { #endif @@ -31,6 +33,7 @@ extern "C" { #define SPI_DATA_SIZE 8 #define SPI_MASK_SIZE 8 #define HW_RMW_DATA_BYTES 12 +#define SPI_MASTER_TOTAL_BYTES_MAX 30 /** * \brief Enum of possible HAL layer error codes. @@ -50,6 +53,47 @@ typedef enum adrv9001_Hal_Err ADRV9001HAL_BUFFER_OVERFLOW } adrv9001_Hal_Err_e; +typedef enum +{ + ADI_ADRV9001_SPI_MASTER_SLAVE_SINGLE = 0u, /* Single SPI slave device connected to ADRV9001 device */ + ADI_ADRV9001_SPI_MASTER_SLAVE_RESERVED = 1u /* More than one SPI slave device connected; Reserved for future */ +} adi_adrv9001_spiMasterSlaveDevices_e; + +typedef enum +{ + ADI_ADRV9001_SPI_MASTER_CS_SOURCE_GPIO_ANALOG = 0u, /* Select digital GPIO for SPI CS */ + ADI_ADRV9001_SPI_MASTER_CS_SOURCE_GPIO_DIGITAL = 1u /* Select analog GPIO for SPI CS */ +} adi_adrv9001_spiMasterSource_e; + +typedef enum +{ + ADI_ADRV9001_SPI_MASTER_TRIGGER_SOURCE_ARM = 0u, /* Reserved for future - Trigger SPI transaction directly from ARM */ + ADI_ADRV9001_SPI_MASTER_TRIGGER_SOURCE_MONITOR = 1u, /* Trigger SPI transaction from monitor logic */ + ADI_ADRV9001_SPI_MASTER_TRIGGER_SOURCE_REF_TIMER = 2u, /* Reserved for future - Trigger SPI transaction directly by reference timer */ + ADI_ADRV9001_SPI_MASTER_TRIGGER_SOURCE_GPIO = 3u /* Reserved for future - Trigger SPI transaction from GPIO */ +} adi_adrv9001_spiMasterTriggerSource_e; + +typedef enum +{ + ADI_ADRV9001_SPI_MASTER_CS_ASSERTION_PER_BYTE = 0u, /* CS is asserted per byte */ + ADI_ADRV9001_SPI_MASTER_CS_ASSERTION_CONTINUOUS = 1u /* CS is asserted for the entire transactionBytes duration */ +} adi_adrv9001_spiMasterAssertionMode_e; + +typedef struct +{ + uint8_t numBytes; /* Number of bytes to write. Valid range is 1 - 30 */ + uint8_t baudRateDiv; /* SPI baudRate = DEV_CLK_IN / baudRateDiv; Valid range is 0 - 31 */ + uint8_t transactionBytes; /* Number of bytes per CS assertion.Valid range is 1 - 30 */ + adi_adrv9001_spiMasterAssertionMode_e assertionMode; /* CS assert/deassert during frame duration */ + adi_adrv9001_spiMasterSlaveDevices_e spiSlaveDevicesConnected; /* Single or multiple(only in future) SPI slaves connected with ADRV9001 */ + adi_adrv9001_spiMasterSource_e csSource; /* GPIO type for all SPI pins: Analog or Digital */ + adi_adrv9001_GpioPin_e pin; /* CS pin - Other SPI signals have dedicated pins: Pin9 = SPI_CLK, + Pin10 = SPI_MISO, Pin11= SPI_MOSI*/ + adi_adrv9001_spiMasterTriggerSource_e triggerSource; /* SPI master transaction trigger source */ + uint32_t wakeupTimer_us; /* Monitor mode early wakeup timer for SPI master transaction. Only available + if triggerSource = ADI_ADRV9001_SPI_MASTER_TRIGGER_SOURCE_MONITOR */ + uint8_t spiData[SPI_MASTER_TOTAL_BYTES_MAX]; /* Bytes to be written in SPI slave device */ +} adi_adrv9001_spiMasterConfig_t; #ifdef __cplusplus } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx.h index 79263051ba2c43..d396e39de6a3fc 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx.h @@ -37,6 +37,7 @@ extern "C" { * \note Message type: \ref timing_direct "Direct register acccess" * * \pre Channel state any of STANDBY, CALIBRATED + * \pre Attenuation mode is not ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device data structure * \param[in] channel The Tx channel for which to configure the attenuation @@ -90,7 +91,6 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Set(adi_adrv9001_Device_t *adrv9001, /** * \brief Get the current attenuation control mode * - * \note Message type: \ref timing_direct "Direct register acccess" * \note If channel state is PRIMED, will always read back as ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device data structure @@ -110,6 +110,7 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Get(adi_adrv9001_Device_t *adrv9001, * channel state must be any of STANDBY, CALIBRATED, PRIMED. * \pre If attenuation mode is ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI: * channel state must be any of STANDBY, CALIBRATED, PRIMED, RF_ENABLED + * \pre Attenuation mode is not ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC * * \note Message type: \ref timing_direct "Direct register acccess" * \note The new attenuation only takes effect in the RF_ENABLED state - may read back incorrect value otherwise @@ -168,6 +169,7 @@ int32_t adi_adrv9001_Tx_Attenuation_Get(adi_adrv9001_Device_t *adrv9001, * degraded. Boost is disabled by default. * * \pre Channel state is STANDBY + * \pre Attenuation mode is not ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC * \note Enabling power boost after calibrations requires running calibrations again or performance will be degraded * * \note Message type: \ref timing_direct "Direct register acccess" @@ -404,6 +406,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *adrv9001, * \note Tx attenuation control via GPIO pins is possible only in RF_ENABLED state * * \pre Channel state must be CALIBRATED + * \pre Attenuation mode is not ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device data structure * \param[in] channel The Tx channel for which to configure the Tx attenuation diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx_types.h index cbe3b9bf83c9c6..c305774054f228 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx_types.h @@ -38,6 +38,7 @@ #define ADRV9001_TX_MAX_ATTENUATION_MDB 41950 #define ADRV9001_TX_ATTENUATION_RESOLUTION_MDB 50 + /** * \brief Enum to set the Tx Attenuation step size */ @@ -57,6 +58,8 @@ typedef enum adi_adrv9001_TxAttenuationControlMode ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_BYPASS = 0, /*!< Tx attenuation mode Bypass: zero total attenuation */ ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI = 1, /*!< Tx attenuation mode set by 10-bit attenuation index used to determine total attenuation */ ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_PIN = 3, /*!< Tx attenuation is control with GPIO Incr/Decr: total attenuation is altered incrementally using pin control */ + ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC = 4, /*!< Tx attenuation : Closed Loop Gain Control : + * If CLGC is enabled in OBJID_CFG_DPD_PRE_INIT_CAL, limited to TX_ATTENUATION_CONTROL_MODE_CLGC */ } adi_adrv9001_TxAttenuationControlMode_e; /** diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h index 80831a0ae0ae92..00069de3335c1b 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h @@ -206,8 +206,14 @@ typedef struct adi_adrv9001_Info uint32_t profileAddr; /*!< Address to load Profile */ uint32_t adcProfileAddr; /*!< Address to load ADC Profile */ uint32_t pfirProfileAddr; /*!< Address to load PFIR coefficients */ - uint32_t fhHopTable1Addr; /*!< Address to load hop table 1 in frequency hopping mode */ - uint32_t fhHopTable2Addr; /*!< Address to load hop table 2 in frequency hopping mode */ + uint32_t fhHopTableA1Addr; /*!< Address to load hop table A1 in frequency hopping mode */ + uint32_t fhHopTableB1Addr; /*!< Address to load hop table B1 in frequency hopping mode */ + uint32_t fhHopTableA2Addr; /*!< Address to load hop table A2 in frequency hopping mode */ + uint32_t fhHopTableB2Addr; /*!< Address to load hop table B2 in frequency hopping mode */ + uint32_t fhHopTableBufferA1Addr; /*!< Address to load hop table A1 Buffer in frequency hopping mode */ + uint32_t fhHopTableBufferB1Addr; /*!< Address to load hop table B1 Buffer in frequency hopping mode */ + uint32_t fhHopTableBufferA2Addr; /*!< Address to load hop table A2 Buffer in frequency hopping mode */ + uint32_t fhHopTableBufferB2Addr; /*!< Address to load hop table B2 Buffer in frequency hopping mode */ uint32_t txInputRate_kHz[ADI_ADRV9001_MAX_TXCHANNELS]; /*!< Tx Input sample rate from currently loaded profile */ uint32_t rxOutputRate_kHz[ADI_ADRV9001_MAX_RXCHANNELS]; /*!< Rx Output sample rate from currently loaded profile */ uint32_t rx1InterfaceSampleRate_kHz; /*!< Rx1 Interface sample rate from currently loaded profile */ @@ -220,6 +226,7 @@ typedef struct adi_adrv9001_Info uint32_t currentStreamImageSize; /*!< Image size of current stream */ uint8_t frequencyHoppingEnabled; /*!< Frequency hopping enabled flag from currently loaded profile */ adi_adrv9001_RxGainTableType_e gainTableType[ADI_ADRV9001_MAX_RX_ONLY]; /*!< type of gain table loaded during ADRV9001 initialization */ + uint8_t txAttenMode[ADI_ADRV9001_MAX_TXCHANNELS]; /* TX Attenuation Mode*/ } adi_adrv9001_Info_t; /** diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_user.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_user.h index e38b19e6558654..1ce2f8b9a919af 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_user.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_user.h @@ -26,7 +26,8 @@ #define ADI_ADRV9001_FRONT_END_GPIO_DOWNLOAD 0 /* Set this to '1' to download front end GPIO */ #define ADI_ADRV9001_SLEWRATE_CONFIG 1 /* Set this to '1' to enable slew rate configuration */ #define ADI_ADRV9001_SW_TEST 0 -#define ADI_ADRV9001_PROFILE_CHECKSUM_ENABLE 0 +#define ADI_ADRV9001_PROFILE_CHECKSUM_ENABLE 1 +#define ADI_ADRV9001_STREAM_CHECKSUM_ENABLE 0 #define ADRV9001_BITFIELD_LOG 0 #define ADRV9001_BITFIELD_HAL_LOG 0 diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h index db012b3eb9fc25..b00fd996a5dc58 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h @@ -19,7 +19,7 @@ extern "C" { #endif /* Auto-generated version number - DO NOT MANUALLY EDIT */ -#define ADI_ADRV9001_CURRENT_VERSION "48.26.4" +#define ADI_ADRV9001_CURRENT_VERSION "48.42.0" #ifdef __cplusplus } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adrv9001_Init_t_parser.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adrv9001_Init_t_parser.h index 107c17fa2af0e4..9e741c2525e78f 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adrv9001_Init_t_parser.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adrv9001_Init_t_parser.h @@ -1,6 +1,6 @@ /* Auto-generated file - DO NOT MANUALLY EDIT */ -/* Filename: C:\Jenkins\workspace\vice-driver_profile-types_master\include\adrv9001_Init_t_parser.h */ -/* Created on: 6/29/2021 4:03:53 PM */ +/* Filename: A:\profile-types\include\adrv9001_Init_t_parser.h */ +/* Created on: 10/29/2021 1:22:26 PM */ /** * Contains auto-generated C macros for loading fields from a JSON file @@ -132,6 +132,7 @@ ADI_PROCESS_INT (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv900 ADI_PROCESS_INT (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_DeviceSysConfig_tInstance.pllLockTime_us, "pllLockTime_us"); \ ADI_PROCESS_INT (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_DeviceSysConfig_tInstance.pllPhaseSyncWait_us, "pllPhaseSyncWait_us"); \ ADI_PROCESS_STRUCT_ADRV9001_PLLMODULUS_T (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_DeviceSysConfig_tInstance.pllModulus, "pllModulus"); \ +ADI_PROCESS_BOOL (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_DeviceSysConfig_tInstance.warmBootEnable, "warmBootEnable"); \ #define ADI_PROCESS_STRUCT_ADRV9001_DEVICESYSCONFIG_T(tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_DeviceSysConfig_tInstance, adrv9001_DeviceSysConfig_tName) \ ADI_PROCESS_STRUCT_X(ADRV9001_DEVICESYSCONFIG_T(tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_DeviceSysConfig_tInstance), tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_DeviceSysConfig_tName); @@ -558,7 +559,7 @@ ADI_PROCESS_INT (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv900 ADI_PROCESS_INT (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_RxProfile_tInstance.rxOutputRate_Hz, "rxOutputRate_Hz"); \ ADI_PROCESS_INT (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_RxProfile_tInstance.rxInterfaceSampleRate_Hz, "rxInterfaceSampleRate_Hz"); \ ADI_PROCESS_INT (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_RxProfile_tInstance.rxOffsetLo_kHz, "rxOffsetLo_kHz"); \ -ADI_PROCESS_INT (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_RxProfile_tInstance.rxSignalOnLo, "rxSignalOnLo"); \ +ADI_PROCESS_BOOL (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_RxProfile_tInstance.rxNcoEnable, "rxNcoEnable"); \ ADI_PROCESS_INT (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_RxProfile_tInstance.outputSignaling, "outputSignaling"); \ ADI_PROCESS_INT (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_RxProfile_tInstance.filterOrder, "filterOrder"); \ ADI_PROCESS_INT (tokenArray, tokenIndex, jsonBuffer, parsingBuffer, adrv9001_RxProfile_tInstance.filterOrderLp, "filterOrderLp"); \ diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c index 73917d49b0529c..ad60b17eb0e92f 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c @@ -26,6 +26,7 @@ #include "adi_adrv9001_radio.h" #include "adi_adrv9001_mcs.h" #include "adi_adrv9001_cals.h" +#include "adi_adrv9001_fh.h" #include "adrv9001_arm.h" #include "adrv9001_arm_macros.h" @@ -159,6 +160,10 @@ int32_t adi_adrv9001_arm_StartStatus_Check(adi_adrv9001_Device_t *device, uint32 { ADI_EXPECT(adi_adrv9001_arm_SystemError_Get, device, &objId, (uint8_t *)(&errorCode)); errorCode = ((uint16_t)objId << 8) | errorCode; + if (errorCode == 0) + { + errorCode = state.bootState; + } ADI_ERROR_REPORT(&device->common, ADI_ADRV9001_SRC_ARMFWSTATUS, errorCode, @@ -190,19 +195,6 @@ int32_t adi_adrv9001_arm_StartStatus_Check(adi_adrv9001_Device_t *device, uint32 ADI_ERROR_RETURN(device->common.error.newAction); } -/* FIXME: Disabled Checksum verification as FW code disabled checksum calculation. - It may have to enabled in future*/ -#if 0 - adi_adrv9001_ChecksumTable_t checksum = { { 0 } }; - uint8_t checksumValid = 0; - - if (armDebugLoaded == 0) - { - recoveryAction = adi_adrv9001_arm_ChecksumTable_Get(device, &checksum, &checksumValid); - ADI_ERROR_RETURN(device->common.error.newAction); - } -#endif - device->devStateInfo.devState = (adi_adrv9001_ApiStates_e)(device->devStateInfo.devState | ADI_ADRV9001_STATE_ARM_LOADED); ADI_API_RETURN(device); @@ -320,7 +312,7 @@ int32_t adi_adrv9001_arm_Image_Write(adi_adrv9001_Device_t *device, uint32_t byt (ADRV9001_ADDR_FH_HOP_TABLE_A_OFFSET < (byteOffset + byteCount + 4))) { i = ADRV9001_ADDR_FH_HOP_TABLE_A_OFFSET - byteOffset; - device->devStateInfo.fhHopTable1Addr = ((((uint32_t)binary[i + 3]) << 24) | + device->devStateInfo.fhHopTableA1Addr = ((((uint32_t)binary[i + 3]) << 24) | (((uint32_t)binary[i + 2]) << 16) | (((uint32_t)binary[i + 1]) << 8) | ((uint32_t)binary[i])); } @@ -328,7 +320,7 @@ int32_t adi_adrv9001_arm_Image_Write(adi_adrv9001_Device_t *device, uint32_t byt (ADRV9001_ADDR_FH_HOP_TABLE_B_OFFSET < (byteOffset + byteCount + 4))) { i = ADRV9001_ADDR_FH_HOP_TABLE_B_OFFSET - byteOffset; - device->devStateInfo.fhHopTable2Addr = ((((uint32_t)binary[i + 3]) << 24) | + device->devStateInfo.fhHopTableB1Addr = ((((uint32_t)binary[i + 3]) << 24) | (((uint32_t)binary[i + 2]) << 16) | (((uint32_t)binary[i + 1]) << 8) | ((uint32_t)binary[i])); } @@ -398,6 +390,22 @@ int32_t adi_adrv9001_arm_Memory_Read(adi_adrv9001_Device_t *device, ADI_API_RETURN(device); } +int32_t adi_adrv9001_arm_Memory_Read32(adi_adrv9001_Device_t *device, + uint32_t address, + uint32_t returnData[], + uint32_t byteCount, + uint8_t autoIncrement) +{ + //uint8_t data[] = { 0 }; + + ADI_PERFORM_VALIDATION(adi_adrv9001_arm_Memory_ReadWrite_Validate, device, address, (uint8_t *)returnData, byteCount, 0, autoIncrement); + + ADI_EXPECT(adrv9001_DmaMemRead, device, address, (uint8_t *)returnData, byteCount, autoIncrement); + + ADI_API_RETURN(device); +} + + int32_t adi_adrv9001_arm_Memory_Write(adi_adrv9001_Device_t *device, uint32_t address, const uint8_t data[], uint32_t byteCount, adi_adrv9001_ArmSingleSpiWriteMode_e spiWriteMode) { ADI_PERFORM_VALIDATION(adi_adrv9001_arm_Memory_ReadWrite_Validate, device, address, (uint8_t *)data, byteCount, spiWriteMode, false); @@ -407,6 +415,13 @@ int32_t adi_adrv9001_arm_Memory_Write(adi_adrv9001_Device_t *device, uint32_t ad ADI_API_RETURN(device); } +int32_t adi_adrv9001_arm_Memory_WriteFH(adi_adrv9001_Device_t *device,adi_adrv9001_FhHopSignal_e hopSignal, adi_adrv9001_FhHopTable_e tableId, uint32_t hopTableAddress, const uint8_t numHopTableEntries[], uint32_t numHopTableEntriesByteCount, uint32_t hopTableBufferAddress, const uint8_t hopTableBufferData[], uint32_t hopTableBufferDataByteCount) +{ + ADI_EXPECT(adrv9001_DmaMemWriteFH, device, hopSignal, tableId, hopTableAddress, numHopTableEntries, numHopTableEntriesByteCount, hopTableBufferAddress, hopTableBufferData, hopTableBufferDataByteCount); + + ADI_API_RETURN(device); +} + int32_t adi_adrv9001_arm_Config_Write(adi_adrv9001_Device_t *device, const uint8_t armData[], uint32_t armDataSize, const uint8_t mailboxCmd[], uint32_t mailboxCmdSize) { ADI_ENTRY_PTR_ARRAY_EXPECT(device, armData, armDataSize); @@ -857,7 +872,6 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad uint32_t waitInterval_us = ADI_ADRV9001_VERIFY_ARM_CHKSUM_INTERVAL_US; uint32_t numEventChecks = 1; uint32_t eventCheck = 0; - int j = 0; int i = 0; static const uint8_t CHECKSUM_BYTES = 0x4; @@ -865,6 +879,8 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad static const uint32_t MIN_TIMEOUT_US = 10000; /* Arm stream checksum order: main, rx1/2, tx1/2, orx12 */ +#if ADI_ADRV9001_STREAM_CHECKSUM_ENABLE > 0 + int j = 0; static const uint32_t streamChannel[] = { 0xFFFFFFFF, ADI_ADRV9001_RX1, @@ -877,22 +893,12 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad ADI_ADRV9001_ELB1 | ADI_ADRV9001_ELB2), }; - +#endif ADI_ENTRY_PTR_EXPECT(device, checksum); ADI_NULL_PTR_RETURN(&device->common, checksumValid); -#if ADI_ADRV9001_SW_TEST > 0 - if (device->devStateInfo.swTest == 1) - { - checksum->fwCheckSums.buildChecksum = 12345678; - checksum->fwCheckSums.runChecksum = 12345678; - *checksumValid = 1; - return (int32_t)recoveryAction; - } -#endif - if (timeout_us < MIN_TIMEOUT_US) { /* Set minimum timeout of 10 ms. Prevent divide by zero error */ @@ -904,13 +910,6 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad ADI_ERROR_RETURN(device->common.error.newAction); checkAddr = ((((uint32_t)checkData[3]) << 24) | (((uint32_t)checkData[2]) << 16) | (((uint32_t)checkData[1]) << 8) | ((uint32_t)checkData[0])); -#if ADI_ADRV9001_SW_TEST > 0 - if (device->devStateInfo.swTest >= 2) - { - checkAddr = ADRV9001_ADDR_ARM_CALC_CHKSUM_PTR; - } -#endif - waitInterval_us = (waitInterval_us > timeout_us) ? timeout_us : waitInterval_us; numEventChecks = (waitInterval_us == 0) ? 1 : (timeout_us / waitInterval_us); @@ -923,24 +922,10 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad buildTimeChecksum = ((((uint32_t)checkData[3]) << 24) | (((uint32_t)checkData[2]) << 16) | (((uint32_t)checkData[1]) << 8) | ((uint32_t)checkData[0])); calculatedChecksum = ((((uint32_t)checkData[7]) << 24) | (((uint32_t)checkData[6]) << 16) | (((uint32_t)checkData[5]) << 8) | ((uint32_t)checkData[4])); -#if ADI_ADRV9001_SW_TEST > 0 - if (device->devStateInfo.swTest == 3) - { - calculatedChecksum = 0; - buildTimeChecksum = calculatedChecksum; - } -#endif - if ((calculatedChecksum == 0) && (eventCheck < numEventChecks)) { /* wait */ halError = adi_common_hal_Wait_us(&device->common, timeout_us); -#if ADI_ADRV9001_SW_TEST > 0 - if (device->devStateInfo.swTest == 3) - { - halError = 1; - } -#endif ADI_ERROR_REPORT(&device->common, ADI_COMMON_ERRSRC_ADI_HAL, halError, @@ -955,19 +940,6 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad } } -#if ADI_ADRV9001_SW_TEST > 0 - if (device->devStateInfo.swTest >= 5) - { - calculatedChecksum = 12345678; - buildTimeChecksum = calculatedChecksum; - } - if (device->devStateInfo.swTest == 2) - { - calculatedChecksum = 0; - buildTimeChecksum = calculatedChecksum; - } -#endif - /* ARM completed calculating checksum */ if ((calculatedChecksum > 0) && (buildTimeChecksum > 0)) { @@ -975,14 +947,6 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad checksum->fwCheckSums.buildChecksum = buildTimeChecksum; checksum->fwCheckSums.runChecksum = calculatedChecksum; -#if ADI_ADRV9001_SW_TEST > 0 - if (device->devStateInfo.swTest == 5) - { - calculatedChecksum = 12345678; - buildTimeChecksum = calculatedChecksum + 1; - } -#endif - /* performing checksum check, skip if checksum was not calculated (ARM DEBUG_MODE)*/ if ((calculatedChecksum > 0) && (buildTimeChecksum != calculatedChecksum)) { @@ -995,6 +959,8 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad ADI_ERROR_RETURN(device->common.error.newAction); } +/* Disabled Stream checksum verification as Firmware does not calculate checksum for Streams */ +#if ADI_ADRV9001_STREAM_CHECKSUM_ENABLE > 0 for (j = 0; j < ADRV9001_MAX_NUM_STREAM; j++) { i = CHECKSUMENTRYSIZE * (j + 1); @@ -1003,13 +969,6 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad buildTimeChecksum = ((((uint32_t)checkData[i + 3]) << 24) | (((uint32_t)checkData[i + 2]) << 16) | (((uint32_t)checkData[i + 1]) << 8) | ((uint32_t)checkData[i + 0])); calculatedChecksum = ((((uint32_t)checkData[i + 7]) << 24) | (((uint32_t)checkData[i + 6]) << 16) | (((uint32_t)checkData[i + 5]) << 8) | ((uint32_t)checkData[i + 4])); -#if ADI_ADRV9001_SW_TEST > 0 - if (device->devStateInfo.swTest == 6) - { - calculatedChecksum = 12345678; - buildTimeChecksum = calculatedChecksum + 1; - } -#endif checksum->streamsCheckSum[j].buildChecksum = buildTimeChecksum; checksum->streamsCheckSum[j].runChecksum = calculatedChecksum; @@ -1030,21 +989,13 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad } } - - //i = offsetof(adi_adrv9001_checksumTable_t, deviceProfileCheckSum); +#endif i = CHECKSUMENTRYSIZE * (ADRV9001_MAX_NUM_STREAM + 1); /* Device profile checksum */ buildTimeChecksum = ((((uint32_t)checkData[i + 3]) << 24) | (((uint32_t)checkData[i + 2]) << 16) | (((uint32_t)checkData[i + 1]) << 8) | ((uint32_t)checkData[i + 0])); calculatedChecksum = ((((uint32_t)checkData[i + 7]) << 24) | (((uint32_t)checkData[i + 6]) << 16) | (((uint32_t)checkData[i + 5]) << 8) | ((uint32_t)checkData[i + 4])); -#if ADI_ADRV9001_SW_TEST > 0 - if (device->devStateInfo.swTest == 7) - { - calculatedChecksum = 12345678; - buildTimeChecksum = calculatedChecksum + 1; - } -#endif checksum->deviceProfileCheckSum.buildChecksum = buildTimeChecksum; checksum->deviceProfileCheckSum.runChecksum = calculatedChecksum; @@ -1053,7 +1004,7 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad if (buildTimeChecksum != calculatedChecksum) { ADI_ERROR_REPORT(&device->common, - ADI_COMMON_ERRSRC_ARMCMD, + ADI_ADRV9001_SRC_ARMCMD, ADI_COMMON_ERR_API_FAIL, ADI_ADRV9001_ACT_ERR_RESET_ARM, calculatedChecksum, @@ -1064,30 +1015,23 @@ int32_t adi_adrv9001_arm_ChecksumTable_Get(adi_adrv9001_Device_t *device, adi_ad i = CHECKSUMENTRYSIZE * (ADRV9001_MAX_NUM_STREAM + 2); - /* ADC profile checksum */ + /* PFIR profile checksum */ buildTimeChecksum = ((((uint32_t)checkData[i + 3]) << 24) | (((uint32_t)checkData[i + 2]) << 16) | (((uint32_t)checkData[i + 1]) << 8) | ((uint32_t)checkData[i + 0])); calculatedChecksum = ((((uint32_t)checkData[i + 7]) << 24) | (((uint32_t)checkData[i + 6]) << 16) | (((uint32_t)checkData[i + 5]) << 8) | ((uint32_t)checkData[i + 4])); -#if ADI_ADRV9001_SW_TEST > 0 - if (device->devStateInfo.swTest == 8) - { - calculatedChecksum = 12345678; - buildTimeChecksum = calculatedChecksum + 1; - } -#endif - checksum->adcProfilefwCheckSum.buildChecksum = buildTimeChecksum; - checksum->adcProfilefwCheckSum.runChecksum = calculatedChecksum; + checksum->pfirProfileCheckSum.buildChecksum = buildTimeChecksum; + checksum->pfirProfileCheckSum.runChecksum = calculatedChecksum; #if ADI_ADRV9001_PROFILE_CHECKSUM_ENABLE > 0 /* performing checksum check */ if (buildTimeChecksum != calculatedChecksum) { ADI_ERROR_REPORT(&device->common, - ADI_COMMON_ERRSRC_ARMCMD, + ADI_ADRV9001_SRC_ARMCMD, ADI_COMMON_ERR_API_FAIL, ADI_ADRV9001_ACT_ERR_RESET_ARM, calculatedChecksum, - "Adc Profile checksum is invalid"); + "PFIR Profile checksum is invalid"); ADI_ERROR_RETURN(device->common.error.newAction); } #endif diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c index ec9bd951a8485f..e92b41cbe5dc32 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c @@ -10,13 +10,14 @@ #include "adi_adrv9001_dpd.h" #include "adi_adrv9001_arm.h" #include "adi_adrv9001_radio.h" +#include "adi_adrv9001_tx.h" #include "adi_adrv9001_arm.h" #include "adrv9001_arm_macros.h" #include "adrv9001_nvs_regmap_tx.h" #include "object_ids.h" -#define MAX_PRELUTSCALE 0b1111 +#define MAX_PRELUTSCALE 15 static __maybe_unused int32_t __maybe_unused adi_adrv9001_dpd_Initial_Configure_Validate(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, @@ -48,6 +49,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_dpd_Initial_Configure_ ADI_ERROR_RETURN(adrv9001->common.error.newAction); } ADI_RANGE_CHECK(adrv9001, dpdConfig->preLutScale, 0, MAX_PRELUTSCALE); + ADI_RANGE_CHECK(adrv9001, dpdConfig->clgcEnable, 0, 1); /* Validate state is STANDBY */ ADI_EXPECT(adi_adrv9001_Radio_State_Get, adrv9001, &state); @@ -70,9 +72,10 @@ int32_t adi_adrv9001_dpd_Initial_Configure(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_DpdInitCfg_t *dpdConfig) { - uint8_t armData[26] = { 0 }; + uint8_t armData[27] = { 0 }; uint8_t extData[5] = { 0 }; uint32_t offset = 0; + adi_adrv9001_DpdCfg_t dpdClgcRead = { 0 }; ADI_PERFORM_VALIDATION(adi_adrv9001_dpd_Initial_Configure_Validate, adrv9001, channel, dpdConfig); @@ -87,12 +90,19 @@ int32_t adi_adrv9001_dpd_Initial_Configure(adi_adrv9001_Device_t *adrv9001, adrv9001_LoadFourBytes(&offset, armData, dpdConfig->modelOrdersForEachTap[2]); adrv9001_LoadFourBytes(&offset, armData, dpdConfig->modelOrdersForEachTap[3]); armData[offset++] = dpdConfig->preLutScale; + armData[offset++] = dpdConfig->clgcEnable; extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_TX, channel); extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_CFG_DPD_PRE_INIT_CAL; - ADI_EXPECT(adi_adrv9001_arm_Config_Write, adrv9001, armData, sizeof(armData), extData, sizeof(extData)) + ADI_EXPECT(adi_adrv9001_arm_Config_Write, adrv9001, armData, sizeof(armData), extData, sizeof(extData)) + + ADI_EXPECT(adi_adrv9001_dpd_Inspect, adrv9001, channel, &dpdClgcRead) + if (dpdConfig->clgcEnable != 0 && dpdClgcRead.clgcLoopOpen == 0) + { + ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Set, adrv9001, channel, ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) + } ADI_API_RETURN(adrv9001); } @@ -111,7 +121,7 @@ int32_t adi_adrv9001_dpd_Initial_Inspect(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_DpdInitCfg_t *dpdConfig) { - uint8_t armReadBack[22] = { 0 }; + uint8_t armReadBack[23] = { 0 }; uint8_t channelMask = 0; uint32_t offset = 0; @@ -130,6 +140,7 @@ int32_t adi_adrv9001_dpd_Initial_Inspect(adi_adrv9001_Device_t *adrv9001, adrv9001_ParseFourBytes(&offset, armReadBack, &dpdConfig->modelOrdersForEachTap[2]); adrv9001_ParseFourBytes(&offset, armReadBack, &dpdConfig->modelOrdersForEachTap[3]); dpdConfig->preLutScale = armReadBack[offset++]; + dpdConfig->clgcEnable = armReadBack[offset++]; ADI_API_RETURN(adrv9001); } @@ -141,9 +152,6 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_dpd_Configure_Validate static const uint32_t DPD_MAX_SAMPLES = 4096; static const uint32_t MAX_RX_TX_NORMALIZATION_THRESHOLD_U2D30 = 1 << 30; // 1.0 in U2.30 static const uint32_t MAX_TIME_FILTER_COEFFICIENT = 0x7FFFFFFF; // 0.999... in U1.31 - adi_adrv9001_RadioState_t state = { 0 }; - uint8_t port_index = 0; - uint8_t chan_index = 0; ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); @@ -154,20 +162,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_dpd_Configure_Validate ADI_RANGE_CHECK(adrv9001, dpdConfig->countsLessThanPowerThreshold, 0, 4096); ADI_RANGE_CHECK(adrv9001, dpdConfig->countsGreaterThanPeakThreshold, 0, 4096); ADI_RANGE_CHECK(adrv9001, dpdConfig->timeFilterCoefficient, 0, MAX_TIME_FILTER_COEFFICIENT); - - /* Validate state is CALIBRATED */ - ADI_EXPECT(adi_adrv9001_Radio_State_Get, adrv9001, &state); - adi_common_port_to_index(ADI_TX, &port_index); - adi_common_channel_to_index(channel, &chan_index); - if (ADI_ADRV9001_CHANNEL_CALIBRATED != state.channelStates[port_index][chan_index]) - { - ADI_ERROR_REPORT(&adrv9001->common, - ADI_COMMON_ERRSRC_API, - ADI_COMMON_ERR_INV_PARAM, - ADI_COMMON_ACT_ERR_CHECK_PARAM, - channel, - "Invalid channel state. Channel must be in CALIBRATED state"); - } + ADI_RANGE_CHECK(adrv9001, dpdConfig->clgcLoopOpen, 0, 1); ADI_API_RETURN(adrv9001); } @@ -176,11 +171,13 @@ int32_t adi_adrv9001_dpd_Configure(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_DpdCfg_t *dpdConfig) { - uint8_t armData[44] = { 0 }; + uint8_t armData[64] = { 0 }; uint8_t extData[5] = { 0 }; uint32_t offset = 0; + adi_adrv9001_DpdInitCfg_t dpdClgcRead = { 0 }; + ADI_PERFORM_VALIDATION(adi_adrv9001_dpd_Configure_Validate, adrv9001, channel, dpdConfig); adrv9001_LoadFourBytes(&offset, armData, sizeof(armData) - sizeof(uint32_t)); @@ -201,12 +198,24 @@ int32_t adi_adrv9001_dpd_Configure(adi_adrv9001_Device_t *adrv9001, offset++; /* 1 byte padding for word alignment */ offset += 4; /* Leave space for 'dpdSampleRate_Hz', which is a read-only parameter */ adrv9001_LoadFourBytes(&offset, armData, dpdConfig->timeFilterCoefficient); + /* CLGC */ + armData[offset++] = dpdConfig->clgcLoopOpen; + offset += 3; /* struct padding */ + adrv9001_LoadFourBytes(&offset, armData, dpdConfig->clgcGainTarget_HundredthdB); + adrv9001_LoadFourBytes(&offset, armData, dpdConfig->clgcFilterAlpha); + offset += 8; /* space for clgcLastGain_HundredthdB & clgcFilteredGain_HundredthdB , which are read-only */ extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_TX, channel); extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_TC_TX_DPD; ADI_EXPECT(adi_adrv9001_arm_Config_Write, adrv9001, armData, sizeof(armData), extData, sizeof(extData)) + + ADI_EXPECT(adi_adrv9001_dpd_Initial_Inspect, adrv9001, channel, &dpdClgcRead) + if (dpdClgcRead.clgcEnable != 0 && dpdConfig->clgcLoopOpen == 0) + { + ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Set, adrv9001, channel, ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) + } ADI_API_RETURN(adrv9001); } @@ -225,7 +234,7 @@ int32_t adi_adrv9001_dpd_Inspect(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_DpdCfg_t *dpdConfig) { - uint8_t armReadBack[40] = { 0 }; + uint8_t armReadBack[60] = { 0 }; uint8_t channelMask = 0; uint32_t offset = 0; @@ -252,6 +261,13 @@ int32_t adi_adrv9001_dpd_Inspect(adi_adrv9001_Device_t *adrv9001, offset++; adrv9001_ParseFourBytes(&offset, armReadBack, &dpdConfig->dpdSamplingRate_Hz); adrv9001_ParseFourBytes(&offset, armReadBack, &dpdConfig->timeFilterCoefficient); + /* CLGC */ + dpdConfig->clgcLoopOpen = (bool)armReadBack[offset++]; + offset += 3; /* struct padding */ + adrv9001_ParseFourBytes(&offset, armReadBack, (uint32_t*)&dpdConfig->clgcGainTarget_HundredthdB); + adrv9001_ParseFourBytes(&offset, armReadBack, &dpdConfig->clgcFilterAlpha); + adrv9001_ParseFourBytes(&offset, armReadBack, (uint32_t*)&dpdConfig->clgcLastGain_HundredthdB); + adrv9001_ParseFourBytes(&offset, armReadBack, (uint32_t*)&dpdConfig->clgcFilteredGain_HundredthdB); ADI_API_RETURN(adrv9001); } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c index e03e74b8141c94..2ed96d33f8b80e 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c @@ -27,6 +27,7 @@ #include "adi_adrv9001_spi.h" #include "adrv9001_init.h" #include "adrv9001_reg_addr_macros.h" +#include "adrv9001_fh_types.h" #include "object_ids.h" #ifdef __KERNEL__ @@ -34,8 +35,8 @@ #endif #define FREQ_HOPPING_SIZE_FIELD_NUM_BYTES 4u -#define FREQ_HOPPING_RX_GAIN_TABLE_NUM_BYTES 9u // 8 1 byte entries + 1 byte to indicate number of valid entries -#define FREQ_HOPPING_TX_ATTEN_TABLE_NUM_BYTES 17u // 8 2 byte entries + 1 byte to indicate number of valid entries +#define FREQ_HOPPING_RX_GAIN_TABLE_NUM_BYTES 17u // 16 1 byte entries + 1 byte to indicate number of valid entries +#define FREQ_HOPPING_TX_ATTEN_TABLE_NUM_BYTES 35u // 16 2 byte entries + 1 byte to indicate number of valid entries #define FREQ_HOPPING_CONFIGURATION_NUM_BYTES 40u #define FREQ_HOPPING_CONFIGURATION_TOTAL_NUM_BYTES (FREQ_HOPPING_SIZE_FIELD_NUM_BYTES +\ FREQ_HOPPING_RX_GAIN_TABLE_NUM_BYTES +\ @@ -56,7 +57,7 @@ if (device->devStateInfo.frequencyHoppingEnabled == 0) \ ADI_API_RETURN(device); \ } -/* TODO JP: Determine if we need to validate the whole table. +/* TODO JP: Determine if we need to validate the whole table. It's difficult to validate the hop table due to the following: 1) At the time of receiving the HOP table, we don't know the channel sequence. So a tx or rx gain index might be valid, or it might be a 'don't care' value, programmed by the user. We could potentially enforce the @@ -64,7 +65,7 @@ if (device->devStateInfo.frequencyHoppingEnabled == 0) \ 2) There doesn't seem a nice way to validate the rx gain in API, since there is no state of the FH operating gain range. The best we could do would be to ensure its within the absolute min/max. However, this could be effected by point 1. - 3) Validating the whole table before its written to ARM might be valuable, however, it might + 3) Validating the whole table before its written to ARM might be valuable, however, it might also waste time. Especially considering we can't validate every field in the table. It might be better for ARM to validate it once received, or on the fly. */ @@ -74,26 +75,9 @@ static __maybe_unused int32_t adi_adrv9001_fh_FrameInfo_Validate(adi_adrv9001_De /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); - ADI_RANGE_CHECK_X(adrv9001, hopFrame->hopFrequencyHz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, hopFrame->hopFrequencyHz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); - -#if 0 - ADI_RANGE_CHECK(adrv9001, hopFrame->txAttenuation_mdB, 0, NORMAL_MAX_ATTENUATION_MDB); - - if (hopFrame->txAttenuation_mdB % NORMAL_ATTENUATION_RESOLUTION_MDB != 0) - { - ADI_ERROR_REPORT(&adrv9001->common, - ADI_COMMON_ERRSRC_API, - ADI_COMMON_ERR_API_FAIL, - ADI_COMMON_ACT_ERR_CHECK_PARAM, - hopFrame->txAttenuation_mdB, - "Invalid attenuation_mdB value. The resolution is only 0.05dB"); - } - - ADI_RANGE_CHECK(adrv9001, hopFrame->rxGainIndex, MIN_RX_GAIN_INDEX, MAX_RX_GAIN_INDEX) -#endif - /* TODO JP: Validate Offset frequency. Not sure about ranges */ ADI_API_RETURN(adrv9001); } @@ -111,17 +95,23 @@ static uint32_t adi_adrv9001_fh_GetHopTableBufferAddress(adi_adrv9001_Device_t * adrv9001_ParseFourBytes(&offset, hopTableBufferAddressBlock, &hopTableBufferAddress); return hopTableBufferAddress; -} +} static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) -{ +{ uint32_t i; + uint32_t j; uint8_t numHopSignals; uint8_t initializedChannelMask; uint8_t maxPossibleGainEntries; + uint8_t channel1Mask = (ADI_ADRV9001_RX1 | ADI_ADRV9001_TX1); uint8_t channel2Mask = (ADI_ADRV9001_RX2 | ADI_ADRV9001_TX2); uint8_t rxChannelMask = (ADI_ADRV9001_RX1 | ADI_ADRV9001_RX2); + static const uint32_t CHANNELS[][2] = { + { ADI_ADRV9001_RX1, ADI_ADRV9001_RX2 }, + { ADI_ADRV9001_TX1, ADI_ADRV9001_TX2 } + }; /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); /* Check for NULL pointer */ @@ -149,7 +139,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } /* Can be unassigned but throw an error if it's set to analog*/ ADI_RANGE_CHECK(adrv9001, fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[0].pin, ADI_ADRV9001_GPIO_UNASSIGNED, ADI_ADRV9001_GPIO_DIGITAL_15); - if ((fhConfig->hopTableSelectConfig.hopTableSelectMode == ADI_ADRV9001_FHHOPTABLESELECTMODE_INDEPENDENT) + if ((fhConfig->hopTableSelectConfig.hopTableSelectMode == ADI_ADRV9001_FHHOPTABLESELECTMODE_INDEPENDENT) && (fhConfig->mode == ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP)) { /* Can be unassigned but throw an error if it's set to analog*/ @@ -194,18 +184,18 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De "Value must be non-zero in Tx only operation"); ADI_API_RETURN(adrv9001); } - + /* Check mode*/ ADI_RANGE_CHECK(adrv9001, fhConfig->mode, ADI_ADRV9001_FHMODE_LO_MUX_PREPROCESS, ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP); /* Check tableIndexCtrl_e */ ADI_RANGE_CHECK(adrv9001, fhConfig->tableIndexCtrl, ADI_ADRV9001_TABLEINDEXCTRL_AUTO_LOOP, ADI_ADRV9001_TABLEINDEXCTRL_GPIO); /* Check operating frequency range */ - ADI_RANGE_CHECK_X(adrv9001, fhConfig->minOperatingFrequency_Hz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, fhConfig->minOperatingFrequency_Hz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); - ADI_RANGE_CHECK_X(adrv9001, fhConfig->maxOperatingFrequency_Hz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, fhConfig->maxOperatingFrequency_Hz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); if (fhConfig->minOperatingFrequency_Hz >= fhConfig->maxOperatingFrequency_Hz) @@ -219,12 +209,12 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De ADI_API_RETURN(adrv9001); } /* Check RX gain ranges */ - ADI_RANGE_CHECK(adrv9001, fhConfig->minRxGainIndex, - ADI_ADRV9001_RX_GAIN_INDEX_MIN, + ADI_RANGE_CHECK(adrv9001, fhConfig->minRxGainIndex, + ADI_ADRV9001_RX_GAIN_INDEX_MIN, fhConfig->maxRxGainIndex); /* Max index can be equal to min and no greater than rx1MaxGainIndex */ - ADI_RANGE_CHECK(adrv9001, fhConfig->maxRxGainIndex, - fhConfig->minRxGainIndex, + ADI_RANGE_CHECK(adrv9001, fhConfig->maxRxGainIndex, + fhConfig->minRxGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); /* TODO JP: Investigate requirements for TX attenuation in diversity mode. Will min/max be the same, or will we need a seperate field? @@ -253,7 +243,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } /* Check frequency select pins */ - if (ADI_ADRV9001_TABLEINDEXCTRL_GPIO == fhConfig->tableIndexCtrl) + if (ADI_ADRV9001_TABLEINDEXCTRL_GPIO == fhConfig->tableIndexCtrl) { ADI_RANGE_CHECK(adrv9001, fhConfig->numTableIndexPins, 1u, ADI_ADRV9001_FH_MAX_NUM_FREQ_SELECT_PINS); for (i = 0; i < fhConfig->numTableIndexPins; i++) @@ -262,28 +252,41 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } } /* Configure gain select pins */ - if (true == fhConfig->gainSetupByPin) + if (true == fhConfig->gainSetupByPin) { - ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig.numGainCtrlPins, 1u, ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_PINS); - for (i = 0; i < fhConfig->gainSetupByPinConfig.numGainCtrlPins; i++) - { - ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig.gainSelectGpioConfig[i].pin, ADI_ADRV9001_GPIO_DIGITAL_00, ADI_ADRV9001_GPIO_DIGITAL_15); - } - maxPossibleGainEntries = (1u << fhConfig->gainSetupByPinConfig.numGainCtrlPins); - - /* Validate Rx gain table is within range specified by fhConfig */ - ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig.numRxGainTableEntries, 1u, maxPossibleGainEntries); - for (i = 0; i < fhConfig->gainSetupByPinConfig.numRxGainTableEntries; i++) - { - ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig.rxGainTable[i], fhConfig->minRxGainIndex, fhConfig->maxRxGainIndex); - } - - /* Validate Tx atten table is within range specified by fhConfig */ - ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig.numTxAttenTableEntries, 1u, maxPossibleGainEntries); - for (i = 0; i < fhConfig->gainSetupByPinConfig.numTxAttenTableEntries; i++) - { - ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig.txAttenTable[i], fhConfig->minTxAtten_mdB, fhConfig->maxTxAtten_mdB); - } + for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) + { + if ((initializedChannelMask & (j == 0? channel1Mask:channel2Mask)) != 0x00u) + { + + ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].numGainCtrlPins, 1u, ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_PINS); + for (i = 0; i < fhConfig->gainSetupByPinConfig[j].numGainCtrlPins; i++) + { + ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].gainSelectGpioConfig[i].pin, ADI_ADRV9001_GPIO_DIGITAL_00, ADI_ADRV9001_GPIO_DIGITAL_15); + } + maxPossibleGainEntries = (1u << fhConfig->gainSetupByPinConfig[j].numGainCtrlPins); + } + + + if (ADRV9001_BF_EQUAL(adrv9001->devStateInfo.initializedChannels, CHANNELS[ADI_RX][j])) + { + /* Validate Rx gain table is within range specified by fhConfig */ + ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].numRxGainTableEntries, 1u, maxPossibleGainEntries); + for (i = 0; i < fhConfig->gainSetupByPinConfig[j].numRxGainTableEntries; i++) + { + ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].rxGainTable[i], fhConfig->minRxGainIndex, fhConfig->maxRxGainIndex); + } + } + if (ADRV9001_BF_EQUAL(adrv9001->devStateInfo.initializedChannels, CHANNELS[ADI_TX][j])) + { + /* Validate Tx atten table is within range specified by fhConfig */ + ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].numTxAttenTableEntries, 1u, maxPossibleGainEntries); + for (i = 0; i < fhConfig->gainSetupByPinConfig[j].numTxAttenTableEntries; i++) + { + ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].txAttenTable[i], fhConfig->minTxAtten_mdB, fhConfig->maxTxAtten_mdB); + } + } + } } ADI_API_RETURN(adrv9001); @@ -291,7 +294,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De static __maybe_unused int32_t adi_adrv9001_fh_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) -{ +{ /* Check for NULL pointer */ ADI_NULL_PTR_RETURN(&adrv9001->common, fhConfig); ADI_API_RETURN(adrv9001); @@ -300,16 +303,36 @@ static __maybe_unused int32_t adi_adrv9001_fh_Inspect_Validate(adi_adrv9001_Devi static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhMode_e mode, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t tableSize) { uint32_t frequencyIndex = 0; - uint32_t tempAddress = (tableId == ADI_ADRV9001_FHHOPTABLE_A) ? adrv9001->devStateInfo.fhHopTable1Addr : - adrv9001->devStateInfo.fhHopTable2Addr; + uint32_t tempAddress = 0; + if (tableId == ADI_ADRV9001_FHHOPTABLE_A) + { + if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) + { + tempAddress = adrv9001->devStateInfo.fhHopTableA1Addr; + } + else + { + tempAddress = adrv9001->devStateInfo.fhHopTableA2Addr; + } + } + else + { + if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) + { + tempAddress = adrv9001->devStateInfo.fhHopTableB1Addr; + } + else + { + tempAddress = adrv9001->devStateInfo.fhHopTableB2Addr; + } + } uint8_t maxNumHopFrequencies = (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) ? ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE : - (ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE) / 2; - tempAddress += (hopSignal * (FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET)); + (ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE) / 2; /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); /* Check for NULL pointer */ @@ -329,7 +352,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate ADI_API_RETURN(adrv9001); } - if ((hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_2) + if ((hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_2) && (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP)) { ADI_ERROR_REPORT(&adrv9001->common, @@ -341,7 +364,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate ADI_API_RETURN(adrv9001); } - + /* Check fhHopTable->numHopFrames are valid */ ADI_RANGE_CHECK(adrv9001, tableSize, 1u, maxNumHopFrequencies); @@ -351,7 +374,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate } ADI_API_RETURN(adrv9001); -} +} static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal, @@ -359,9 +382,29 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Inspect_Validate(adi_adrv adi_adrv9001_FhHopFrame_t hopTable[], uint32_t tableSize) { - uint32_t tempAddress = (tableId == ADI_ADRV9001_FHHOPTABLE_A) ? adrv9001->devStateInfo.fhHopTable1Addr : - adrv9001->devStateInfo.fhHopTable2Addr; - tempAddress += (hopSignal * (FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET)); + uint32_t tempAddress = 0; + if (tableId == ADI_ADRV9001_FHHOPTABLE_A) + { + if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) + { + tempAddress = adrv9001->devStateInfo.fhHopTableA1Addr; + } + else + { + tempAddress = adrv9001->devStateInfo.fhHopTableA2Addr; + } + } + else + { + if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) + { + tempAddress = adrv9001->devStateInfo.fhHopTableB1Addr; + } + else + { + tempAddress = adrv9001->devStateInfo.fhHopTableB2Addr; + } + } /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); /* Check for NULL pointer */ @@ -383,7 +426,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Inspect_Validate(adi_adrv } ADI_API_RETURN(adrv9001); -} +} int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) @@ -396,6 +439,7 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, uint32_t offset = 0; uint32_t tempOffset = 0; uint32_t i = 0; + uint32_t j = 0; adi_adrv9001_GpioSignal_e frequencySelectPinSignal = 0; adi_adrv9001_GpioSignal_e gainSelectPinSignal = 0; adi_adrv9001_MailboxChannel_e rxHopSignalPortMask[2] = { ADI_ADRV9001_RX1, ADI_ADRV9001_RX2 }; @@ -428,7 +472,7 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, armData[offset++] = fhConfig->tableIndexCtrl; armData[offset++] = fhConfig->gainSetupByPin; armData[offset++] = fhConfig->hopTableSelectConfig.hopTableSelectMode; - + armData[offset++] = hop1SignalsPortMask; armData[offset++] = hop2SignalsPortMask; @@ -447,21 +491,32 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, armData[offset++] = fhConfig->rxZeroIfEnable; offset += 2u; /* padding */ /* If in gain select by pin mode, load Rx gain and Tx attenuation tables */ - if (fhConfig->gainSetupByPin == true) + if (fhConfig->gainSetupByPin == true) { /* Load Rx gain and Tx atten table */ - armData[offset++] = fhConfig->gainSetupByPinConfig.numRxGainTableEntries; - armData[offset++] = fhConfig->gainSetupByPinConfig.numTxAttenTableEntries; - /* Create a second offset variable to point to the Tx atten table location. + armData[offset++] = fhConfig->gainSetupByPinConfig[0].numRxGainTableEntries; + armData[offset++] = fhConfig->gainSetupByPinConfig[1].numRxGainTableEntries; + armData[offset++] = fhConfig->gainSetupByPinConfig[0].numTxAttenTableEntries; + armData[offset++] = fhConfig->gainSetupByPinConfig[1].numTxAttenTableEntries; + /* Create a second offset variable to point to the Tx atten table location. Rx gain index is 1 byte, so second offset is offset + (ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES * 1) */ - tempOffset = offset + ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; + tempOffset = offset + 2 * ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; /* Rx and Tx tables */ - for (i = 0; i < ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; i++) - { - armData[offset++] = fhConfig->gainSetupByPinConfig.rxGainTable[i]; - adrv9001_LoadTwoBytes(&tempOffset, armData, fhConfig->gainSetupByPinConfig.txAttenTable[i]); - } + for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) + { + for (i = 0; i < ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; i++) + { + armData[offset++] = fhConfig->gainSetupByPinConfig[j].rxGainTable[i]; + } + } + for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) + { + for (i = 0; i < ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; i++) + { + adrv9001_LoadTwoBytes(&tempOffset, armData, fhConfig->gainSetupByPinConfig[j].txAttenTable[i]); + } + } } /* Write to set buffer */ ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_SET, armData, sizeof(armData), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); @@ -518,15 +573,24 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, } } /* Configure gain index pins if selected */ - if (fhConfig->gainSetupByPin == true) + if (fhConfig->gainSetupByPin == true) { /* Configure ADRV9001 GPIOs */ - gainSelectPinSignal = ADI_ADRV9001_GPIO_SIGNAL_FH_GAIN_SEL_0; - for (i = 0; i < fhConfig->gainSetupByPinConfig.numGainCtrlPins; i++) - { - ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, (gainSelectPinSignal + i), &(fhConfig->gainSetupByPinConfig.gainSelectGpioConfig[i])); - } + for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) + { + gainSelectPinSignal = j == 0? ADI_ADRV9001_GPIO_SIGNAL_FH_CH1_GAIN_ATTEN_SEL_0 : ADI_ADRV9001_GPIO_SIGNAL_FH_CH2_GAIN_ATTEN_SEL_0; + for (i = 0; i < fhConfig->gainSetupByPinConfig[j].numGainCtrlPins; i++) + { + ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, (gainSelectPinSignal + i), &(fhConfig->gainSetupByPinConfig[j].gainSelectGpioConfig[i])); + } + } } + adrv9001->devStateInfo.fhHopTableA2Addr = adrv9001->devStateInfo.fhHopTableA1Addr + FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET; + adrv9001->devStateInfo.fhHopTableB2Addr = adrv9001->devStateInfo.fhHopTableB1Addr + FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET; + adrv9001->devStateInfo.fhHopTableBufferA1Addr = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, adrv9001->devStateInfo.fhHopTableA1Addr); + adrv9001->devStateInfo.fhHopTableBufferB1Addr = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, adrv9001->devStateInfo.fhHopTableB1Addr); + adrv9001->devStateInfo.fhHopTableBufferA2Addr = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, adrv9001->devStateInfo.fhHopTableA2Addr); + adrv9001->devStateInfo.fhHopTableBufferB2Addr = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, adrv9001->devStateInfo.fhHopTableB2Addr); ADI_API_RETURN(adrv9001); } @@ -540,6 +604,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a uint32_t offset = 0; uint32_t tempOffset = 0; uint32_t i; + uint32_t j; adi_adrv9001_GpioSignal_e frequencySelectPinSignal = 0; adi_adrv9001_GpioSignal_e gainSelectPinSignal = 0; @@ -567,7 +632,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a fhConfig->tableIndexCtrl = armData[offset++]; fhConfig->gainSetupByPin = armData[offset++]; fhConfig->hopTableSelectConfig.hopTableSelectMode = armData[offset++]; - + hop1SignalsPortMask = armData[offset++]; offset++; fhConfig->rxPortHopSignals[0] = ((hop1SignalsPortMask & 0x1) == 1) ? ADI_ADRV9001_FH_HOP_SIGNAL_1 : ADI_ADRV9001_FH_HOP_SIGNAL_2; @@ -589,39 +654,59 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a /* Get gain setup by pin information */ if (fhConfig->gainSetupByPin) { - fhConfig->gainSetupByPinConfig.numRxGainTableEntries = armData[offset++]; - fhConfig->gainSetupByPinConfig.numTxAttenTableEntries = armData[offset++]; - tempOffset = offset + ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; - /* Rx and Tx tables */ - for (i = 0; i < ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; i++) + for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) { - fhConfig->gainSetupByPinConfig.rxGainTable[i] = armData[offset++]; - adrv9001_ParseTwoBytes(&tempOffset, armData, &fhConfig->gainSetupByPinConfig.txAttenTable[i]); + fhConfig->gainSetupByPinConfig[j].numRxGainTableEntries = armData[offset++]; } - /* Configure ADRV9001 GPIOs */ - gainSelectPinSignal = ADI_ADRV9001_GPIO_SIGNAL_FH_GAIN_SEL_0; - fhConfig->gainSetupByPinConfig.numGainCtrlPins = ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_PINS; - for (i = 0; i < ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_PINS; i++) + for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) { - ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, (gainSelectPinSignal + i), &(fhConfig->gainSetupByPinConfig.gainSelectGpioConfig[i])); - if (fhConfig->gainSetupByPinConfig.gainSelectGpioConfig[i].pin == ADI_ADRV9001_GPIO_UNASSIGNED) + fhConfig->gainSetupByPinConfig[j].numTxAttenTableEntries = armData[offset++]; + } + + tempOffset = offset + 2 * ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; + /* Rx and Tx tables */ + for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) + { + for (i = 0; i < ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; i++) + { + fhConfig->gainSetupByPinConfig[j].rxGainTable[i] = armData[offset++]; + } + } + for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) + { + for (i = 0; i < ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; i++) + { + adrv9001_ParseTwoBytes(&tempOffset, armData, &fhConfig->gainSetupByPinConfig[j].txAttenTable[i]); + } + } + /* Inspect ADRV9001 GPIOs */ + for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) + { + fhConfig->gainSetupByPinConfig[j].numGainCtrlPins = ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_PINS; + } + for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) + for (i = 0; i < ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_PINS; i++) { - fhConfig->gainSetupByPinConfig.numGainCtrlPins = i; - break; + gainSelectPinSignal = j == 0 ? ADI_ADRV9001_GPIO_SIGNAL_FH_CH1_GAIN_ATTEN_SEL_0 : ADI_ADRV9001_GPIO_SIGNAL_FH_CH2_GAIN_ATTEN_SEL_0;; + ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, (gainSelectPinSignal + i), &(fhConfig->gainSetupByPinConfig[j].gainSelectGpioConfig[i])); + if (fhConfig->gainSetupByPinConfig[j].gainSelectGpioConfig[i].pin == ADI_ADRV9001_GPIO_UNASSIGNED) + { + fhConfig->gainSetupByPinConfig[j].numGainCtrlPins = i; + break; + } } - } } ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP, &(fhConfig->hopSignalGpioConfig[0])); ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_TABLE_SELECT, &(fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[0])); - + if (fhConfig->mode == ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) { ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2, &(fhConfig->hopSignalGpioConfig[1])); ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2_TABLE_SELECT, &(fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[1])); } - - /* Configure table index pins if selected */ + + /* Inspect table index pins if selected */ if (fhConfig->tableIndexCtrl == ADI_ADRV9001_TABLEINDEXCTRL_GPIO) { frequencySelectPinSignal = ADI_ADRV9001_GPIO_SIGNAL_FH_TABLE_INDEX_0; @@ -643,7 +728,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhMode_e mode, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t hopTableSize) { @@ -651,9 +736,9 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 uint32_t hopTableAddress = 0; uint32_t offset = 0; uint32_t frequencyIndex = 0; - uint8_t bitmSwInt; uint8_t numHopTableEntries[4u]; uint32_t hopTableBufferAddress = 0; + /* ARM Data is written directly to ARM memory because FREQ_HOPPING_NUM_BYTES is greater than set buffer size */ #ifndef __KERNEL__ uint8_t armData[FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; @@ -666,55 +751,57 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 memset(&armData, 0, sizeof(armData)); #endif - - hopTableAddress = (tableId == ADI_ADRV9001_FHHOPTABLE_A) ? adrv9001->devStateInfo.fhHopTable1Addr : - adrv9001->devStateInfo.fhHopTable2Addr; - hopTableAddress += (hopSignal * (FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET)); - hopTableBufferAddress = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, hopTableAddress); - - /* Trigger appropriate SPI Interrupt upon table load */ - if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) - { - /* Set bit 0 to SW_INTERRUPT_4 to trigger SWInt4 to load FH table A - Set bit 1 to SW_INTERRUPT_4 to trigger SWInt11 to load FH table B */ - bitmSwInt = (tableId == ADI_ADRV9001_FHHOPTABLE_A) ? 0x1 : 0x2; - } - else - { - /* Set bit 7 to SW_INTERRUPT_4 to trigger SWInt5 to load FH table A - Set bit 6 to SW_INTERRUPT_4 to trigger SWInt6 to load FH table B */ - bitmSwInt = (tableId == ADI_ADRV9001_FHHOPTABLE_A) ? 0x80 : 0x40; - } - - ADI_PERFORM_VALIDATION(adi_adrv9001_fh_HopTable_Static_Configure_Validate, adrv9001, mode, hopSignal, tableId, hopTable, hopTableSize); - + if (tableId == ADI_ADRV9001_FHHOPTABLE_A) + { + if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) + { + hopTableAddress = adrv9001->devStateInfo.fhHopTableA1Addr; + hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + } + else + { + hopTableAddress = adrv9001->devStateInfo.fhHopTableA2Addr; + hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferA2Addr; + } + } + else + { + if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) + { + hopTableAddress = adrv9001->devStateInfo.fhHopTableB1Addr; + hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB1Addr; + } + else + { + hopTableAddress = adrv9001->devStateInfo.fhHopTableB2Addr; + hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB2Addr; + } + } + adrv9001_LoadFourBytes(&offset, numHopTableEntries, hopTableSize); offset = 0; for (frequencyIndex = 0; frequencyIndex < hopTableSize; frequencyIndex++) { - adrv9001_LoadEightBytes(&offset, armData, hopTable[frequencyIndex].hopFrequencyHz); + adrv9001_LoadFourBytes(&offset, armData, (hopTable[frequencyIndex].hopFrequencyHz & 0xFFFFFFFF)); + adrv9001_LoadFourBytes(&offset, armData, ((hopTable[frequencyIndex].hopFrequencyHz >> 32) & 0xFFFFFFFF)); + adrv9001_LoadFourBytes(&offset, armData, hopTable[frequencyIndex].rx1OffsetFrequencyHz); adrv9001_LoadFourBytes(&offset, armData, hopTable[frequencyIndex].rx2OffsetFrequencyHz); - armData[offset++] = hopTable[frequencyIndex].rxGainIndex; - offset ++; /* Padding */ - adrv9001_LoadTwoBytes(&offset, armData, hopTable[frequencyIndex].txAttenuation_mdB); - offset += 4; /* Padding */ + armData[offset++] = hopTable[frequencyIndex].rx1GainIndex; + armData[offset++] = hopTable[frequencyIndex].rx2GainIndex; + armData[offset++] = hopTable[frequencyIndex].tx1Attenuation_fifthdB; + armData[offset++] = hopTable[frequencyIndex].tx2Attenuation_fifthdB; } - - /* Write the data directly to the ARM memory */ - ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, hopTableAddress, numHopTableEntries, sizeof(numHopTableEntries), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); - /* 'offset' is used to represent the exact number of bytes to write to avoid writing over the entire table */ - ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, hopTableBufferAddress, armData, offset, ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); - - /* Issue SW interrupt 4 or 11 to load FH table A or B. The SPI reg is self-cleared so there is no need to do read/mod/write. */ - ADRV9001_SPIWRITEBYTE(adrv9001, "ADRV9001_ADDR_SW_INTERRUPT_4", ADRV9001_ADDR_SW_INTERRUPT_4, bitmSwInt); - + + /* Write the data directly to the ARM memory */ + /* 'offset' is used to represent the exact number of bytes to write to avoid writing over the entire table */ + ADI_EXPECT(adi_adrv9001_arm_Memory_WriteFH, adrv9001, hopSignal, tableId, hopTableAddress, numHopTableEntries, sizeof(numHopTableEntries), hopTableBufferAddress, armData, offset); ADI_API_RETURN(adrv9001); } int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t hopTableSize, uint32_t *numHopFramesRead) @@ -727,6 +814,9 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, uint8_t numHopFrequenciesReadbackBlock[4u] = { 0 }; uint32_t hopTableBufferAddress = 0; uint32_t numHopFrequenciesReadback = 0; + uint32_t hopFrequencyHz_LSB = 0; + uint32_t hopFrequencyHz_MSB = 0; + #ifndef __KERNEL__ uint8_t armData[FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; #else @@ -738,14 +828,36 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, memset(&armData, 0, sizeof(armData)); #endif - - hopTableAddress = (tableId == ADI_ADRV9001_FHHOPTABLE_A) ? adrv9001->devStateInfo.fhHopTable1Addr : - adrv9001->devStateInfo.fhHopTable2Addr; - hopTableAddress += (hopSignal * (FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET)); - hopTableBufferAddress = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, hopTableAddress); + + if (tableId == ADI_ADRV9001_FHHOPTABLE_A) + { + if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) + { + hopTableAddress = adrv9001->devStateInfo.fhHopTableA1Addr; + hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + } + else + { + hopTableAddress = adrv9001->devStateInfo.fhHopTableA2Addr; + hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferA2Addr; + } + } + else + { + if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) + { + hopTableAddress = adrv9001->devStateInfo.fhHopTableB1Addr; + hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB1Addr; + } + else + { + hopTableAddress = adrv9001->devStateInfo.fhHopTableB2Addr; + hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB2Addr; + } + } ADI_PERFORM_VALIDATION(adi_adrv9001_fh_HopTable_Inspect_Validate, adrv9001, hopSignal, tableId, hopTable, hopTableSize); - /* Even though we are going to read directly from ARM memory, we can still use the GET protocol to + /* Even though we are going to read directly from ARM memory, we can still use the GET protocol to tell ARM how many bytes we will read. ARM will return an error if the read size is invalid */ adrv9001_LoadFourBytes(&offset, armData, sizeof(armData)); @@ -761,7 +873,7 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, OBJID_GO_GET_FH_HOP_TABLE, ADI_ADRV9001_DEFAULT_TIMEOUT_US, ADI_ADRV9001_DEFAULT_INTERVAL_US); - + /* First read number of frequencies in hop table */ offset = 0; ADI_EXPECT(adi_adrv9001_arm_Memory_Read, adrv9001, hopTableAddress, numHopFrequenciesReadbackBlock, sizeof(numHopFrequenciesReadbackBlock), false); @@ -771,7 +883,7 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, *numHopFramesRead = numHopFrequenciesReadback; } /* Read back the hopping table from ARM memory based on number of HOP frequencies */ - numberOfBytesReadback = (numHopFrequenciesReadback * sizeof(adi_adrv9001_FhHopFrame_t)); + numberOfBytesReadback = (numHopFrequenciesReadback * sizeof(adrv9001_FhHopFrame_t)); if (numberOfBytesReadback > FREQ_HOPPING_MAX_NUM_BYTES) { numberOfBytesReadback = FREQ_HOPPING_MAX_NUM_BYTES; @@ -792,14 +904,16 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, offset = 0; for (frequencyIndex = 0; frequencyIndex < numHopFrequenciesReadback; frequencyIndex++) { - adrv9001_ParseEightBytes(&offset, armData, &hopTable[frequencyIndex].hopFrequencyHz); + adrv9001_ParseFourBytes(&offset, armData, &hopFrequencyHz_LSB); + adrv9001_ParseFourBytes(&offset, armData, &hopFrequencyHz_MSB); + hopTable[frequencyIndex].hopFrequencyHz = (((uint64_t)hopFrequencyHz_MSB << 32) | (uint64_t)hopFrequencyHz_LSB); + adrv9001_ParseFourBytes(&offset, armData, (uint32_t *)(&hopTable[frequencyIndex].rx1OffsetFrequencyHz)); adrv9001_ParseFourBytes(&offset, armData, (uint32_t *)(&hopTable[frequencyIndex].rx2OffsetFrequencyHz)); - hopTable[frequencyIndex].rxGainIndex = armData[offset++]; - hopTable[frequencyIndex].reserved = 0; - offset ++; /* Padding */ - adrv9001_ParseTwoBytes(&offset, armData, &hopTable[frequencyIndex].txAttenuation_mdB); - offset += 4; /* Padding */ + hopTable[frequencyIndex].rx1GainIndex = armData[offset++]; + hopTable[frequencyIndex].rx2GainIndex = armData[offset++]; + hopTable[frequencyIndex].tx1Attenuation_fifthdB = armData[offset++]; + hopTable[frequencyIndex].tx2Attenuation_fifthdB = armData[offset++]; } ADI_API_RETURN(adrv9001); @@ -861,19 +975,21 @@ int32_t adi_adrv9001_fh_HopTable_Get(adi_adrv9001_Device_t *adrv9001, ADI_API_RETURN(adrv9001); } -int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhFrameIndex_e frameIndex, adi_adrv9001_FhHopFrame_t *hopFrame) { uint8_t armData[16u] = { 0 }; uint8_t extData[5u] = { 0 }; uint32_t offset = 0; + uint32_t hopFrequencyHz_LSB = 0; + uint32_t hopFrequencyHz_MSB = 0; /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); ADI_NULL_PTR_RETURN(&adrv9001->common, hopFrame); ADI_RANGE_CHECK(adrv9001, frameIndex, ADI_ADRV9001_FHFRAMEINDEX_CURRENT_FRAME, ADI_ADRV9001_FHFRAMEINDEX_NEXT_FRAME); - + /* Write the size to the GET buffer */ adrv9001_LoadFourBytes(&offset, armData, sizeof(armData)); ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_GET, armData, sizeof(uint32_t), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); @@ -894,17 +1010,20 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, /* Read config data from GET buffer */ offset = 0; // Reset offset ADI_EXPECT(adi_adrv9001_arm_Memory_Read, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_GET, armData, sizeof(armData), false); - adrv9001_ParseEightBytes(&offset, armData, &hopFrame->hopFrequencyHz); + adrv9001_ParseFourBytes(&offset, armData, &hopFrequencyHz_LSB); + adrv9001_ParseFourBytes(&offset, armData, &hopFrequencyHz_MSB); + hopFrame->hopFrequencyHz = (((uint64_t)hopFrequencyHz_MSB << 32) | (uint64_t)hopFrequencyHz_LSB); + adrv9001_ParseFourBytes(&offset, armData, (uint32_t *)(&hopFrame->rx1OffsetFrequencyHz)); adrv9001_ParseFourBytes(&offset, armData, (uint32_t *)(&hopFrame->rx2OffsetFrequencyHz)); - hopFrame->rxGainIndex = armData[offset++]; - hopFrame->reserved = 0; - offset ++; /* Padding */ - adrv9001_ParseTwoBytes(&offset, armData, &hopFrame->txAttenuation_mdB); + hopFrame->rx1GainIndex = armData[offset++]; + hopFrame->rx2GainIndex = armData[offset++]; + hopFrame->tx1Attenuation_fifthdB = armData[offset++]; + hopFrame->tx2Attenuation_fifthdB = armData[offset++]; ADI_API_RETURN(adrv9001); -} +} -int32_t adi_adrv9001_fh_Hop(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_fh_Hop(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal) { /* Flip the hop signal */ @@ -941,7 +1060,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_NumberOfHops_Get(adi_adrv9001_Devi default: ADI_SHOULD_NOT_EXECUTE(adrv9001); } - + ADI_API_RETURN(adrv9001); } @@ -973,7 +1092,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure_Validat mode, "FH mode must be dual hop for hopSignal to be HOP_2 "); } - + } ADI_ENTRY_PTR_EXPECT(adrv9001, spiPackedFhTable); @@ -1001,7 +1120,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure_Validat ADI_COMMON_ACT_ERR_CHECK_PARAM, tableSize, "spiPackedFhTable[] size is not sufficient "); - + } for (frequencyIndex = 0; frequencyIndex < tableSize; frequencyIndex++) { @@ -1065,10 +1184,10 @@ static uint32_t adrv9001_HopTable_Spi_Pack(adi_adrv9001_Device_t *adrv9001, for (i = 0; i < numberOfHops; i++) { - for (j = 0; j < sizeof(adi_adrv9001_FhHopFrame_t); j += 4) + for (j = 0; j < sizeof(adrv9001_FhHopFrame_t); j += 4) { addrIdx = j % 4; - dataIdx = (i * sizeof(adi_adrv9001_FhHopFrame_t)) + j; + dataIdx = (i * sizeof(adrv9001_FhHopFrame_t)) + j; adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADDR_ARM_DMA_DATA[addrIdx + 0], hopTable[dataIdx + 3], ADRV9001_SPI_WRITE_POLARITY); adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADDR_ARM_DMA_DATA[addrIdx + 1], hopTable[dataIdx + 2], ADRV9001_SPI_WRITE_POLARITY); adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADDR_ARM_DMA_DATA[addrIdx + 2], hopTable[dataIdx + 1], ADRV9001_SPI_WRITE_POLARITY); @@ -1078,7 +1197,7 @@ static uint32_t adrv9001_HopTable_Spi_Pack(adi_adrv9001_Device_t *adrv9001, /* Issue SW interrupt 4 or 11 to load FH table A or B. The SPI reg is self-cleared so there is no need to do read/mod/write. */ adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADRV9001_ADDR_SW_INTERRUPT_4, bitmSwInt, ADRV9001_SPI_WRITE_POLARITY); - + /* Restore back the original values of ADRV9001 DMA control register */ adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADRV9001_ADDR_ARM_DMA_CTL, regVal, ADRV9001_SPI_WRITE_POLARITY); @@ -1102,8 +1221,8 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 uint32_t armAddr_B = 0; uint32_t hopTableBufferAddress_A = 0; uint32_t hopTableBufferAddress_B = 0; - uint8_t fhTable_A[160] = { 0 }; - uint8_t fhTable_B[160] = { 0 }; + uint8_t fhTable_A[sizeof(adrv9001_FhHopFrame_t) * 8] = { 0 }; + uint8_t fhTable_B[sizeof(adrv9001_FhHopFrame_t) * 8] = { 0 }; uint32_t numWrBytes = 0; uint32_t i = 0; uint32_t j = 0; @@ -1118,88 +1237,84 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 if (ADI_ADRV9001_FH_HOP_SIGNAL_1 == hopSignal) { bitmSwInt_A = 0x1; - hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTable1Addr; - hopTableBufferAddress_A += (ADI_ADRV9001_FH_HOP_SIGNAL_1 * (FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET)); - armAddr_A = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, hopTableBufferAddress_A); - - bitmSwInt_B = 0x80; - hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTable1Addr; - hopTableBufferAddress_B += (ADI_ADRV9001_FH_HOP_SIGNAL_2 * (FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET)); - armAddr_B = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, hopTableBufferAddress_B); + hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + armAddr_A = adrv9001->devStateInfo.fhHopTableA1Addr; + + bitmSwInt_B = 0x80; + hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; + armAddr_B = adrv9001->devStateInfo.fhHopTableB1Addr; } else //ADI_ADRV9001_FH_HOP_SIGNAL_2 { bitmSwInt_A = 0x2; - hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTable2Addr; - hopTableBufferAddress_A += (ADI_ADRV9001_FH_HOP_SIGNAL_1 * (FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET)); - armAddr_A = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, hopTableBufferAddress_A); + hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA2Addr; + armAddr_A = adrv9001->devStateInfo.fhHopTableA2Addr; bitmSwInt_B = 0x40; - hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTable2Addr; - hopTableBufferAddress_B += (ADI_ADRV9001_FH_HOP_SIGNAL_2 * (FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET)); - armAddr_B = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, hopTableBufferAddress_B); + hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB2Addr; + armAddr_B = adrv9001->devStateInfo.fhHopTableB2Addr; } } else { - bitmSwInt_A = 0x1; - hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTable1Addr; - hopTableBufferAddress_A += (ADI_ADRV9001_FH_HOP_SIGNAL_1 * (FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET)); - armAddr_A = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, hopTableBufferAddress_A); - - bitmSwInt_B = 0x2; - hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTable2Addr; - hopTableBufferAddress_B += (ADI_ADRV9001_FH_HOP_SIGNAL_1 * (FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET)); - armAddr_B = adi_adrv9001_fh_GetHopTableBufferAddress(adrv9001, hopTableBufferAddress_B); + bitmSwInt_A = 0x1; + hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + armAddr_A = adrv9001->devStateInfo.fhHopTableA1Addr; + + bitmSwInt_B = 0x2; + hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; + armAddr_B = adrv9001->devStateInfo.fhHopTableB1Addr; } armAddr_A >>= 2; hopTableBufferAddress_A >>= 2; - addrArray_A[0] = (uint8_t)((hopTableBufferAddress_A >> 24) & 0x000000FF); - addrArray_A[1] = (uint8_t)((hopTableBufferAddress_A >> 16) & 0x000000FF); - addrArray_A[2] = (uint8_t)((hopTableBufferAddress_A >> 8) & 0x000000FF); - addrArray_A[3] = (uint8_t)(hopTableBufferAddress_A & 0x000000FF); - addrArray_A[4] = (uint8_t)((armAddr_A >> 24) & 0x000000FF); - addrArray_A[5] = (uint8_t)((armAddr_A >> 16) & 0x000000FF); - addrArray_A[6] = (uint8_t)((armAddr_A >> 8) & 0x000000FF); - addrArray_A[7] = (uint8_t)(armAddr_A & 0x000000FF); + addrArray_A[0] = (uint8_t)((armAddr_A >> 24) & 0x000000FF); + addrArray_A[1] = (uint8_t)((armAddr_A >> 16) & 0x000000FF); + addrArray_A[2] = (uint8_t)((armAddr_A >> 8) & 0x000000FF); + addrArray_A[3] = (uint8_t)(armAddr_A & 0x000000FF); + addrArray_A[4] = (uint8_t)((hopTableBufferAddress_A >> 24) & 0x000000FF); + addrArray_A[5] = (uint8_t)((hopTableBufferAddress_A >> 16) & 0x000000FF); + addrArray_A[6] = (uint8_t)((hopTableBufferAddress_A >> 8) & 0x000000FF); + addrArray_A[7] = (uint8_t)(hopTableBufferAddress_A & 0x000000FF); armAddr_B >>= 2; hopTableBufferAddress_B >>= 2; - addrArray_B[0] = (uint8_t)((hopTableBufferAddress_B >> 24) & 0x000000FF); - addrArray_B[1] = (uint8_t)((hopTableBufferAddress_B >> 16) & 0x000000FF); - addrArray_B[2] = (uint8_t)((hopTableBufferAddress_B >> 8) & 0x000000FF); - addrArray_B[3] = (uint8_t)(hopTableBufferAddress_B & 0x000000FF); - addrArray_B[4] = (uint8_t)((armAddr_B >> 24) & 0x000000FF); - addrArray_B[5] = (uint8_t)((armAddr_B >> 16) & 0x000000FF); - addrArray_B[6] = (uint8_t)((armAddr_B >> 8) & 0x000000FF); - addrArray_B[7] = (uint8_t)(armAddr_B & 0x000000FF); + addrArray_B[0] = (uint8_t)((armAddr_B >> 24) & 0x000000FF); + addrArray_B[1] = (uint8_t)((armAddr_B >> 16) & 0x000000FF); + addrArray_B[2] = (uint8_t)((armAddr_B >> 8) & 0x000000FF); + addrArray_B[3] = (uint8_t)(armAddr_B & 0x000000FF); + addrArray_B[4] = (uint8_t)((hopTableBufferAddress_B >> 24) & 0x000000FF); + addrArray_B[5] = (uint8_t)((hopTableBufferAddress_B >> 16) & 0x000000FF); + addrArray_B[6] = (uint8_t)((hopTableBufferAddress_B >> 8) & 0x000000FF); + addrArray_B[7] = (uint8_t)(hopTableBufferAddress_B & 0x000000FF); for (i = 0; i < hopTableSize; i += (2 * numberOfHops)) { offset = 0; for (j = 0; j < numberOfHops; j++) { - adrv9001_LoadEightBytes(&offset, fhTable_A, hopTable[i + j].hopFrequencyHz); + adrv9001_LoadFourBytes(&offset, fhTable_A, (hopTable[i + j].hopFrequencyHz & 0xFFFFFFFF)); + adrv9001_LoadFourBytes(&offset, fhTable_A, ((hopTable[i + j].hopFrequencyHz >> 32) & 0xFFFFFFFF)); adrv9001_LoadFourBytes(&offset, fhTable_A, hopTable[i + j].rx1OffsetFrequencyHz); adrv9001_LoadFourBytes(&offset, fhTable_A, hopTable[i + j].rx2OffsetFrequencyHz); - fhTable_A[offset++] = hopTable[i + j].rxGainIndex; - offset++; /* Padding */ - adrv9001_LoadTwoBytes(&offset, fhTable_A, hopTable[i + j].txAttenuation_mdB); - offset += 4; /* Padding */ + fhTable_A[offset++] = hopTable[i + j].rx1GainIndex; + fhTable_A[offset++] = hopTable[i + j].rx2GainIndex; + adrv9001_LoadTwoBytes(&offset, fhTable_A, hopTable[i + j].tx1Attenuation_fifthdB); + adrv9001_LoadTwoBytes(&offset, fhTable_A, hopTable[i + j].tx2Attenuation_fifthdB); } ADI_EXPECT(adrv9001_HopTable_Spi_Pack, adrv9001, addrArray_A, fhTable_A, numberOfHops, &numWrBytes, bitmSwInt_A, spiPackedFhTable); - + offset = 0; for (j = numberOfHops; j < (2 * numberOfHops); j++) { - adrv9001_LoadEightBytes(&offset, fhTable_B, hopTable[i + j].hopFrequencyHz); + adrv9001_LoadFourBytes(&offset, fhTable_B, (hopTable[i + j].hopFrequencyHz & 0xFFFFFFFF)); + adrv9001_LoadFourBytes(&offset, fhTable_B, ((hopTable[i + j].hopFrequencyHz >> 32) & 0xFFFFFFFF)); adrv9001_LoadFourBytes(&offset, fhTable_B, hopTable[i + j].rx1OffsetFrequencyHz); adrv9001_LoadFourBytes(&offset, fhTable_B, hopTable[i + j].rx2OffsetFrequencyHz); - fhTable_B[offset++] = hopTable[i + j].rxGainIndex; - offset++; /* Padding */ - adrv9001_LoadTwoBytes(&offset, fhTable_B, hopTable[i + j].txAttenuation_mdB); - offset += 4; /* Padding */ + fhTable_B[offset++] = hopTable[i + j].rx1GainIndex; + fhTable_B[offset++] = hopTable[i + j].rx2GainIndex; + adrv9001_LoadTwoBytes(&offset, fhTable_B, hopTable[i + j].tx1Attenuation_fifthdB); + adrv9001_LoadTwoBytes(&offset, fhTable_B, hopTable[i + j].tx2Attenuation_fifthdB); } ADI_EXPECT(adrv9001_HopTable_Spi_Pack, adrv9001, addrArray_B, fhTable_B, numberOfHops, &numWrBytes, bitmSwInt_B, spiPackedFhTable); } @@ -1234,8 +1349,8 @@ int32_t adi_adrv9001_fh_HopTable_BytesPerTable_Get(adi_adrv9001_Device_t *adrv90 ADI_EXPECT(adi_adrv9001_fh_NumberOfHops_Get, adrv9001, numberHopsPerDynamicLoad, &numberOfHops); spiPackBytesPerTable = spiConfigBytes + spiAddrPackLength + spiInterruptBytes; - - payloadBytes = ((sizeof(adi_adrv9001_FhHopFrame_t) * numberOfHops) + fhBytesLength) * 3; + + payloadBytes = ((sizeof(adrv9001_FhHopFrame_t) * numberOfHops) + fhBytesLength) * 3; *bytesPerTable = payloadBytes + spiPackBytesPerTable; ADI_API_RETURN(adrv9001); diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c index f8241b369915f8..30800ec233900d 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c @@ -145,6 +145,17 @@ int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *device, if (ADI_ADRV9001_GPIO_DIGITAL_00 <= pin && pin <= ADI_ADRV9001_GPIO_DIGITAL_15) { ADI_EXPECT(adrv9001_NvsRegmapCore_NvsGpioSpiRead_Get, device, &pinLevels); + + /* Work around for swapped bitfield DGPIO12 to DGPIO15 */ + if (ADI_ADRV9001_GPIO_DIGITAL_12 == pin || ADI_ADRV9001_GPIO_DIGITAL_14 == pin) + { + pin++; + } + else if (ADI_ADRV9001_GPIO_DIGITAL_13 == pin || ADI_ADRV9001_GPIO_DIGITAL_15 == pin) + { + pin--; + } + *gpioInPinLevel = (pinLevels & (1 << (pin - 1))) >> (pin - 1); } else if (ADI_ADRV9001_GPIO_ANALOG_00 <= pin && pin <= ADI_ADRV9001_GPIO_ANALOG_11) @@ -213,38 +224,6 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_gpio_ManualAnalogInput ADI_API_RETURN(device); } -static __maybe_unused int32_t adi_adrv9001_gpio_PinDirection_Get_Validate(adi_adrv9001_Device_t *device, - adi_adrv9001_GpioPin_e pin) -{ - ADI_API_RETURN(device); - ADI_RANGE_CHECK(device, pin, ADI_ADRV9001_GPIO_DIGITAL_00, ADI_ADRV9001_GPIO_ANALOG_11); -} - -int32_t adi_adrv9001_gpio_PinDirection_Get(adi_adrv9001_Device_t *device, - adi_adrv9001_GpioPin_e pin, - adi_adrv9001_GpioPinDirection_e *direction) -{ - uint16_t gpioOutEn = 0; - - ADI_PERFORM_VALIDATION(adi_adrv9001_gpio_PinDirection_Get_Validate, device, pin); - if (ADI_ADRV9001_GPIO_DIGITAL_00 <= pin && pin <= ADI_ADRV9001_GPIO_DIGITAL_15) - { - ADI_EXPECT(adrv9001_NvsRegmapCore_NvsGpioDirectionControlOe_Get, device, &gpioOutEn); - *direction = (gpioOutEn & (1 << (pin - 1))) >> (pin - 1); - } - else if (ADI_ADRV9001_GPIO_ANALOG_00 <= pin && pin <= ADI_ADRV9001_GPIO_ANALOG_11) - { - ADI_EXPECT(adrv9001_NvsRegmapCore1_NvsGpioAnalogDirectionControlOe_Get, device, &gpioOutEn); - *direction = (gpioOutEn & (1 << (pin - ADI_ADRV9001_GPIO_ANALOG_00))) >> (pin - ADI_ADRV9001_GPIO_ANALOG_00); - } - else - { - ADI_SHOULD_NOT_EXECUTE(device); - } - - ADI_API_RETURN(device); -} - int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *device, adi_adrv9001_GpioPin_e pin) { @@ -350,23 +329,6 @@ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_MON_BBIC_WAKEUP, &initCfg->systemPowerSavingAndMonitorWakeUp); } - if (ADI_ADRV9001_GPIO_UNASSIGNED != initCfg->rx1ExternalLnaPinCfg[0].pin) - { - ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_RX1_LNA_ATTENUATION_1, &initCfg->rx1ExternalLnaPinCfg[0]); - } - if (ADI_ADRV9001_GPIO_UNASSIGNED != initCfg->rx1ExternalLnaPinCfg[1].pin) - { - ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_RX1_LNA_ATTENUATION_2, &initCfg->rx1ExternalLnaPinCfg[1]); - } - if (ADI_ADRV9001_GPIO_UNASSIGNED != initCfg->rx2ExternalLnaPinCfg[0].pin) - { - ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_RX2_LNA_ATTENUATION_1, &initCfg->rx2ExternalLnaPinCfg[0]); - } - if (ADI_ADRV9001_GPIO_UNASSIGNED != initCfg->rx2ExternalLnaPinCfg[1].pin) - { - ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_RX2_LNA_ATTENUATION_2, &initCfg->rx2ExternalLnaPinCfg[1]); - } - ADI_API_RETURN(adrv9001); } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_powersavingandmonitormode.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_powersavingandmonitormode.c index 554e1d27ef1b70..ebc518ae1d03fb 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_powersavingandmonitormode.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_powersavingandmonitormode.c @@ -330,7 +330,7 @@ int32_t adi_adrv9001_powerSavingAndMonitorMode_SystemPowerSavingAndMonitorMode_C adrv9001_LoadFourBytes(&offset, armData, monitorModeCfg->initialBatterySaverDelay_us); adrv9001_LoadFourBytes(&offset, armData, monitorModeCfg->detectionTime_us); adrv9001_LoadFourBytes(&offset, armData, monitorModeCfg->sleepTime_us); - offset++; + armData[offset++] = (uint8_t)monitorModeCfg->bbicWakeupLevelEnable; armData[offset++] = (uint8_t)monitorModeCfg->externalPllEnable; /* Write monitor mode configuration parameters to ARM data memory */ @@ -390,7 +390,7 @@ int32_t adi_adrv9001_powerSavingAndMonitorMode_SystemPowerSavingAndMonitorMode_I adrv9001_ParseFourBytes(&offset, armReadBack, &monitorModeCfg->sleepTime_us); monitorModeCfg->detectionFirst = armReadBack[offset++]; monitorModeCfg->detectionMode = (adi_adrv9001_PowerSavingAndMonitorMode_MonitorDetectionMode_e)armReadBack[offset++]; - offset++; + monitorModeCfg->bbicWakeupLevelEnable = (armReadBack[offset++] == 1) ? true : false; monitorModeCfg->externalPllEnable = (armReadBack[offset++] == 1) ? true : false; ADI_API_RETURN(device); @@ -405,6 +405,7 @@ int32_t adi_adrv9001_powerSavingAndMonitorMode_SystemPowerSavingMode_Set(adi_adr .sleepTime_us = 0xFFFFFFFF, .detectionFirst = 0, .detectionMode = ADI_ADRV9001_POWERSAVINGANDMONITORMODE_MONITOR_DETECTION_MODE_RSSI, + .bbicWakeupLevelEnable = false, }; config.powerDownMode = mode; @@ -685,14 +686,14 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_powerSavingAndMonitorM { adi_common_port_to_index(ports[port], &port_index); adi_common_channel_to_index(channels[channel], &chan_index); - if (ADI_ADRV9001_CHANNEL_STANDBY != state.channelStates[port_index][chan_index]) + if (ADI_ADRV9001_CHANNEL_RF_ENABLED == state.channelStates[port_index][chan_index]) { ADI_ERROR_REPORT(&adrv9001->common, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_INV_PARAM, ADI_COMMON_ACT_ERR_CHECK_PARAM, channel, - "Invalid channel state. Channel must be in STANDBY state"); + "Invalid channel state. Channel must be in STANDBY, CALIBRATED or PRIMED state"); ADI_ERROR_RETURN(adrv9001->common.error.newAction); } } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_radio.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_radio.c index 9fde41084c8b41..8b42db12fb620a 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_radio.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_radio.c @@ -84,6 +84,7 @@ int32_t adi_adrv9001_Radio_Carrier_Configure(adi_adrv9001_Device_t *adrv9001, armData[offset++] = carrier->loGenOptimization; /* Loading byte array with parsed bytes from intermediateFrequency_Hz word */ adrv9001_LoadFourBytes(&offset, armData, carrier->intermediateFrequency_Hz); + armData[offset++] = (uint8_t)(carrier->manualRxport & 0x1); /* Write carrier Frequency to ARM mailbox */ ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, (uint32_t)ADRV9001_ADDR_ARM_MAILBOX_SET, &armData[0], sizeof(armData), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c index 8580c6846890e6..623f616122fe48 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c @@ -98,7 +98,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Write_Val // Maximum combined gain step must not exceed 29000 mdB ADI_RANGE_CHECK(device, totalGainSteps, 0, 29000); } - + /*Check that the gain index offset is within range*/ ADI_RANGE_CHECK(device, gainIndexOffset, ADI_ADRV9001_MIN_RX_GAIN_TABLE_INDEX, ADI_ADRV9001_START_RX_GAIN_INDEX); @@ -126,7 +126,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Write_Val } ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + ADI_RANGE_CHECK(device, gainTableType, ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE, ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE); /*Check that Rx profile or ORx profile is valid*/ @@ -174,11 +174,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, int32_t j = 0; uint16_t numGainIndicesToWrite = 0; uint8_t lnaStepOffset = { 0 }; -#ifdef __KERNEL__ - static adi_adrv9001_RxGainTableRow_t lnaGainTable[127] = { { 0 } }; -#else adi_adrv9001_RxGainTableRow_t lnaGainTable[127] = { { 0 } }; -#endif adi_adrv9001_RxGainTableRow_t *gainTablePtr = NULL; uint8_t minGainIndex = 0; uint8_t indexOffset = 0; @@ -203,7 +199,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, { if (i == 0) { - lnaStepOffset = (gainIndexOffset - (lnaConfig->minGainIndex - 1)); + lnaStepOffset = (gainIndexOffset - (lnaConfig->minGainIndex - 1)); } else { @@ -227,7 +223,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, } gainTablePtr = lnaGainTable; } - + baseIndex = (gainIndexOffset - (numGainIndicesToWrite - 1)); minGainIndex = (uint8_t)baseIndex; ADI_EXPECT(adrv9001_RxGainTableFormat, device, gainTablePtr, &armDmaData[0], numGainIndicesToWrite); @@ -331,7 +327,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Read_Vali ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcMinimumGainIndex_Get, device, instance, &minGainIndex); ADI_RANGE_CHECK(device, gainIndexOffset, minGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); - + if (((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_RX_PROFILE_VALID)) == 0) && ((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_ORX_PROFILE_VALID)) == 0) && ((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_TX_PROFILE_VALID)) == 0)) @@ -466,7 +462,6 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a uint8_t gainIndex, adi_adrv9001_RxGainControlMode_e *gainCtrlMode) { - adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; static const uint32_t RX_CHANNELS[] = { ADI_ADRV9001_RX1, ADI_ADRV9001_RX2 }; uint8_t chan_idx = 0; uint8_t minGainIndex = 0; @@ -478,7 +473,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); adi_common_channel_to_index(channel, &chan_idx); - + /* Check that Rx profile is valid */ if (0 == ADRV9001_BF_EQUAL(device->devStateInfo.initializedChannels, RX_CHANNELS[chan_idx])) { @@ -497,10 +492,10 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcMinimumGainIndex_Get, device, instance, &minGainIndex); ADI_RANGE_CHECK(device, gainIndex, minGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); - + /* Save the current gain control mode and set to the required mode */ ADI_EXPECT(adi_adrv9001_Rx_GainControl_Mode_Get, device, channel, gainCtrlMode); - if (ADI_ADRV9001_RX_GAIN_CONTROL_MODE_AUTO == *gainCtrlMode) + if (ADI_ADRV9001_RX_GAIN_CONTROL_MODE_SPI != *gainCtrlMode) { ADI_ERROR_REPORT(&device->common, ADI_COMMON_ERRSRC_API, @@ -509,25 +504,6 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a channel, "Invalid Rx gain control mode to set Rx Gain"); } - else if (ADI_ADRV9001_RX_GAIN_CONTROL_MODE_PIN == *gainCtrlMode) - { - ADI_EXPECT(adi_adrv9001_Channel_Validate, device, channel); - - ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); - if (ADI_ADRV9001_CHANNEL_STANDBY == state) - { - ADI_ERROR_REPORT(&device->common, - ADI_COMMON_ERRSRC_API, - ADI_COMMON_ERR_INV_PARAM, - ADI_COMMON_ACT_ERR_CHECK_PARAM, - state, - "Invalid channel state to set gain index in ADI_ADRV9001_RX_GAIN_CONTROL_MODE_PIN mode."); - } - } - else /* ADI_ADRV9001_RX_GAIN_CONTROL_MODE_SPI */ - { - /* No action taken */ - } ADI_API_RETURN(device) } @@ -545,19 +521,8 @@ int32_t adi_adrv9001_Rx_Gain_Set(adi_adrv9001_Device_t *device, baseAddr = ADRV9001_BF_RXB2_CORE; } - if (ADI_ADRV9001_RX_GAIN_CONTROL_MODE_PIN == gainCtrlMode) - { - ADI_EXPECT(adi_adrv9001_Rx_GainControl_Mode_Set, device, channel, ADI_ADRV9001_RX_GAIN_CONTROL_MODE_SPI); - } - ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcManualGainIndex_Set, device, baseAddr, gainIndex); - /* Restore the gain control mode */ - if (ADI_ADRV9001_RX_GAIN_CONTROL_MODE_SPI != gainCtrlMode) - { - ADI_EXPECT(adi_adrv9001_Rx_GainControl_Mode_Set, device, channel, gainCtrlMode); - } - ADI_API_RETURN(device) } @@ -705,7 +670,7 @@ static __maybe_unused int32_t adi_adrv9001_Rx_InterfaceGain_Validate(adi_adrv900 adi_adrv9001_RxInterfaceGain_e rxInterfaceGainMax = ADI_ADRV9001_RX_INTERFACE_GAIN_NEGATIVE_36_DB; adi_common_channel_to_index(channel, &chan_index); - + if (device->devStateInfo.rxOutputRate_kHz[chan_index] < RX_OUTPUT_RATE_kHZ) { if (gainTableType == ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE) @@ -744,7 +709,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Confi adi_adrv9001_RxInterfaceGainCtrl_t *rxInterfaceGainCtrl) { adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&device->common, rxInterfaceGainCtrl); @@ -766,10 +731,20 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Confi device->devStateInfo.gainTableType[channel - 1], rxInterfaceGainCtrl->gain); + ADI_RANGE_CHECK(device, + rxInterfaceGainCtrl->rssiDuration, + 64, + 255); + + ADI_RANGE_CHECK(device, + rxInterfaceGainCtrl->rssiMovingAverageDuration, + 1, + 10); + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); if (ADI_ADRV9001_CHANNEL_CALIBRATED != state) { - ADI_ERROR_REPORT(device, + ADI_ERROR_REPORT(device, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -784,7 +759,7 @@ int32_t adi_adrv9001_Rx_InterfaceGain_Configure(adi_adrv9001_Device_t *device, adi_common_ChannelNumber_e channel, adi_adrv9001_RxInterfaceGainCtrl_t *rxInterfaceGainCtrl) { - uint8_t armData[4] = { 0 }; + uint8_t armData[8] = { 0 }; uint8_t extData[5] = { 0 }; ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_InterfaceGain_Configure_Validate, device, channel, rxInterfaceGainCtrl); @@ -793,6 +768,10 @@ int32_t adi_adrv9001_Rx_InterfaceGain_Configure(adi_adrv9001_Device_t *device, armData[1] = (uint8_t)(rxInterfaceGainCtrl->controlMode); armData[2] = (uint8_t)(device->devStateInfo.gainTableType[channel - 1]); armData[3] = (uint8_t)(rxInterfaceGainCtrl->gain); + armData[4] = (uint8_t)(rxInterfaceGainCtrl->rssiDuration); + armData[5] = (uint8_t)(rxInterfaceGainCtrl->rssiMovingAverageDuration); + armData[6] = (uint8_t)(rxInterfaceGainCtrl->reserved1); + armData[7] = (uint8_t)(rxInterfaceGainCtrl->reserved2); /* Write RX interface gain control parameters to ARM mailbox */ ADI_EXPECT(adi_adrv9001_arm_Memory_Write, device, ADRV9001_ADDR_ARM_MAILBOX_SET, &armData[0], sizeof(armData), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); @@ -844,12 +823,12 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Set_V /* Perform Range check of allowed gain value */ ADI_EXPECT(adi_adrv9001_Rx_InterfaceGain_Validate, device, channel, gainTableType, gain); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); if ((ADI_ADRV9001_CHANNEL_PRIMED != state) && (ADI_ADRV9001_CHANNEL_RF_ENABLED != state)) { - ADI_ERROR_REPORT(device, + ADI_ERROR_REPORT(device, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -930,7 +909,7 @@ int32_t adi_adrv9001_Rx_InterfaceGain_Inspect(adi_adrv9001_Device_t *device, adi_adrv9001_RxInterfaceGainCtrl_t *rxInterfaceGainCtrl, adi_adrv9001_RxGainTableType_e *gainTableType) { - uint8_t armReadBack[4] = { 0 }; + uint8_t armReadBack[8] = { 0 }; uint8_t extData[5] = { 0 }; ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_InterfaceGain_Inspect_Validate, device, channel, rxInterfaceGainCtrl, gainTableType); @@ -957,10 +936,12 @@ int32_t adi_adrv9001_Rx_InterfaceGain_Inspect(adi_adrv9001_Device_t *device, sizeof(armReadBack), ADRV9001_ARM_MEM_READ_AUTOINCR) - rxInterfaceGainCtrl->updateInstance = (adi_adrv9001_RxInterfaceGainUpdateTiming_e)armReadBack[0]; - rxInterfaceGainCtrl->controlMode = (adi_adrv9001_RxInterfaceGainCtrlMode_e)armReadBack[1]; - *gainTableType = (adi_adrv9001_RxGainTableType_e)armReadBack[2]; - rxInterfaceGainCtrl->gain = (adi_adrv9001_RxInterfaceGain_e)armReadBack[3]; + rxInterfaceGainCtrl->updateInstance = (adi_adrv9001_RxInterfaceGainUpdateTiming_e)armReadBack[0]; + rxInterfaceGainCtrl->controlMode = (adi_adrv9001_RxInterfaceGainCtrlMode_e)armReadBack[1]; + *gainTableType = (adi_adrv9001_RxGainTableType_e)armReadBack[2]; + rxInterfaceGainCtrl->gain = (adi_adrv9001_RxInterfaceGain_e)armReadBack[3]; + rxInterfaceGainCtrl->rssiDuration = armReadBack[4]; + rxInterfaceGainCtrl->rssiMovingAverageDuration = armReadBack[5]; ADI_API_RETURN(device); } @@ -1465,12 +1446,12 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_PortSwitch_Configur } /* NULL pointer check */ - ADI_NULL_PTR_RETURN(&device->common, switchConfig); + ADI_NULL_PTR_RETURN(&device->common, switchConfig); /* Freuqency range check */ - ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); - ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); - ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); /* Min frequency must be smaller than max */ @@ -1498,16 +1479,16 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_PortSwitch_Configur "Port A and B freuqency ranges cannot overlap."); ADI_API_RETURN(device) } - + ADI_API_RETURN(device); } int32_t adi_adrv9001_Rx_PortSwitch_Configure(adi_adrv9001_Device_t *device, adi_adrv9001_RxPortSwitchCfg_t *switchConfig) { - uint8_t armData[41] = { 0 }; + uint8_t armData[42] = { 0 }; uint8_t extData[3] = { 0 }; - uint32_t offset = 0u; + uint32_t offset = 0u; ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_PortSwitch_Configure_Validate, device, switchConfig); @@ -1519,7 +1500,8 @@ int32_t adi_adrv9001_Rx_PortSwitch_Configure(adi_adrv9001_Device_t *device, adrv9001_LoadEightBytes(&offset, armData, switchConfig->maxFreqPortA_Hz); adrv9001_LoadEightBytes(&offset, armData, switchConfig->minFreqPortB_Hz); adrv9001_LoadEightBytes(&offset, armData, switchConfig->maxFreqPortB_Hz); - armData[offset] = switchConfig->enable; + armData[offset++] = switchConfig->enable; + armData[offset++] = switchConfig->manualRxPortSwitch; ADI_EXPECT(adi_adrv9001_arm_Memory_Write, device, @@ -1531,7 +1513,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Configure(adi_adrv9001_Device_t *device, extData[0] = 0; extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_CFG_RX_PORT_SWITCHING; - + ADI_EXPECT(adi_adrv9001_arm_Config_Write, device, armData, sizeof(armData), extData, sizeof(extData)) ADI_API_RETURN(device); @@ -1554,7 +1536,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Inspect(adi_adrv9001_Device_t *device, ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_PortSwitch_Inspect_Validate, device, switchConfig); ADI_EXPECT(adi_adrv9001_arm_Config_Read, device, OBJID_CFG_RX_PORT_SWITCHING, channelMask, offset, armReadBack, sizeof(armReadBack)) - + adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->minFreqPortA_Hz); adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->maxFreqPortA_Hz); adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->minFreqPortB_Hz); @@ -1577,7 +1559,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_RANGE_CHECK(device, gainTableType, ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE, ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE); ADI_NULL_PTR_RETURN(&device->common, lnaConfig); - + if (!lnaConfig->externalLnaPresent) { ADI_ERROR_REPORT(&device->common, @@ -1604,7 +1586,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu ADI_RANGE_CHECK(device, lnaConfig->numberLnaGainSteps, 2, 4); //ADI_RANGE_CHECK(device, lnaConfig->settlingDelay, 0, 0); //ADI_RANGE_CHECK(device, lnaConfig->lnaDigitalGainDelay, 0, 0); - + if(0 != lnaConfig->lnaGainSteps_mdB[0]) { ADI_ERROR_REPORT(&device->common, @@ -1615,7 +1597,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu "lnaConfig->lnaGainSteps_mdB[0] should have the gain step as '0' only"); ADI_ERROR_RETURN(device->common.error.newAction); } - + for (i = 1; i < lnaConfig->numberLnaGainSteps; i++) { if ((lnaConfig->lnaGainSteps_mdB[i] == 0) || ((lnaConfig->lnaGainSteps_mdB[i] % 500) != 0)) @@ -1699,12 +1681,12 @@ int32_t adi_adrv9001_Rx_ExternalLna_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapRxb_FeGainDelayIncr_Set, device, rxbAddr, (lnaConfig->lnaDigitalGainDelay + FEGAIN_INCR_FIXED_VALUE)); ADI_EXPECT(adrv9001_NvsRegmapRxb_FeGainDelayDecr_Set, device, rxbAddr, (lnaConfig->lnaDigitalGainDelay + FEGAIN_DECR_FIXED_VALUE)); ADI_EXPECT(adrv9001_NvsRegmapRx_ExtLnaDigitalGainDelay_Set, device, rxAddr, (lnaConfig->lnaDigitalGainDelay + EXTDIGGAIN_DELAY_FIXED_VALUE)); - + if (ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE == gainTableType) { ADI_EXPECT(adrv9001_NvsRegmapRx_GainCompForExtGain_Set, device, rxAddr, (uint8_t)lnaConfig->externalLnaPresent); } - + ADI_API_RETURN(device); } @@ -1783,4 +1765,111 @@ int32_t adi_adrv9001_Rx_ExternalLna_DigitalGainDelay_Get(adi_adrv9001_Device_t * ADI_EXPECT(adrv9001_NvsRegmapRx_ExtLnaDigitalGainDelay_Get, device, rxAddr, lnaDigitalGainDelay); ADI_API_RETURN(device); +} + +static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Loid_Configure_Validate(adi_adrv9001_Device_t *adrv9001, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) +{ + adi_adrv9001_RadioState_t state = { 0 }; + uint8_t port_index = 0; + uint8_t chan_index = 0; + + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); + + ADI_NULL_PTR_RETURN(&adrv9001->common, loidConfig); + + /* Validate state is STANDBY or CALIBRATED*/ + ADI_EXPECT(adi_adrv9001_Radio_State_Get, adrv9001, &state); + adi_common_port_to_index(ADI_RX, &port_index); + adi_common_channel_to_index(channel, &chan_index); + if ((ADI_ADRV9001_CHANNEL_STANDBY != state.channelStates[port_index][chan_index]) && + (ADI_ADRV9001_CHANNEL_CALIBRATED != state.channelStates[port_index][chan_index])) + { + ADI_ERROR_REPORT(&adrv9001->common, + ADI_COMMON_ERRSRC_API, + ADI_COMMON_ERR_INV_PARAM, + ADI_COMMON_ACT_ERR_CHECK_PARAM, + channel, + "Invalid channel state. Channel must be in CALIBRATED or STANDBY state"); + } + + ADI_API_RETURN(adrv9001); +} + +int32_t adi_adrv9001_Rx_Loid_Configure(adi_adrv9001_Device_t *adrv9001, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) +{ + uint8_t armData[4] = { 0 }; + uint8_t extData[2] = { 0 }; + + ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_Loid_Configure_Validate, adrv9001, channel, loidConfig); + + armData[0] = loidConfig->loidEnable; + armData[1] = loidConfig->loidInterval; + armData[2] = loidConfig->loidThHigh; + armData[3] = loidConfig->loidThLow; + + /* Write LOID config to ARM mailbox */ + ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_SET, &armData[0], sizeof(armData), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); + + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_RX, channel); + extData[1] = OBJID_GS_LOID; + + ADI_EXPECT(adi_adrv9001_arm_Cmd_Write, adrv9001, (uint8_t)ADRV9001_ARM_SET_OPCODE, &extData[0], sizeof(extData)); + + /* Wait for command to finish executing */ + ADRV9001_ARM_CMD_STATUS_WAIT_EXPECT(adrv9001, + (uint8_t)ADRV9001_ARM_SET_OPCODE, + extData[1], + (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_TIMEOUT_US, + (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_INTERVAL_US); + + ADI_API_RETURN(adrv9001); +} + +static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Loid_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) +{ + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); + + ADI_NULL_PTR_RETURN(&adrv9001->common, loidConfig); + + ADI_API_RETURN(adrv9001); +} + +int32_t adi_adrv9001_Rx_Loid_Inspect(adi_adrv9001_Device_t *adrv9001, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) +{ + uint8_t armReadBack[4] = { 0 }; + uint8_t extData[2] = { 0 }; + + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_RX, channel); + extData[1] = OBJID_GS_LOID; + + ADI_EXPECT(adi_adrv9001_arm_Cmd_Write, adrv9001, (uint8_t)ADRV9001_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + + ADRV9001_ARM_CMD_STATUS_WAIT_EXPECT(adrv9001, + (uint8_t)ADRV9001_ARM_GET_OPCODE, + extData[1], + (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_TIMEOUT_US, + (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_INTERVAL_US); + + /* read the ARM memory to get LOID config */ + ADI_EXPECT(adi_adrv9001_arm_Memory_Read, + adrv9001, + ADRV9001_ADDR_ARM_MAILBOX_GET, + &armReadBack[0], + sizeof(armReadBack), + ADRV9001_ARM_MEM_READ_AUTOINCR) + + loidConfig->loidEnable = armReadBack[0]; + loidConfig->loidInterval = (adi_adrv9001_LoidInterval_e) armReadBack[1]; + loidConfig->loidThHigh = armReadBack[2]; + loidConfig->loidThLow = armReadBack[3]; + + ADI_API_RETURN(adrv9001); } \ No newline at end of file diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_spi.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_spi.c index 84e0e3f30084a6..fc8068bce7fe8c 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_spi.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_spi.c @@ -14,9 +14,11 @@ #include "adi_adrv9001_spi.h" #include "adi_common_error.h" +#include "adi_adrv9001_arm.h" #include "adi_adrv9001_error.h" #include "adi_adrv9001_hal.h" +#include "object_ids.h" /*********************************************************************************************************/ int32_t adi_adrv9001_spi_DataPack(adi_adrv9001_Device_t *device, @@ -532,4 +534,96 @@ int32_t adi_adrv9001_spi_Cache_Read(adi_adrv9001_Device_t *device, ADI_ERROR_RETURN(device->common.error.newAction); ADI_API_RETURN(device); +} + +static __maybe_unused int32_t __maybe_unused adi_adrv9001_spi_Master_Configure_Validate(adi_adrv9001_Device_t *adrv9001, + adi_adrv9001_spiMasterConfig_t *spiMasterConfig) +{ + ADI_NULL_PTR_RETURN(&adrv9001->common, spiMasterConfig); + ADI_RANGE_CHECK(adrv9001, spiMasterConfig->numBytes, 1, SPI_MASTER_TOTAL_BYTES_MAX); + ADI_RANGE_CHECK(adrv9001, spiMasterConfig->baudRateDiv, 0, 31); + ADI_RANGE_CHECK(adrv9001, spiMasterConfig->transactionBytes, 1, SPI_MASTER_TOTAL_BYTES_MAX); + + if(spiMasterConfig->csSource == ADI_ADRV9001_SPI_MASTER_CS_SOURCE_GPIO_ANALOG) + { + ADI_RANGE_CHECK(adrv9001, spiMasterConfig->pin, ADI_ADRV9001_GPIO_ANALOG_00, ADI_ADRV9001_GPIO_ANALOG_08); + } + else if(spiMasterConfig->csSource == ADI_ADRV9001_SPI_MASTER_CS_SOURCE_GPIO_DIGITAL) + { + ADI_RANGE_CHECK(adrv9001, spiMasterConfig->pin, ADI_ADRV9001_GPIO_DIGITAL_00, ADI_ADRV9001_GPIO_DIGITAL_08); + } + + ADI_API_RETURN(adrv9001); +} + +int32_t adi_adrv9001_spi_Master_Configure(adi_adrv9001_Device_t *device, + adi_adrv9001_spiMasterConfig_t *spiMasterConfig) +{ + uint8_t armData[48] = { 0 }; + uint8_t extData[5] = { 0 }; + uint32_t offset = 0; + uint8_t cnt = 0; + + ADI_PERFORM_VALIDATION(adi_adrv9001_spi_Master_Configure_Validate, device, spiMasterConfig); + + adrv9001_LoadFourBytes(&offset, armData, sizeof(armData) - sizeof(uint32_t)); + armData[offset++] = spiMasterConfig->numBytes; + armData[offset++] = spiMasterConfig->baudRateDiv; + armData[offset++] = spiMasterConfig->transactionBytes; + armData[offset++] = spiMasterConfig->assertionMode; + armData[offset++] = spiMasterConfig->spiSlaveDevicesConnected; + armData[offset++] = spiMasterConfig->csSource; + armData[offset++] = spiMasterConfig->pin - 1; + armData[offset++] = spiMasterConfig->triggerSource; + adrv9001_LoadFourBytes(&offset, armData, spiMasterConfig->wakeupTimer_us); + + for (cnt = 0; cnt < SPI_MASTER_TOTAL_BYTES_MAX; cnt++) + { + armData[offset++] = spiMasterConfig->spiData[cnt]; + } + + extData[0] = 0; + extData[1] = OBJID_GS_CONFIG; + extData[2] = OBJID_CFG_SPI_MASTER_CONFIG; + + ADI_EXPECT(adi_adrv9001_arm_Config_Write, device, armData, sizeof(armData), extData, sizeof(extData)) + + ADI_API_RETURN(device); +} + +static __maybe_unused int32_t __maybe_unused adi_adrv9001_spi_Master_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, + adi_adrv9001_spiMasterConfig_t *spiMasterConfig) +{ + ADI_NULL_PTR_RETURN(&adrv9001->common, spiMasterConfig); + ADI_API_RETURN(adrv9001); +} + +int32_t adi_adrv9001_spi_Master_Inspect(adi_adrv9001_Device_t *device, + adi_adrv9001_spiMasterConfig_t *spiMasterConfig) +{ + uint8_t armReadBack[44] = { 0 }; + uint8_t channelMask = 0; + uint32_t offset = 0; + uint8_t cnt = 0; + + ADI_PERFORM_VALIDATION(adi_adrv9001_spi_Master_Inspect_Validate, device, spiMasterConfig); + + ADI_EXPECT(adi_adrv9001_arm_Config_Read, device, OBJID_CFG_SPI_MASTER_CONFIG, channelMask, offset, armReadBack, sizeof(armReadBack)) + + spiMasterConfig->numBytes = armReadBack[offset++]; + spiMasterConfig->baudRateDiv = armReadBack[offset++]; + spiMasterConfig->transactionBytes = armReadBack[offset++]; + spiMasterConfig->assertionMode = armReadBack[offset++]; + spiMasterConfig->spiSlaveDevicesConnected = armReadBack[offset++]; + spiMasterConfig->csSource = armReadBack[offset++]; + spiMasterConfig->pin = (armReadBack[offset++] + 1); + spiMasterConfig->triggerSource = armReadBack[offset++]; + adrv9001_ParseFourBytes(&offset, armReadBack, &spiMasterConfig->wakeupTimer_us); + + for (cnt = 0; cnt < SPI_MASTER_TOTAL_BYTES_MAX; cnt++) + { + spiMasterConfig->spiData[cnt] = armReadBack[offset++]; + } + + ADI_API_RETURN(device); } \ No newline at end of file diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_ssi.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_ssi.c index 3de4b03f2fef1d..7ca29599b0a76a 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_ssi.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_ssi.c @@ -194,6 +194,9 @@ static __maybe_unused int32_t adi_adrv9001_Ssi_Tx_CssiClearErrorFlags(adi_adrv90 ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x1); ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearDdrStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearDdrStrobeAlignError_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearDdrStrobeAlignError_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDebugStartRamp_Set, device, baseAddress, 0x1); ADI_API_RETURN(device); } @@ -250,11 +253,17 @@ int32_t adi_adrv9001_Ssi_Tx_TestMode_Configure(adi_adrv9001_Device_t *device, else { ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugMode_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugAfterFifoErrorClear_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugAfterFifoErrorClear_Set, device, baseAddress, 0x1); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugAfterFifoErrorClear_Set, device, baseAddress, 0x0); - ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearStrobeAlignError_Set, device, baseAddress, 0x1); - ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); - ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxFifoClear_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearStrobeAlignError_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearEarlyStrobeDetectedFlag_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearEarlyStrobeDetectedFlag_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearEarlyStrobeDetectedFlag_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxFifoClear_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxFifoClear_Set, device, baseAddress, 0x1); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxFifoClear_Set, device, baseAddress, 0x0); if (ADI_ADRV9001_SSI_TESTMODE_DATA_RAMP_16_BIT == ssiTestModeConfig->testData) { @@ -278,7 +287,9 @@ int32_t adi_adrv9001_Ssi_Tx_TestMode_Configure(adi_adrv9001_Device_t *device, else if (ADI_ADRV9001_SSI_TESTMODE_DATA_PRBS7 == ssiTestModeConfig->testData) { ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugPrbs7Enable_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugPrbs7ErrorClear_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugPrbs7ErrorClear_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugPrbs7ErrorClear_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugPrbs7Restart_Set, device, baseAddress, 0x1); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugStartErrorCheck_Set, device, baseAddress, 0x1); recoveryAction = adi_common_hal_Wait_us(&device->common, 1000); @@ -297,7 +308,9 @@ int32_t adi_adrv9001_Ssi_Tx_TestMode_Configure(adi_adrv9001_Device_t *device, else if (ADI_ADRV9001_SSI_TESTMODE_DATA_PRBS15 == ssiTestModeConfig->testData) { ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugPrbs15Enable_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugAfterFifoErrorClear_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugAfterFifoErrorClear_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugAfterFifoErrorClear_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugPrbs15Restart_Set, device, baseAddress, 0x1); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugStartErrorCheck_Set, device, baseAddress, 0x1); recoveryAction = adi_common_hal_Wait_us(&device->common, 1000); @@ -421,9 +434,12 @@ int32_t adi_adrv9001_Ssi_Tx_TestMode_Status_Inspect(adi_adrv9001_Device_t *devic ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDebugStartRamp_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDebugQSel_Set, device, baseAddress, 0); // 0: I_data; 1: Q_data ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDebugNibbleSel_Set, device, baseAddress, nibSel); - ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); - ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x1); - ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearDdrStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearDdrStrobeAlignError_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearDdrStrobeAlignError_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDebugStartCapture_Set, device, baseAddress, 0x1); /* Wait for capture to complete */ for (eventCheck = 0; eventCheck <= numEventChecks; eventCheck++) @@ -473,9 +489,12 @@ int32_t adi_adrv9001_Ssi_Tx_TestMode_Status_Inspect(adi_adrv9001_Device_t *devic ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDebugStartRamp_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDebugQSel_Set, device, baseAddress, 1); // 0: I_data; 1: Q_data ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDebugNibbleSel_Set, device, baseAddress, nibSel); - ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x1); - ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearDdrStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearDdrStrobeAlignError_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxClearDdrStrobeAlignError_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDebugStartCapture_Set, device, baseAddress, 0x1); /* Wait for capture to complete */ for (eventCheck = 0; eventCheck <= numEventChecks; eventCheck++) @@ -583,7 +602,12 @@ int32_t adi_adrv9001_Ssi_Tx_TestMode_Status_Inspect(adi_adrv9001_Device_t *devic ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugMode_Set, device, baseAddress, 0x1); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugStartRamp_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugQSel_Set, device, baseAddress, i); // 0: I_data; 1: Q_data - ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearStrobeAlignError_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearStrobeAlignError_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearStrobeAlignError_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearEarlyStrobeDetectedFlag_Set, device, baseAddress, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearEarlyStrobeDetectedFlag_Set, device, baseAddress, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxClearEarlyStrobeDetectedFlag_Set, device, baseAddress, 0x0); ADI_EXPECT(adrv9001_NvsRegmapTx_LssiTxDebugStartCapture_Set, device, baseAddress, 0x1); /* Wait for capture to complete */ for (eventCheck = 0; eventCheck <= numEventChecks; eventCheck++) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c index a4b5671ad3e27f..a250a0e0369bef 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c @@ -134,13 +134,15 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_AttenuationMode_Set adi_adrv9001_TxAttenuationControlMode_e mode) { adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; + adi_adrv9001_TxAttenuationControlMode_e txModeRead = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_BYPASS; ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); switch (mode) { case ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_BYPASS: /* Falls through */ case ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI: /* Falls through */ - case ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_PIN: + case ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_PIN: /* Falls through */ + case ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC: break; default: ADI_ERROR_REPORT(&device->common, @@ -166,6 +168,18 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_AttenuationMode_Set currentState.channelStates[port_index][chan_index], "Error while attempting to set attenuation mode. Channel must be in STANDBY or CALIBRATED."); } + + /* Retrieve attenuation mode */ + ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Get, device, channel, &txModeRead); + if (txModeRead == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) + { + ADI_ERROR_REPORT(&device->common, + ADI_COMMON_ERRSRC_API, + ADI_COMMON_ERR_API_FAIL, + ADI_COMMON_ACT_ERR_CHECK_PARAM, + txModeRead, + "Invalid TxAttenuation Control Mode. Cannot control when mode CLGC is enabled"); + } ADI_API_RETURN(device); } @@ -180,8 +194,15 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Set(adi_adrv9001_Device_t *device, txChannelBaseAddr = Tx_Addr_Get(channel); - ADI_EXPECT(adrv9001_NvsRegmapTx_TxAttenMode_Set, device, txChannelBaseAddr, (uint8_t)mode); + device->devStateInfo.txAttenMode[channel - 1] = mode; + + if (mode == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) + { + mode = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI; + } + ADI_EXPECT(adrv9001_NvsRegmapTx_TxAttenMode_Set, device, txChannelBaseAddr, (uint8_t)mode); + ADI_API_RETURN(device) } @@ -199,15 +220,18 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Get(adi_adrv9001_Device_t *device, adi_common_ChannelNumber_e channel, adi_adrv9001_TxAttenuationControlMode_e *mode) { - uint8_t regData = 0; - adrv9001_BfNvsRegmapTx_e txChannelBaseAddr = ADRV9001_BF_TX1_CORE; - - ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_AttenuationMode_Get_Validate, device, channel, mode); - - txChannelBaseAddr = Tx_Addr_Get(channel); - - ADI_EXPECT(adrv9001_NvsRegmapTx_TxAttenMode_Get, device, txChannelBaseAddr, ®Data); - *mode = (adi_adrv9001_TxAttenuationControlMode_e)regData; + ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_AttenuationMode_Get_Validate, device, channel, mode); + + adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_TX, channel, &state); + if (state == ADI_ADRV9001_CHANNEL_PRIMED) + { + *mode = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI; + } + else + { + *mode = (adi_adrv9001_TxAttenuationControlMode_e)device->devStateInfo.txAttenMode[channel - 1]; + } ADI_API_RETURN(device); } @@ -321,6 +345,8 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_Attenuation_Set_Val uint16_t attenuation_mdB) { uint8_t chan_index = 0; + adi_adrv9001_TxAttenuationControlMode_e txModeRead = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_BYPASS; + ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); adi_common_channel_to_index(channel, &chan_index); @@ -355,6 +381,18 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_Attenuation_Set_Val } } + /* Retrieve attenuation mode */ + ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Get, device, channel, &txModeRead); + if (txModeRead == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) + { + ADI_ERROR_REPORT(&device->common, + ADI_COMMON_ERRSRC_API, + ADI_COMMON_ERR_API_FAIL, + ADI_COMMON_ACT_ERR_CHECK_PARAM, + txModeRead, + "Invalid TxAttenuation Control Mode. Cannot control when mode CLGC is enabled"); + } + ADI_API_RETURN(device); } @@ -510,9 +548,22 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_OutputPowerBoost_Se adi_common_ChannelNumber_e channel) { adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; + adi_adrv9001_TxAttenuationControlMode_e txModeRead = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_BYPASS; ADI_EXPECT(adi_adrv9001_Channel_Validate, device, channel); + /* Retrieve attenuation mode */ + ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Get, device, channel, &txModeRead); + if (txModeRead == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) + { + ADI_ERROR_REPORT(&device->common, + ADI_COMMON_ERRSRC_API, + ADI_COMMON_ERR_API_FAIL, + ADI_COMMON_ACT_ERR_CHECK_PARAM, + txModeRead, + "Invalid TxAttenuation Control Mode. Cannot control when mode CLGC is enabled"); + } + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_TX, channel, &state); if (state != ADI_ADRV9001_CHANNEL_STANDBY) { @@ -691,6 +742,10 @@ int32_t adi_adrv9001_Tx_AttenuationTable_Write(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapTxb_TxAlgArmOrGroup11ClkSel_Set, device, ADRV9001_BF_TXB1_CORE, false); ADI_EXPECT(adrv9001_NvsRegmapTxb_TxAlgArmOrGroup11ClkSel_Set, device, ADRV9001_BF_TXB2_CORE, false); + /* Initialize TX Attenuation Mode */ + device->devStateInfo.txAttenMode[0] = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI; + device->devStateInfo.txAttenMode[1] = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI; + ADI_API_RETURN(device); } @@ -1770,6 +1825,8 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_Attenuation_PinCont adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; + adi_adrv9001_TxAttenuationControlMode_e txModeRead = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_BYPASS; + /* Check device pointer and gain pointer are not null */ ADI_NULL_DEVICE_PTR_RETURN(device); ADI_NULL_PTR_RETURN(&device->common, config); @@ -1801,6 +1858,18 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_Attenuation_PinCont "Tx attenuation pin control configuration is not supported in TX_DIRECT_FM_FSK mode"); } + /* Retrieve attenuation mode */ + ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Get, device, channel, &txModeRead); + if (txModeRead == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) + { + ADI_ERROR_REPORT(&device->common, + ADI_COMMON_ERRSRC_API, + ADI_COMMON_ERR_API_FAIL, + ADI_COMMON_ACT_ERR_CHECK_PARAM, + txModeRead, + "Invalid TxAttenuation Control Mode. Cannot control when mode CLGC is enabled"); + } + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_TX, channel, &state); if (state != ADI_ADRV9001_CHANNEL_CALIBRATED) { From da2249e17daeab07a4bf3e99580b4a73fb655f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 23 Dec 2021 09:26:52 +0100 Subject: [PATCH 072/407] firmware: Update firmware for adrv9002 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Arm firmware updated to version 0.19.4.5. Update default profiles. Update stream binary for the default profiles. Signed-off-by: Nuno Sá --- firmware/Navassa_CMOS_profile.json | 16 ++++++++-------- firmware/Navassa_EvaluationFw.bin | Bin 294912 -> 294912 bytes firmware/Navassa_LVDS_profile.json | 16 ++++++++-------- firmware/Navassa_Stream.bin | Bin 32768 -> 32768 bytes 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/firmware/Navassa_CMOS_profile.json b/firmware/Navassa_CMOS_profile.json index 74d70c65ed43da..a52377b6918d60 100644 --- a/firmware/Navassa_CMOS_profile.json +++ b/firmware/Navassa_CMOS_profile.json @@ -41,7 +41,7 @@ "rxOutputRate_Hz": 1920000, "rxInterfaceSampleRate_Hz": 1920000, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -157,7 +157,7 @@ "rxOutputRate_Hz": 1920000, "rxInterfaceSampleRate_Hz": 1920000, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -273,7 +273,7 @@ "rxOutputRate_Hz": 0, "rxInterfaceSampleRate_Hz": 0, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -389,7 +389,7 @@ "rxOutputRate_Hz": 0, "rxInterfaceSampleRate_Hz": 0, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -505,7 +505,7 @@ "rxOutputRate_Hz": 1920000, "rxInterfaceSampleRate_Hz": 1920000, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -621,7 +621,7 @@ "rxOutputRate_Hz": 1920000, "rxInterfaceSampleRate_Hz": 1920000, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -737,7 +737,7 @@ "rxOutputRate_Hz": 0, "rxInterfaceSampleRate_Hz": 0, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -853,7 +853,7 @@ "rxOutputRate_Hz": 0, "rxInterfaceSampleRate_Hz": 0, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, diff --git a/firmware/Navassa_EvaluationFw.bin b/firmware/Navassa_EvaluationFw.bin index 37170c96bf4a515aeadb6f7bfa0faa5e79c19651..730e3be79b2cb55db88669a7f941170e713fd2de 100644 GIT binary patch delta 116060 zcmbTe33yXg-amfM&CSv@ZBtsH8*q~@qzlj%(6Xp$Q*KLHS`ZZlG%RXbP{Sqx!L)2v zmZ5M(3%H=;IJk_KYG+!Y78DiH85Z2Ze=hPUYyI*`(Gyir@P*y`lZZs2(S8@3&*G3Oz8U;RrG8+r8|bx zU&{P%Z9aKBrQ6|l-cH?gHv)U$o`ZW4?hkOR;yeSPk#U6H5lv_e{Qs%3FBbngp#RR7 z?)aYv(z9Ger>s!Xo;H^6?rZqTw<&!AZskK9y}q2IU!lO0=PA8@7f0WR+YNWuY>uvm zKM;Ns%Ki)G);T#^vx1}QUXG4}dkAhT+}=75zKhjFT#QJKTSl|NkBT?f(Cy@9R7> zvd{18_lM&qJog--FT(u+?p3%y!5xHaf@^{M?*T-Z2rWGSpIgAvm}6yAdkFpO4;)Qk z5tg_ljtV?agij-hptk1HXO?EFa#Y{OQRy~5vBX%w3rea=phS0unu$D&b|~HnTddXy zn<5C#k_gHX)tL^ZJ+fw&v!p}$bOI;Ga7o3S!lyV(BE?woXabc_NiXo3ahz;a9!lXy zT)vRkI^uF~d55xAy1^6Aw!%YRlk+NYeS9`s`(rT0cp9&eHZ& zk@i%F@{Tk|{TR>5;}q$iTj^mdJt#dTnFI7=>*4YDz z>Q0fXQ_c-;RL$kWb^behB9`0z5B#EZFZqpXVIJ(|vqgrsk>tLOL4|K}N{sxTwWCV#V%lY6O( zQ|FzvUz!Y?tf(}zCzcz7shw?_`Z>Mk%rohLx zHPX%!qUkKA4azISo0aq0T>)7x9k{Xel3b%pWEs_Kt4V1%E{)es&nj3<%v4?z>QH1u zwn$BU=b4q%`H=4A&PjZ}I8O97(gswvD&I*}x}lK;iz$lViQ)&O3%W!)Ub?Ouu71B4 zYb%)|hPlnXm=xhngM^T8eUDOQjVCfCq|PknF1F#|%tFnS6e{SP9Ba0aL&=B!B{z}I z_Em0Ov^YfEj|tQ?#EYZFOz~)A$k*A6vqgz~y=T)eE#J{2|I#u$d6vag9*&leOKlMY z%Wpw@8d1~v`KlqJTlY$5i8fMXEoO=e+MA8BS|&(Jy1?4aZwWQ3JD<=Va#SZ2c7C&z z$Sr;SbZ*8LJxeSL9a5^^9I@9ECO1>@wC{?C;< zlH1au%teijoYrlMTaxHxhq6Pdi0n{GlXIIkxH^>LxwLZwU(@iSBTFP$@^?coI;tv9 zEEcYC+{uNGO3ro?1I$IO1k^I3*88Ys_)RT}TE9oF*M6yW;FnrB@+G@OUW^h==an2g zfX7}U99U2<-mO^3Qmy7pL}x8WhVOK2sah{pMw+;afV3@gWctg24#g2!p`;PEIar($ zPCjuMBiCc(Nx4lbHgc&Wa-jR?kzR8AI?@!Bibp9MN*U+;IzKkjZ5V0RFC(@5$4CM1 zwsa`xD(jVZG#$#9NwrFo=4MBeW32rzb|NVAn-}g@Mi64rwh^~N_TtNCEPvPj#Ze49|K+^=2bxb9eK_x*1x`J07o zw*21TihKOTH!Egdd2v^q)k~S%|QI6cMn*(`p(xk-k&g zfGfq0%}sn=gJ2ABS8EdhGUj(EM>149+p9X1GlRG~zJ7)xI6IV=2f{Z3$Z6C&S1+zm zOhS^~1;E#fC3#0fUC#l}uU$M~2u+o&du+U)yDDuq4jsPn&JJbcD{z0_uJD4UPE+r- z9@9=b`@6#hi|=NrJir?HO!~x_YbXZH-+*CvjPJFID%lXSio85Is8lUYFV$1&0)6zv^_;v>MS^PU` zaojMsf_u9ydzWI)?NDm7w>FRrlBSYXs%Z``Th~U@xX$APw7bag?MedC?~Hg#xBDJ! z+Qc{_Kd0I~6lw1kU(& zU46t}(z#wWrTCVz({4q#f0vR@5?bOr_57sHD=Y6jyi=*x{&_NIiEkqUTf|D%(O}ii zzOGm|{zedZ@*;Hfe1AtzvX1zZT|}>~KdQ(t>AG?`Z9Ta@aVaP8@(q-9r|9dcV@FZm zsd#||wB5S;(&9-Dx30cIiLh>NNh)o>%%?tA6mgoKd#Xrty8W^y_4Ohir0GjV^wjhl z>YLE9ac3#%q-FpUeI3q9tZazkI-k((XeT2#d+LqF0XUFW4ScMyxb#?6A@0|) z1=M_#SAL!d1?bG#bSsWj{gh(>4)t?P;e3+8%bx{#FE5`8((u0wI>#y9JSgwxhTu0B zSx+GHOdZNp1C`Ieo7+S%@#2YspS$+0wz%zf#axl;oSDLBUB8fv(J(yp!l2|a4ImjB zA`M>7@^ z5HC+i#fdYxQQ%$_OeFp?5zecKSOBR8ft%Vvgmbt*BQAH9tIS#qGy&AY8SUl^c|la#_IPJ=r)BGdZCr z@;)?T3^&4vfoW*OibfUv zH^QNjA-%+;Mz^F_p07@0V|&)my63|+2M3b-YmPz9>8P0yt_k)KHE6izKYMZ)sMFYh z+ylZ@b>XVoz$Gl&I%#)erh8I=rc$#>yws?bZwoMvFm$8)&AlKkj%i7kulfr`XCy-H zLSp(tAwu0k{q^n#zfcUMW+5?uq44m>**lb{5&?~gQ8|BGas-1%`pzO=mCav0<22xE zsAP`U=<-w5-bJY@?}=3EEx&eR`TNx*RpqYMcXDKA3eBok&fWawSC82b+xIDyaF#?* zR9Yoi6Ro_w=Q)Lt6pNu9zTk3D(@v|-=CXSmqbz(I%WJkTO8G})T;_Kd_9+~pmeC%P zrcJL5Pij_wZCyJx)mRNSOtimN!HS1c+?N~mnO80ptUYc$Qln2N=#s6(`2VMpzQ2+S zl`c0LGOv8)LY-g@F>C4x4xv`w){79XAPaBC{%m9GG#7EeSf1 zYea7EVX*hFJuG}C9QO2R%$zAs(8)`beOM!v1>7o9Mj&OO0$LyK$l3waT2rJ362GK9 zww2WCYKKAMae_TvL6h zdd+g0I${2r`TqHb=6`fqXVzRl^}wNp`O6P2@GtN$%y%wxawC>iztKk0X*wO=SiN$2 z{`^(*ug-6rzbIv6k@h@p>YXE8+z6D&pc(I9Jh?z_wYRBg=G=dU2|A2c2C~jsxd$sh z(M9AKohm0D2!s;o~iI%xkP>SY4GJG2p1syyc>~1 zM6A?kR$qO^sRI>fH1k~*RDJc&h;8a_y_9Ed{f-SHrTBGp!I)~DygJ+k2*umc_)@;h z0wR^jCI!tqS;s^kgz)nSk3rao@GDDMyAz2{o`W9HI%-WNZk;>}U;1vIF3z|?8hA-DoaM6vF}!z#7&i| z&f}`Nj`-Ahw)EnWYX_~^RLMdQuf4NB^yb>9S5#NpY~Fp#?T$N3YQ)3}s%3qjjr;utWR?fW8TS?@q2U84rJFHsU&{E$5 z(z%K9*B9HiICd_+kg^AKeuFT{=1iC==+T41{Xl1S4bI5xbc+nK=t!^T@fUF_k z-$SjJcxyBg7~Bo{J`2ZHCXE-1FMM=SWujiv#^J0VlO8k;b1y25hOB_eNsDBG>-F_0 zf@o}Id>o_uzR(f66YjYPLWjfkz!^bW88Q#Fm0neG3FoIw{ikb$Mdu;ee4F4>Sz9>1E|p%FDF!;UFg((f$cFD5DpM@OL*zqzj0A3HKFTb<@8w zukRGKiTOe|`@f=mi~lc?#{5Az`ka-8zHY8=x&r?*=SIgO)(zv#twgaPH5-n6O1%)`Rrze%5^XQpEywFw(yV$$nPDJzPF@|i}FWyeaWeJC8nzDBfA!H z#H5o|{>baKE;|pF90tyqHlB_EBkN6Nq;;S z@r&IoHK&_}GrMU$WWlCeW2Xba`*U&i2uN<7{E}b#F0(kz9x4^J^1P5%P6$!42xv?r zf39fdSj5V3-!(X!()6sX=uv)RW?F^lsT%nMN{cQR!Nc);6+C3Wr`8<+MqfdHerna3`i5RlZH;~P8U~{Rm>xn z@$IF;vgyWvTFxylHIX5DxuIKHk-dOh-z}ZXewd3|ES2VD(AT6#ax(S*4l=}{mk0Mq zFXcS$h7?mEDJr4y5`h1FA_SBBPWBjt+c2Qjvk%--0lygW@M+&X;l%=IWSkHS8&d5+ z1_vP6I7ej36CP2s90++6Z3I)#X3Kc3ux(B*} z(C1}EN;aY4ou3JjNW4PpXF!s^M)6E84CiD!*a?}5G+%$-=RKeF=dqmIapM8%d!GY` zVL1p@n=&DWm`u)bPA2WffN87Z=EABI-;P_GG|$pq_YeJ3;SVvK#EZ>kWcN%ZEw^df z9ZDK7%k80?p*fSwH#Dq=^!!ediETBVo2jMctXv#*C*>-&}Z=n4whdlU0Q)lG)~z7O$>6~z6HIkSfqTbe>bS~Y;k-z=J3aO=Wk<0 z(@>NO^chljx0tmUWpZ~lvhw!?o-TzD$#@Q2QeJm9iE})-jdpIOsn^`9gWa6*HofhN z))r^K%dv3V!k-40+-2ADjH!!ruoAaL_vK1A<(l1(m&FD&H|pl)9%MsNF`~UZQvT|2 zIE4LI%4@_e;t5d?3afDS1L)RLq3)WfDIYq<)mCW0*5x`SafVn5ARQT6j4iNW0vwa5F!E_ONXtcF zO`d`~@D1W{?QjrEhhYR$9@_DXz%liU?n-UYoy`U_GcC1+@?@xD1Dp4RXneltTadO+2Yc-3@_unG%M4S zQ5NUghKrr%{Th_)>qQ0#=3at$?(56kqGyZTYDAv~4}u~j4n=qri3%6dqlgAYG~p7e z)6|SI0`*S0N(FRV@rdcY*cgCzg(vF z{t~;|I$)qvZY6C@A`dOH@PP(@STRYyYB&HT&p^6 zr;ym?TSLBKpsZN#pD+|6{~`SUR``E>_}><$s)%rx7Z5nkXtA_K46zcugQgOBDA{1$ zYtw^ca5jA+ogSU3e#A?~Hi?cIvS^e-9I;0HOr8c z$TA;qGuZ9noI%LpmG^#9#hRRVd0(BZcQ{K}4L!JNCG;{e%Lddiglm*|d2!K2X~`I2 z*sM^RK)Kp!zwC%rz#lz-DjV^hd?GPHSeB)SUuJ_v0@^T(l8 z)P&=$p=!k6yTTXg(Sp%B^rFO%y>q~V?!xaAB26+Wq-MvINcr(@Y021x=xN=zf1i+@ zDid3zyrEm#HFh?)+b?}Twwl`*kRHCt9I-5*^BRX3Kr`*RDLwXg{?3cWAtB$;&_(#Y zzN6A-Hx0R?8OPl~$mDpq1UN=iGJey@VIOKwTW7yc1dbAs5t%D+nvG2cktDLg#fnK{ zukUiJGc5P4g+RSF5pFV^RCx2gNwQ^^vQA4Z9ORmp5Ecl+9!n*$+~*;g^V(x>Bn(o& zZZzkKM!_H-^~c;GgSpo^^Ei=1d_sU}0AH3&1-DU$G{3+^3#1JN!`)5(U&}-W1TpHm zdL6Fu21bWjM2pu6_VoMVkWJnU|3R*k#H%{VKusqxMuWdGnj+-S{Aw@F)U_E+hIVk$ zNV9;xIqo-t3Q&1fnd)!~lkP^yEr*<~GLwv?M|j1m&#gWwbKKoAb9=tJ%+n7qYpA&@ z=IUB$=eTqlFa2fQu;QSmLP>8h*3-REGo(Tfgqa-b9_!2#xq5^Ax}V!ap3-+}RrwgJ z0g|UOMGKRZzVdyg|Jf}ijZaFf{}9qF@mbtEEGJY=)sK=)wvZd8Y2yde71I6V(`kjY zb^PjrAwg>1uEYz_KfomlBrVgSb1{8vhjLU6H}Gd){hC3J2*#Tn=$Z>k6DK4Ms7HZ% z6zKB}^1lO;V?utx?|L#F`bwjnq*)x)MY=4S<*V~o=Q`B#gGygc_}@{{qFYybkXlq8 zoy#DnhNM#y@~8bdWWoR_WM6g%tv&WrG^N$lBsd6)w1#rM)ROJdyTH3IYMA??gIJ6r z*KUx%?ooRU@&mmlhu%enhFK&v16=t=X~x8X39t3;cbFaYF(X>o+sj&_CWBnvD?L7O z(42xr#&ri;j4pztbs@7OZcXgE#FnSo(PJd|PQELi4sh{ZMiK?!ViB*lQV2Tx%HJ7o zjMaSLm(b$g;SSWs@%dKz_r!EJLsn`roo(w zJ&ptqfeFl!Apx( zf9JSkO~mT<)q{!)Z8xuOcMJ?@N2>#Lw8=4t5cv_eGT%{XXHZhEA%qQvc3Jojre!!_ zTccKYR%^MD>m0X1oLIbpbXv8#Vv>PQjm^cr#so#{Y$+Pi{%DG?Q8ntuX_E265A|S{ zK5Ik?FLIBPAL~xiAB|U(AMFro6(;5VXisW@AnTnUtw~)!8vPMx-H(doM`IO}c;%u{ z!;eSx(cEG)^Xf{ zkaXnM6!*FiGn|r3V#MW40k{j|v+DYWzhCC)UoY$EfCJ+y=~7}EU$x#|xRjuQKeng1YCn|b@>>4c=I*8*+ zqd}e&dME{Y3(MDE5h0IPXI2fwaXXn%lgO$_l5X_2Abj*EnypIL!)T$a zU6pgao#u@6^rt7&bdqszwqGM3)e2|t^KbTNiwWV;s$RX?$Q>|1^~vREJ^ZUOhVlf4 zGKgp~lq2@8MrQdE<1d&`U*|Aaro&p+`)G>X$XPzWuqZ{9^U)WHVF|G`#_CE{fWOl~ z<;(_)cn)EP3K&jjR8Vaf^sxyl=`*V-^5|bc+yKQx4j~1sb0)5sLM#bwoQ24ntE=VO zY61|vXb#*~xP8%Lu0w%(eEC@isMFVaD`7GeC7)E-|BH&Wt1w5Ck_@rpC(`l4{Z)~@ z?i4y|<5w#0A%J9qJP!mwSctuWaY2k^g39d>9PCnN>A70yRQ+n1D;nN@xe>?;f*1{Y zdB~sAwhyum>X!B0n6&XmOyG^34spb&*xXQZ5tS z09@sFn)fN|hLbD?@m~fs>O-A6piULbT_OX%TjdkgG)vbu)U0g>DFrJxL7-WNwqa&S z42DOGyrkZh=jgVcaBHnyZ&iPOnM?gEoVp&POCfd479+Q^$M<3H2aRkSUIIO4)fE(r zH}=!w1jyX8(Dj6d%JIeA^{?+%bv~iL)WX-FSEd?ki-voMiPiaicOEv9$lH|rt`J?6 zhsYb0p%}6}7*-r?;oB%UJvSAe1PwY5+;;omhRQWIeK8=U`i?|u8RlV4&O(!OJWu0( zFk&IE$}yK%26zru=7$>})y*2$qwzZw*5Hdy)*eT4tEee+*4ve;Y$4prBD7M#S}~GL zRa<`50klFh2YB+`q6(u0Q}jzidEtgkOIbsFe?tc=IUrazoVjQy-qSa;$9|dF;PA{6 zelxQd!}T?Utpu;IBkT5+zGW5r^exyxEwwOS$E`pC{q57RoqAvo+tqZMwXuQio4Or4 z`^%mg#A=+{1K0*6FwIP9Lro*iw2IN}Y!`w? z$Vja!wZ$fsUpwb4vDKMRB;Ia&FCm(p^uqbLf(|pX^N{_uy~K7R5$AhpnT;!EvOTh! zrgC6{NFC56I)dJ)`?QxCTtJqw8TzgVq{qb+H<8Oh82?pa4Bod2Q|U4i=KBEqpBt(P z6EsUg>ruT_36Bp4AX8-fc3fEvah|!VPGCZN(&gf{ULrSyQ;Gb%Las-zAo9~_y-uOw zR?Q(c9GYqtSuX@)7XCg+4T-!-c~0Sl3E^ae+#ZA)M_vW-G0z~_6KBGh0MzO(T#^W8 zw;cYOn>ytB3+ES9@b|eaw>|*rzGJ1$SH9Xga3Zo@{ zp3Ch@x$RiuuXC|#*j#Q4rxJMt=0YB2D{`V&i=ml7Zy4myd)dwo?w{MMy?t|g5$BuD ztw7-+g&?v)DU?Q+#<|~omxR|~_q*mQY?G6%8B^N{iG8QyHLJ16S<(l=Dl!Uf6>L*s zFwh6%O4IsM&Mk#11mY$O&dr&yz-hz}+}14(%oLQEVs2RC=+4uZ$(xd>d6fhG7%9NS z?ah$6#w~7FbOHmZ5nbCAJv5dFEYHC=x^zVeSSemdU6WHlHzYOx=-onOS!o4HV1(l9 zXk!GpGMKHNBJ#g}PF+Jr;@WHDJap}LCBj&|7MlLJo#6##kfIJ@1}V}(b7K%jlh@6S zjQ0@ejrg4emb(9zj_$-JJN2uN(;D=dNd_yb$k07IMvwKKuNF}f|q36v@{In5W+ePhAFLQ zYbFmVbh2=b^WGLJJclL5BzFE2wn!1e-QgaRVDi9vY6$5YtYWMCdv0s%rK>w|gEZK8 zfx2RG+~gliLHZGWl>AvsFRXykbUN3$S@meyS4%*o-OQ!Y?4fN-L9hwAG&_<3C7ZMS zUK_yCvcripZ1*G>)9Oqb296dio^q#cZx{kiv&{guT)x= zrnVnMAJWpY;cjIh1(8j!pPhgDGPjAqoQm7jcS%PDm`pmB@UM--1Xgt;Y-Bw!oLyKt zAV9C;YAhTYpuJr2#L~sK&Ba`&O2z(SoVIFTkA4a_#%`_HU<+rOj7tKm( zt8vjxO*>u9Ab#~~3Y`D@YML=L{jeLG9MP^h03DN}c~t?;chS%O-}RTvRHyT6f1Oh zX7NQKkl4H?7Ir-OrG|B=%CX@W6>rWYU~{7yF*bT%{G867-r^0D9$x!e%_T`e`mCstH(E@`=iDKBHyVa zjKh1W$^urYCA8A9ayq+joER6-DLCCrHJv(Dxvft4B5{&!e^q92LW`~sL)K6b=_(8D ze2=O;+AQsyQ`Wq$iyWv*E~~!HmDl+N5w2XEkE!)da$f%=HJV*#e@ zZy3q+@4PGim;9@(rqZ}+)Db^jD9^Mnc8zwv>RRf&;%ao><|tU(aL}vOo`vYkEx+L> zaz0oLgX|3M*XqxXb~U<|LIz=wUqDW}!a@r{s$XqAf+?4R5n=;mid41)?2`ZX;xlVP zCMsqO69Wo_!jV2Hu*G#u%bjKCu@5=3Wz>cGf6}+*i(+^8#N0R$5p$y*_GNn&y=;8@ z?g}-HcpcOTm{WO*^x%wnWAB2fgbA=rq7ecty~iXLKt(aNhbbSmaw&XEzaWdHv|hSq z)ylU>-80&_hLCh@=;J`O5!Xtx4c)Xnw2s>N+y21Qm_oh1+o_NT{`lq z8M-riG?ABGJqIhjiJzJ;p2(F1rLx&W zX^m7ldpJiHOS@)gO`mUWO8UE(a5=qiyY6;T)lTJ&w|}}PhPpTUsdwrP$_rvX>_C|H z64M&cxA2e?Zs(hL#0j6_1!ls-#H&W+S2vv%g1%S$yoveVu;!YD4jig(`aAqR$YK8J za1IOYLyiajHsmn>!*GsgGJ?ND)@k@|WHG-boW(*lhghRe9%2n_KE$eRIK3s+ z6Hb#1V8S)v*|t98eUPTz-Q$b$KbpdiymWy{oR|&jmZ4l0In89?zy;%Bt(rY|?h(^e zTP$96O%yn=pj0qIN(%S`xWUVivpHp+Umdc0tesD|HcnKhTu1&i+;HFjJu z_pmP24-A!-l;YJv+YSjr5|Kv*+gtk5*72;Fx-hbIpH*}6Gn5L;sBfu`B0BkabFJigCaeC z-%z)=3LUS;Bw9KY*Aoz4I&+<})9K7z3VvRX!RxCPvY(_Kdh9)?9fRbP7k~$bD18ML zIus?zR9w3>=WQ;BwkMn(;bq_ff(U(&Z>wT78xd|tc$31=FKesE=T`F3+X+3DZ&y&> zf@4qkN;xfu}aS}+NXur$BF(S_YL5Wu(|-y$i`o=C??Q|!s^$%?L%kJtk?npkf4 z6t}QW!Q6%IWx*ie6X|RWZlnQp=lqkKh0-krppZ zrKQr2g*Vfq(nkyP+((koSj7Y6C6aKEvqZP6PCN0`>`W=eku*#?)yT8GRUr3+cr3#E zry*u~s*&yYvEFYr=4c(Lw3L6a)BWjGCO+c3Oll*9^o!b0qJF_v=)*u08Bjhs*vO9U zV{rQhXa_{gNQ(_N-oHkRz;Pu%>>pB=ts(Luy#@vyPs<97;_!?%oY%SY|MWNECUZ&y#{XY&tv{mVA(o0WV>>8E%WbG z^4GEdMwGNy5qXMY2`fZ?9q@S|)X#eacX-6G060^oTS-09rO$)Zn)H8#`pwH9OH;qb6!__|xL3s_+NK&#^drI+80qRS| z7W5ryg=&1mOf0qlA|Q{=zzOy%=xb>03l|{#TI(*PTd})A-^Ps~v;|F!?zs$camcqdbf5ppE*4rYO?eO&djOxwiZS&HfNklZ zXm3gCsYcgira+~s<8jJMkssNg|4t$^JZ5yq)eX3zgV~E5!y$$f8E#}0BQbA;Y+RmF zer?V2-v_9J$#a!8<#K48FR`>UA_6Q-(+6%#vX&i}Y>s_A8jX;?cUWfa zDqF93pm9K*#1m$fyyI{|lL|L>AZGJ&M54&jHU-R}1zIl^ScxhAAA~R~fG{3c!DtY+ zcq`yP3AY(elR!jiNu|I|jgWpt_{4tKP4S0`;mgj)LvcJ9lRevBjl5N7-tspec#i^ z!){E3WZ$3?(vnmHHBX+1PNw{WEh)1F+ODYVc;jYtmQd4doXFLO31NzDBlN#2ELX~G zb>{|+rfaR5&xCkFx>!}1Jo2KmwGmrAJzf=Ni3^&d#6(z~ve#@kFV0LedfV@3w#{R# zbG>;Wn{-${W{p<&El7Wa_p;?&u{cXzpe6Ep>Gz8>-ES#)iz`0{=HYP+ib0)u;Z;&& zRUbfz&t)rX3a=S~G(JM%Mp3Npy|{Uy8bZ!QsgUasZvZrg3ZvLi65%odYV9)>p&F++ zkrx@4qcVN;5G@in?n9 zmUw-)SybazM0i=M0jV32x+nS#DY08ieyDPF_|R6MECM;ic{8LbYr_)Tn6 zwqR2XraQ1H_p~rhf>|mub4j+`w>A+;^~ku0gl>>YxUKW0NsnaGko3qS(}eRg)|CrK z-eqpOaOBo<0heJ3>O2hh5S-NhNRGri6X-5!h%-_BHIDWIs3!6p#AYe^-fvuZ%Obty95V1Ggk#3yvLI)>VqVR#>XXtxoN;b< zf9x^T#(O8^KdQXsnyDFpqhJx^QSTJ6O*P7!QIY{HW-+tC)rW)FV!q@G`CR^7to$L^ zLu|*;*Tb=8f628A?eJJIiiH%K8IhWc6P+Bk_UTXvUm-1DI;@yk+l)jzY*bmwH{sqj zCWCi@s}^HUMD8%;vd}l-77Z8~+n#{$avLE%gNPU!B%NO>!~}e&+Zgb{6#$j)lp>ZT z53Gmf%?ogUhua5t4(=Ig+_E8R$L+w|(wt=`Zs;ND@nr(tA-%Bd7M>v?>C0uMhBCYh zi30cB>&xwta+jy+hxF7y%+%`}*(2S%Jb_-3RxMvi=SV*+9~`$Ks0IT53SzRSl_R;# z81lF@c*T&Ch5+AHO*ug;hx~k(0;4!C6R%w>Da?hb{9=H={`^uEa%Dg9E(se2Gecqu z;)^}RVA2v6E0rEwkvyWfTP25J@>~?Q)@$`oE9Hw}lp+^&o5Cp*!>pP20u%gPkltT0 zYE%OBj}+9{ZP&)VH4f$`y}r~SG2MLeX{9X}Vr;-k00yu?eWN)hnO2rZG7*Lqj_Gb6 zTRGXr@NzN0#z|}_1Huf)jmZE;fTJ)6?)!>~-}eCwV1H};=I zPI+`fx_t_+^;nWvSvd8EDt^F0E(`3zDGCW_aZXE-%1bjqgi5bJI?Qd&UT8a;V8>Rg z<%EE`Yb*(wIVUk?u2AIwAWpn{?XeXD+V~t|I<|tD3^Q~QC9i`~J>azb4~6kk!SSLG}kA)|5NCttnRBfg-+*2#Zp*&@MDD&`Fb54U0LD z1O>-?hdhx(bjOf~;?+LR@6=J~m z&tOE?RuW^P_nv)T0aP}4nuge0Rn0>zO^96;DAQSwSG-khMF~PLDSn|^h3j; z+92CrMl7*X+x*h=EuE_?(09QaZ2 zE%3Rv2$*!Lv!sMKAfNx-L*cC1e4iv7}`SLe(+cZlHEi+yAE+9?TkTXX`WF5kg3OHJ1#t)?qY z?Sjb=D7mYi*i8F)SN8tuxr_skk0fo`FItdNJ9jf|B&vYam`y-zNV;iF`u)SXdM5~p zkZ*b~6x3GW@3h(ha14WOw#ecb zlcY?-MEIK-dbl|^;IkdB2Aw%OLAO?DiN*T~EN`UB+ZW1-4B&N5UpNin5&hv5gog)O zFX^m(c@9IsH|(&|#N-@rFgr3kUVCW_Bp$0>&x1*;m!5oVIJHX$A4`r+4FRQVqQaS< z!p7oL>8r;+aM$4jI>p?bPv(ms{zNh#_Ftk=p^`%a7Z@F~#F&B+$=Xi39ircG-I zhpP`W`u#vSTygj+%6yxg2AX=1Cm~$p%W%%67FOd-INaRAY6QdK+7?#hT5_b9%Zc<< zxLa5!m%>>>xC)+-qC>_CFusF54muvB_&*lp@c(Ymj+J^=jl+i~n`c4bvIrF9W*r`D za`N0DM2r5Hz{AxWVoU+wApicg(3bV|`u+kp3s;H^cM(HwCBA19DNhc~JuK~CXPMU3 zjl&3*D&YIRo0tl4+nn8uQ4aYSw5Q>e2fOX2)wWE?U`ki8Gw|_grdWJe#RK zu-($Y$A=}z*r*n?N=<{j1Hzl@MG9UxOnp4f9SIH=7KB3rzIp&@_Ckh3;{ac(`8F|p z$R7^kEpb*g;QzblX`G=L+?JbhTh?^Tl_yN4wxf|z@?w8Ah!&fs{EBYC zsYWNtrYlfrscp5Xr38HT?sy?82D)(q0R}9=(ac@lQt#s#skRn2%z*E< z7Th{BX~Wu=^I}WsmWEnr9@83dO{5a{Fx#Vw`hfK&&5CLzwocorAN<6M@+(m!`^9)X z&T=SZ#CBzXlbyb8e`Kz?i^gc%)NkR68Xv&|)vN91ebTG$Q4tkMoOe7ZlVa%~?(|4U zkRdQ8ewiS}RzKu^U`mB8p%|Z20OB@~MU!VJX%#6D;XvT!vAT(uxTEC9x;5g}Mir*f zj%lpJe5+MLv1XYwY#viB-oDI36j@0{#<$PNGDMIG&LQek;PmT))F_z(I6{ElL z!)jT=Db~d-g`v}LU_A?RQ5v>>6x}YBuOC=a1`&M$4&?9s8gbLXM?ro*g*%Xv^4`1| z%5dW@jUjbFbWWZHy*(e)h-+KeG4Az^>LDX_Z3I?cV_O&)#dks0XO6W@z1wCghCcK` zyk~r{y%iETV>?Dio%dHY#8N0lpjR5Pxq%lae3=NIO%EuRB1LRS=l<@OayN+SDKL%G z;tNQGFuc#?)AD2vhK9X1_Pvck;xG*KQEA_XX*5r|ykS(b2}ZZAmwGp_Lw-)r9%^Bt zVAl%1CDQ1PdDH60Q-|LCQh-vsxytrzLR|52KxVujri^O&v!5s6V}ZItzK8Ii+& z`hE6ZO+Oaa^kZSa@6NEaiRI4dWmXo;yBTWI05$o2rM+wha!tu3>X~{YGM?moBx;rF1p^PPJ@2_ck ze^?Uo1R+cdLEn;wK9P{TC1h-wdP8FzmUYwV#;0n!weGR0Su;`T)*$LBZOF?TmicUvhc*+>duWS zVm_^G9L(UsNM%uqI_KKyyw*O&pmv(0b^`hDq+C*R7>Ze}2X5ccg1##wBH!aJ?bS#lB=chg`Z*1{=GOnBjtMs3M- z|MBq2Mv4XEN7ljE1b`nQp zu{J>F#QK|cm%7W&)a@a5?o5ys6j<%}9Nb5T*yRPqwu;9+9EX#2%8w1Ph}v-R%n$)u z>+vmta8;}5)*4%2zN3s4n5L3l&Y%?9l1OJuiCahC|8jQ(9>;3&cIUNj-rMUt*3CW$ z@!%v2UIycB0}i?ckIA-WKp0|;bMeaf+pPEqq3^V@wYn)v{#$^+#_gFPWYvRo&eluR z`fb>_RYR~XBcbGoU=oH|(!s6C^b_f?TeBnAhj_78WYX;~CDk?)T_UA#%cRXx`L=<1 zFZ#DJ9AMXUeWNv+Lq1K236V8jUR+HHj~1gLnCj`Z3;QM)+jJ1oxTM|NMkN&kLbli7 z^GrsP1EH&i;idSM5J|6;zTTF93lkhMz7SR!IZ>zV>5oodVjELDX$<=^hH2%3l`&WO z87JqOoz5_TWN0N=Sc}~rEZR+rrD@xf-FdJY-L2e&$4X?kS+oH_N6Mby&=v-I$M$N% zn$#OLjE0RutzO@%poR?eu!Sz*SHrH9blpu!mrhmYqPxb65iYW`?|P}xE^A|dFjwpi zi(i?p+@A5`Wg@aP zGAPoC(Bu2U{{aB9rt?XOa@ZWlp>OJ6SGtC00PQyDn`7on`zB&6i_$pD1RM9Rykd%H#tvI#C!r)&X*A+N?xGZ$ z^W|4s@h^v|i3&0D0KZmz;;;taHCx{kBfk>JtE5;D&VL9z4I^NUa#Bc(2PzJ95f_k( zcILVVg_s`p;sqc(RGZPGJxnr)(3q0x=ej=8#-EiN9X5R@uy&V=wl~ItR;XxsN|}ho zR<+BB-`itsVSX8`y}KG|=07kT7z*^+zJw_ghVcJeQ4KU67H%~pfq1~j+QK#-;n(PZ zrAz`2Nxl@hE1Tv^H}4vb|NC|&)IOa~#j&v)Kt>h=u_(f-_|(69T#mr_^Xjs#zl9+!H}JHogek945_i-4{|2H5NN zZ49Tfkh@oU{;3?!@vijgQ@3(s-jxiyH*>(}Pwmd4p|{(1Z=l>QJyP*AN~!|MT{~Xa ze+GBrFcH3oUjtVQ*9M0J@b-Q6*%Xu5x@X6&1PpwJ0>dNUID|}!;^Ttc2-;4=V*3Gz z|2q)Xr6COY=XRS3E18CpYUKO?>z2I*@fQvw(+J66XARfb%@M_S>ag_k-ZXC8%hJic zvvpg$hvUVUaj}%OPjEleZ7Ss)t(QmzO?8@Lgh+YxFM4_wGju0SPAo62Oq#quz&rK_ z)RS0hlAryr?q>gwcQc_i5n|;=e{5M_=xa#s3V~R3N`al>bzDfrh392*jlPVeM#$y3 z3GDMx<%uaoEFVflE3UQyJI}D^5BS7x)br9e`|jip`rjV^tetYaUwZbrUBaR6LyehY zGj9 z+FybnX!*0nGO@A;dw;!{2W?y4bOz#?IKhm8y%LnJ{ocau3`#>^el#-S6cKJCq?&ym z_=T5E+?;o%_g-$MM(MFXWM}z%n6iyw_li=*_Y-u$<&!I>mNGq+MemIAu$*bg`L0K5 z|HDY*-+CCKP=IfNz#Pu^QL7aFN=CwwfM7SuFNGkx2pePz4r+>(y8_bGS0+Y3*_zkN zl;IYfvkk4%)34mh313T}zhWNTz}A%`;tr51Y}=j(DYNY#M2h+21a3=6n)=6Aa?S+V z)*k|OLgY3`!e?sh%rdSfx(?a}wK5|n5{xB_w_&aaW*MG>me>htuHxGP)13n^&ASDk zL7RFbDzTJ_rZzCO(}k3INFl_p;C#x8Mos_z9Hy(W5*)C_<&3IaT!1TfNSc< z7x;Jlu3n@%iF~198s+O%GqZ+XXEF4z1}PzugUVJ}8tisiJ}qNC zcQ5@kjqz*hTpO#`7Fg@Dx(1;ju}NsuoBEw}O3XPi)BJB;tjV3QcXy>kJVcM>*}dQt0l4RX)qrFz!}_YwXTzw5#MU-R94yYmm2Sz>~C$Zfc4j*+i= zVz{g8ViH8R+cmr1jEs-`T<_wV0%s{O1q`+X@k4Ms>-(w3w{or@>)#oXAa?pmUbV43 zVZGt1ZvFG^-1-x^VS;!GYBBlpSM4n31PsLz#NQClMw~}H2JxS z%f4C#(SCf;Wb2FjyyZ_27vUKjCujcw$zqLCBpr9+#WRo*Q<1qSa%;eKwXtMCf;bs$ z{cPD%d8%EtzWS;Ik1!f3Npg8*HT0+xz?`H5Lp5TQ2Q2T|O{cVkgHiCS>-K{S`NJn% zI}YC9uY`BMcW5i9hhV`9ixVVFUQhA4V4oFZ6l!c&XaTN3SPZ*ne?f171zab-u&B_E zE9%Sp(i6lzVIWVk;uT9*ST8e!oBmr9#O-0%vM)0$62vVyH+(BYpplD_REoy5-O0*c zv~md|p!{v!Z0ArtLA*Oc*2n7239z`N2Cob*ch)#Lo|-Fi>Pi#DC1~jbJkuNaxnwF+ zv{ZD`O%q^PN$l>fyF39hdcWL*i?f06lOW!w+{A*DO#*C3M_x(m7Q5vg*y|tSrvkg+ zpd(QnA&n2t%eR z%C%Y6*r*gXHgV~ccriIbtaLN(l@%Uf8!;T8LU)`z)}m^(Qg!aEHSOANU&^|wFTo@0 zx~U#F)!_!uqSTErSzyPDUq)QbUs)}Q;#T?Yi=;M9LvyNOl2}eaXR_97qDf+=^DN=MIh!i6Y#Z_yvxm90$%Lvzz za)R?MKGpF!g-376&%!GL%#OF}T-S7$`9;%9swmx7$@QJ_xMU zHUr?=qQsc+O=0nj_S!@oRwnnD{D`O2M$d1-^G|jCc4TCQM)b+&+ZV-jRXHBIS!LMf zTI-F-}j|Rm9e%D9e?ck#tTvLyl+5fnfADz`t zU8kTbFcMGGlp#LK$Pah%hl#Mo{y^wGID{BDQ21B*nD(pQkO-t~U-KvwShsX4-~xqfQt z&Ca?aEdzCz10v3Doq^rMj;&#_S8twFI;Bft*OB8N@Xv=_0FgijL(K{3C7!Rs@`m%^u!B zSR>Q%vtQy|@1N{7#6c?y+8u%4D3qC!r&3@?`Xl}g^7i0I@2de=V!<49NvFmQ8K!WU^x{sRYcL0?g~iq>nLr9zl~5K!Y9*8! z>LPPE=`e9#<fi@DMn}pF~-fIo+hTur;CuPaiWB+}#J88$6a}%p3q<>4@_EV5y9E-SKnp zM+QL)a1f-ygNETZmaEdd#=F=?KDTv2ku6yq>2F;?>MF?qs(=)!Fux^9JOp`?1z+ux zAmo$8hR{DHE~A9Sxd0Dv-VdWNuC9Ekb6p8U9spMwfPMU|tL5k1l4NmtpnSoq^a=pv`zdzNPNbWbs|U>)4q&tkE^(Z2yWR@wI^2$*@e*GhGUN z=2PntHzkWLlx}>d{o|NqDAW@d`(lXxt3qZc>1)7lD_8=M^O0T`9wMtCGKI0LZgH#$9rM_$b2OyAb_5a$F9&N$$p zS!_>3b6kTJ+>C+Q>C&8=qSiwp&Nbs)AuDvfa4t9gNgrkD2IH5XJriGQva9}F3ESg} zoGWFOuF_xo0|?{EU+;v9uKQObYj&OaHESS*eo&RL_VWVs0Lt7;H1Io7)jkCemmVmt zL`P{gd2KjkPSB-MO18WDpU+~8c279}0ApXcKKArwpY8t1^C_z+)RIRF+UO0vCzWvm z*+*HN*CaK>5O6O73xcN|BuP3QDjTDM;cl6GG>m1wAZzer~kPJj(xWRYMaX~#yyUO2UftK=wR&!wgu2Sz=yFx*EXJG zo0d67zPzFKTQm<)Lb)GSs)WaT24aIbxOJ>nKMOT%@mh4$8GG|%)6J&*AVY`YJC|X2luX$z& z&q~j5>{VRv#&00PRcCl*(K@|}HxPG?tYL_^Q2qyJ_zVkAD$I0f@oB|^=m-0N#%;0d z=RZc~!1l&r1@nGU(C(|Y3AzUS zH7q?zbVP>1K$yP9DUqQzBC{#{dBnB$uRL{6QSW!{`fED7;)=RpoL6{9iDQFu^N2Jh z!t!Yna`>Z8(gRTE=|QQJ)LAm;k#XA9*kF>Cn=EDp`r9U5KlQkF;zs!v!=zGgTJ%i5 zhM7p(0)G`^T0Pg4`jYFF3;SUPGv?wY%+-Odt8-n-VcD@F%B%rEGw_7E>l5e)II>Y? ziV4Y`uAf^6R+I*{-tkeF9L2V4(!$_&EC*w_Ytr1{0)%V`*@Fd2-prtRMM?It+8jl! zbzSNmbgUQ|HNHvJi|bW@458v%bEOqEOM94#Zv?SHMY?J6wbgYwp5srx@gX( z>(1H8xaR+=DP5C#9dM<$rL#=et!*zk+NCBf< zHTr>Mo62hwZWOHW4MY z+{e8!rsOrd%E)boM1UvS=}$%Gcw?2`HS|gx*6Kqc*Z3=$70F^-(CH?_B;Y{LZ1 zF0j?}2U%6zz0P;Xd{}m5CLvd|H&j(z=gIOZD`_sU{7K>u6}m~{kI=V16f;TO(Tyuy z*upkf$-RIq0LagR!sa56-k`3!#dEKd&#&OD9j??#*N-f)x-LJ0^ly;l?7gsRb6*hC_aXci2ER+uS-&?17{Y(^G36>}$z_%6=l17a_N%Rv zX|1y0ctr?T#Iqzu_y5Zo-vYwy4g5aoiC+?DYlalm3N#%CjSL8Z(vQIE6Qo0*1h86M zul#*``t|5LU;gS^w8q-8!`Qt9Vlthog&C5?SAwn!f8UOGe=%sg939=eW@{z~2=ip| ze30xEO_WW|h7G-)8un08+QEb2Lqm2$lcmT-Aw_X|=c z8U{-R>;a4mr}L}*$!Yq_F>wzxkB1~~P{CT6tF)J{l@kF2&%53i6COx~NIkEb74|q+ zkG==Z2?2I3VU$aeBIGm?5Qh$8u&2Vz^jqz8d@$34I)67Ys?>wt{v0ew1Btq13)G;u z&17cHSsXCLz4BVQTcrvL(Vw~!yuGvTg#D1GHkx1_a7`9J44GF@pE6q@wslSNX0SP~ zN4&VcG5NQuMsfnb)0FHkpGRsfy`%HSWP{wMh5$b%rr>W&iQ zp)MJ#)Q!b>Q=L+zP#bpyRh~MqExAGB#sIyTcaAG^Vmt=-2XO|8>2^Cw^d?1N#VCwI zcVA#oSF#A04zAZaGHyMHSLdnKiN8f?5R%2#-~qfCbIFM2G+8~_Q+q=a2{8kM3o-;J zZL|y(;NLn5*lt(1Yo!&pxxpRhGVoCN4#fij@PcvOhjS#U(Go4jiM=tfyg`N(r0cpD zTxh+OH~6IY_M7m^l4TQ?7fwu&i90JxkDwg2wh{NE)~cY%kf+5oE@#i^8>kIQ66%#D zbdK_fKlwOu5R?x9BPly;pzf7q9JS6l*$u&*-T=1eN`;TDw*nJJx~)-<9fs7bBGcWhSJyY!@3{AH;%k^Y1RO(}Wlu%8H-KOY zT^@R5sM#7H@~;!s;%b~|Jhf`EB2wuQYc-%lx1m4Fnn|f(VAIQ4?&6iaS$(z) zE5{Vq1Dy}!4u?9k5~?Cp^Is7V!3P{GJQxYl7(h)f5b7e}Y>|@uhl99hGyQWKd_e-?6 zV(X~f%i|_KsT`j%-7W%^0p6%a%6wdDraT-bHAH5j8$E#T@kWN!=}LK0*PDiN8l+6Z zRfX#~*H2RJ=%HcGuoa6R)rv?1F|Vl2e&I(Uz&oPVoTOJw^T{XWDbr%sc+Ox)dCWDG z&p>&)OR{UEoRripd_QWf|4%Kt3v)dp=k!#ICbt3^I+_@>TWw{oH|5?HoiGL-HYP5u z_*r~TErZZW~$mVo1~ z3BHtqWV}5LuZKQLvK|yiCyPx7aD9Q{E4m?t8tE!aPr3f(%ej-(tx08J{7w59+J8J+ zFayBPA&YX7L=&rz_&c#4KuRFI0b!1H@p<%n=a$WNwfl1L>iY#?&4 zWcZJ3fPBg=oifqU`s>rsd7rEy9`}U59 z>ok@(&|?M(@>igEA`y)sJ_36xlf`Ev$>K*4;Bv-6t^@vzA^j#Ctesv{yDSsNzmu*n z9M!!!&e*5ynly}7CJ%9%%phI?DUWl>+)-U*XVw^#t9xK*MckNgmt_`kXCT)x>G!U; z9xv4u=*LGLGdlG(F{LKR_`6wi@qd;QpRL3n#($1mf&sIGCMRf08lW*8XDh>x24xzq zr2p|&37Nih`55v`VZVAa9J+W0%RLP{QsbQ^)5f@73?%WF{jRNn{Gw{8zVV)dnMKpA znOjTz$BXgaV66g9$2BaTq-Oqqn`?AQfg<*ys~|W$eU?(UXlB99x>U=GhrZkIdN!EP z=DR)&_Dz_gh;Jj(&yjz6ROb34cx!Hw-wwIeRu29UDAZY54n~Jx-3bB|-;5orwc0g2 zG(6$$iDsu35PwnL6|rYQ>Np%*TrY-ncivzAz#8IVC2J=M<+8+7|Ndxt~sD0b5u%EuZ1nzSgyna4nT zV=cD*?@?F(NsPBMI^Dww>NhRU0l*X{_I{Md3U(?Psk|yv=oi?PKrEs4_G2(_i@c7? z)=X*wA^jWjb%VwETFLxlUHKX%A9fyw;qc@Jk)U`zQnWy4FJ8%+ziasgoMF42Gr>oR z{$0DtPFl421juMEZt*&FxDEwY04EA^7uFweH&^s|JXgDeZaUD3X7vf9Rzri|zG9o* zzJjY^2FK$%Q_VuX>%~ZZMX0NdSF!(_0Y_)+jH=g>{&5z8D5V5ELM0<{G)+X z#lRWs?09BFb?mP1FWtwRik+!%mt+rkoZmqT8o;2FJHZvvk0M8ROPw`#r<3|z{y6(s zhm-e0+q(;6U*oqMzyNq71jhji^I@2C0P?vvpjWf~np74_s1`Rp&mNifx}W48dU31Y z;8eF&YDoH_7r*m=B_C#WR}aGy%dEgNg{4(DOTN@qQr%VZGyj+JLDm4+A4RFvlp@yD z2_=lpPWMWmMLHZqZH6qbR1+y$L0j;3t5AgJ;Lf3b_>?U_^_}ihV{!%7JVU_ zYXcVO9cAt!C}!6uwb(|Y(@x+xk09a55_t7^dw^uE{Q*t3Ra z`34O3iXoiskdDZ_2hd`kIOtdtRdh|d8WjE~j+qU8u=tjaixaER9E4G&J;YBDx&tZS z$~_=-7cRuHA9CqrvlDZe=Jig@XHE}xvjvN2BCdlt8wOkWNzZPpSOR)>NeX_-l~6gm z%bIHLKlJXLs94)=ka+a6o1Dag_zkYB+9Gz6Q@#LYKBo1a<8|dw@?%?_dR+hDJx+@M z$P7yZicDq(uil7w)6Po+Kvy?po3yGEk6bYSWf)6Z#H-w z9AFXOTdwuCMH3rCi};&99Bqdd|XbyU%fsx-=OvRWOlvrV8_6qo1 z^Bo`j9xUMhkbhrEoq!RsZ}!Trk>kWm2$OB!L3Hg8-*lU4C3d|@$Bac)oq-{gB-}2Fa}D_g|J|N z>Q2SUMi_M{8oE@n#ez4Dl-ORdx`pP^?>S_Jtyc28EG@Z?htckSl(|C6jvU3A^U$?b zioN!UL8LblWBcbWAEDgAo8>;#bJ$vPk zl&ruzX+^D+its1eK0Pq$P_f(^i;6vzr=b(n%elI@de|68uOfO&4hSctt)?H>`PI@b zH5@=%yLohNUvYEOCIh(S(6vNn!?hg;)g1ZL5`1oWr751Su>;VtQkLtioW*sht$;GW zmdFcd6It?bn}>58yoN;v9{$Qlm*FwLprxcV+tx5n_g0FH=jgRYzY*KiIH73*?(Sr5 z-$ZXf4|WK>lW@-Ox(QAGEg@lQ66;s7>gHNh3~XlVcqNRFDr+rJO6CDN=zI?^>$y}c z4ZS&f7?`7grO*uy#yJq~MCJY)lK`QtWatdc$*e3CkAr#@3uM9+p)R8YD;iq`R(WOr_T!2qY|_39#3~@QAg|P~fu=n@ zaRE9Eop)O~ae|@w&Uvpyah=C#7U7sqH^;m*9IAb{B=#8KBKz`U1>dK<2y~RWsi&=| z{LxHn=HKu;30xku*pJ3SS&vIejsE^IJa~~NdyehS=Fx6|td9fDY2r;iZK)`CB`7RP zW{%ALL9^Xx)3s>7El3CJ-`>*(OT&2IoYXdJtt$Y&94~X;M8*{l|6LQjdWxHGOy|FbnSv zegJ3^P3JLCxW!gACgJ${*=o-AI2R4o& z+EZfVHjTr%W+)D1p9ckVs#5=4Sh$+Xl2QGkumI=l2L6n1U!OEq!uRk?$>H%J)hnT! z-ZLyL1Gh@;m(GRu{hq;IXL(7YK4`ET9C~OZstkWin<82xUC9F$Z>5mXB)pZyQq|GW zb=X&z#hzn@e@h3#S{#-CmO63l=B*TJXr%vNHTE9Ud+ekek#b$7-qBMW(J0Kz0a0@p zM9oV%?3O4JyFm0WH07|Qn8z!idIBfNFV_jb=CE{C)g^9UAcu9bcu_I{|D)@rl;fqO zHSFU}ES^QtsR?psAtRUl3=M&uzD@GW9B+}&PYw?N0{JyWg$6_ zt$r9s${$A<9%&=YxVUNXHSYPNXqR@fLhY?a24^h`jQ-HVyx zlSQk~gSz~dN!JfPA;I2Bc)b@Jt4@KaQuwnMAmUTR%z6P}djqml#6Rmvecw=NuiRSc zsoZMsZaavPkA-1`ykD^AvxWTUe&J|7n>s)b7r#{2VlTHxd3$L{#CsM?s9v-Nxjc&f z8u2@dpzX{7URo~>2nv&Xv(NdmfRJcr3n5{ADePJ_Rg4 zRxerrJ;)nU#BYPb%mQXgg!DS#fO)E>#prl(;bbUX*<@iu0UMSM(Z8Q^h*!Iy+~A0& zbH${dVz5rQP{5vsD(4RWYNf5xpwVGJ)?1hr#P@tzDD1}$;+w*ti~U$SsvVX0_2|!fuw*(*6@mlOS;MoQ zwLJ6Uy233Cu&_S-9UeZpOFRIa8}9FQw(S2 zd|XHvHUi$8gF(SQg4xneL%DU*^@*d22hg#aR-eS}oB_%bLemKLseTDe{z&-*ry;Bz z=+Cpau~BLcigLo&x3OUeEov0hw=)xZtBDAGZfAqjuS%`qBzS{NYyw)d;dR+$h%y?> zu1e>^`4KL;@WgZrzmE{Y*$-o6!OwEV@0WBfwn7B;|D^XsI&7Xhl4l9TH-~F$J+5M4|+3!ps))eUiJwm#xqOBx9(Wu z>ahea4Ua}#yL1%sivJb=(M_IP2!25ej(WTFw~yF+&4~3ttkp-%!EX_ZL+m%73bD@- z(Ky5u1%zwJ!#-*AROcvF*NYh^6t-R5Jq&03Kb|PDg5sC^5uTO-6MXOslIFU_HssG@=&i9I6d6-#C z;y5hT`}$8}x3EIuBIx%f112#U0B2mD-aYAh_fc9;ve*MDDFL0k>;_q+5Q|H&PiEQ4 zS0oAD$j3d4U<}4v^9@&^-79RI%N`$8)41%q38Us*^(z@1LfV7oL>soIX!p|tJSEJWYC@pBc8Ax5Ew4n7qi154+ zd1Bzr-yi3Cwbo7pxl4W1dIunHx>8$k|PLR5M6E^Xz{@>jODA(^mW^v>_lIyc=J5Pw|U}eHZR#QyJe77KYu+ zs+n16yO#}wPS05w$<1+C9Bc)UIbp;#N5{3Ti)FcI48q>S*HVNqxl-kr{dW0_qE7Rhv$ zY_f$wv;TXBT!6wBrQt77FiCvuX2W7oNWBkhcd|G;B#gh0rB*aSFE>uHhGI_>%__by z4Bewn+|fuOy?Cvzm)mNxV)fTWsXSdFE~;HJAAqD#+tb!A1!oqLH$E@!r}+9sP2@7%@2YGf3r^5{~-HFH@Yq-_qudXgW!0GP3)TqG&Sm`4B=tB zlvH;|E?MGUhgxEn9*1JLXodehDNXq8A+~zp73oU=<#vI%-hpJYPzH~SfeZ$EEhH;2 z15?Oi(6O{`W3?6pJ1b&w!nbxdMtwzkv`I*w#mW#G-6YJO1^V%dq;J~SJPU*fg6kRu z&uli)suP$0qa_R|d>$tPQey=VLv;lwf0D0t#XX3RZH(*Cm(qb3IwGAlKZbNh-E8{Xl(14Qtj+!aY1zO01*LYNEpSxV^_5cY?5EbU_6P>pL? zHyCpK$Z1#b3)MIzUV%0r2U$-)rv{i4Cccl`-R-GWe~-_2IHBQcQzzb}kNBt@VOo9y38N?|m3Z zLdfJ7#?J$#ULF+m^I0LWeuX>cv&UGX@acTkS95eZq{zbg`K&j8Js{{D;4W<)u4;RZ zKPJCrHLZw&oG7fAGp`#5j#b8ZQ%Na!;wo!q%qX?_3;8WW=NS;Q_v7~ne#>#ZtWtL# zds5x`+!H!b7Fe8oc6+gVh`qyLwyR8&uFn~X4-L3Z)%d8&`tnt5gT~0c_K?V_z;}s_ zefPQP=^ONM9b@!r@l%*?Sy9#6q0&=j*qNfT%5QL(Y>E>{>pU#%OBzb2O&!nS4{IbC zUwbmZv{-}{5l^;fCI_Q7F3*l>^MN2aSdRL#TXiM9VO(4$EL{L6CHDs};f$+$ zicryIX(z<6blnzao{01pT<@s+|8NGzc2XF67BYO!V@*Im$HzXmkc7FM*bX{{w2{83 zhFBFgVsr3R=Ykq>fsZrIMfj&+T*o296)EUv_z$%P1DD5nirsO>-{5;mRdEt70E01( zs?l>Y)rHs2I3P%`D!>n>-fPCdd3DE|3AuI#-78><`jW*rLi81#0D{pdyi?15VBOrG zEULm#4WET~&0JMteAMz0cY)$&_xN*r6Rstt5m0nzx|bfkV~+wjFvm z*L}>~27yKtBc>Oao(CLz& zTQtyT<_*`RR|6Q*47@S>j~6+>QGv;eNoCEjIMzMva5|u^(gHisPb1f)vwp~eL)QT2 z>~QKT$jZ7L8pW_(`9`)l@FixfvtNO9CPlnm=HP0U(t_!S?acHN*gh(6PJ6Nj{`w4G9!qO@>1c1(;8FLe}pTowchIHZuqz=nMs)Ef=sXS6w1S&FR z5Mrm#U`oU=BeN429o>YRGWxVJm^T|{C?N1KG*@W3rFJdU70VuLUML5&>8aTs=!Yu5N ze(-bo4xFAp4l<5ltgNU%9uh!nNAy5a#!;cZLNxVLL#z_5)Y;?jxS-mBZw=ljD$5~& z#-QwTS1|PZ$o_Id>~+|6Nrmj#?@{`bSh5w_@!Kv&u&b83Swu2}H+j2T)Q>tw3czys)Yt1Mgrk22u ziFEUDn*rG*Jn|?@ODRNui_u@hV4WQZPpQ<|4ZW!T3&4L7T#K18b#_n<6LmtanF0O_ zS*Kq*lOjfkgrkeuJvpONz<$*CtTAM*8_jw6UOW^lV-0aPoBKc*`54Q}$o+$uzFH^Y zszpdW)k>?DWetwM!qUfBPTD5{075e}*Mh~G)HNmp`c1B7;zpqc^()$bC-ovxa>!P< z5!a2-YEo2*45IW(oua}z>4j>wlUn~gz+F~H(}}MEjzY%3>x-f=hc99xzMg4Xz6y>6 z&FW@SmW#mfIKhKyq-DS|K#E>{j*hW=p(O=nHiW97ef9Pz6eaFWmtX8da3O#J(r_yo zoGPo#DWV)&;>LQ1)vf@W#KqmUUPwU0WJ8` z!kM-?bqI$-1#nApFiLasq^zsX0GL#COFvHqzQ%-@b;IEtM0G8_B)|C!=*&;IUB$6{ z2LxvKfib;XhQ5GuL&z!%lA0GP>CA9d%8M*^ZYcxIa@$%h%M}+<>9+_yTJgMjRZ4^x z9`ed%`BZI46(0#<^1MD0Ez^(YVWruw5D;-T53q&+X1LDy1weK z$mF4%AA8{S30!`G;`a|e98Yq{^-AAFs(}K*d5=VOrxb|a8zbg*Q1S6IuMX->oUty` z3r-4o`C}F4^XH%k2!=E5g#W-la3FuX-ZxS5<)e2hHe#z55poWZ!$APFkwVgG=-QmX z&%T^7*xwtfWUktPY1Ah1jex3i{?8<0;hgemtk~r9InO9}FQv2UllRK`9GI8BimsKS z15f|KL?FNUEaeOX2D6#S0O!aBJxeq#tb#B20IuDV#BF$Ea&4md>Y3GJbPn>_VuK5k z$|yb5RU|+;wMJ=AK0QYFpYN?#5K0H`R9JG-aXA_|a+jnJApBDFc#K-Z+wiPpTvyg6 z?Q9_F0@*$hJBC!N2)&iio5Oqijj5bKHv!>QQz5*%g!P*9bQ#V_Vq6q_TbI*%R}mr* z7YVX<6*h}Y3X#1S%{~s^gVp#bLW@GF;@?n+GnYHc+oTZ4?KbH*97>F~9vJv>^4y83 zBBA1xJ2=w<9CWQAA@wO{=q>l{0^HQ^9dEh^NNJg=X*B>pX;vSP^Qd6dYMP)S?eSE&A&yuEO?pH;%wG3>-u}B%|1jikUxi ztbRXMM>Mbvjjlj=6^wbwH}?G~N2fAuFg8;0D&sg?-t)*q8>Hq{iJOql+*Ihxb>OAB zpodLUbXzm8Oi!Ao43F^zI{fewVgJ)Cec{}Cau*q!|CS9?vlrKUt?g?omn%lS35%O8 zwm0DCjI+!>xh|g-q_*feT~lQ*RWsj5-L$UP$2MKAF0UR-l&(pgpV(aQyV88)F}cEp?6)%3++O;%UKzr#=@ znsqgNHu$*G)K9@8G;}=Z&7x+SgE52evN2Olt#SaFG)a8fI^rTBadJ(4J|gh$CDECH zy5OE73sD$uKc(pdX2X4uWP-AZ^Tn*&L5+p5S(} zoQfv{?=dT)`oL^vz%@1i7(FahZPL7egcqXX8N(_|hlY`BVS^2-Nw?AVIM_l)`%HG4 z+rp)@*j}u^)|;y9!j8jAC)n<-m8nt0BIg8Y8LC(tm)RHX9D*-U=ij6 z2wQKQiIRg0eR3t6*q(ciQ!9&%w-tHPlS5;lN`Sa(;#V0FO)l|vIlm;xe zyOg?`u2|N1rM}r#=HdH~MK_)k^*ypr*2C|GR;XFZ5-M~+85*J#Rx1^m(pajk!1Iv* zl@2{vl4dUV=Iwh#nf|$bT%yrvOyj7}|GOSgT9q4Wy>Xn*L(ir4CUB~oZCUYEizC~l zhW)s%Du;uW^Sta7O5r=F;ynOmky%*{v|DP4fGOIw}8)QFU&>_?yA6TXmnM!TadziUr3(M7D<0XmzaNN4PtVNj~^77?WCdxDv zV-f|OL@?c69qOdC^3fLC+kf36e7cgQu~y;RmH1v_LCKwxh44y9BI__}P{Zl?Ti+(t z%A|`%QwbZNEKGftnKC!3Y1lS`pxGp|LQ)N&jo*^hCjCnms-9(q6P~`=!XId%94%0< zX6vXO_`Q+lV{b)o){>r4n`Eye_FtPclUz%dYT)vOGakIQN=L+e>>MKIqbpc0>lALO zU>QjlL(E3>%$YMfYGd`Yd*eEe3J+AUExitp|8|1e9|clo@JaFt9F~3yaOTSosGEoe z=L!m1>Wznlj7s(}`$(v$WOrzUu_tB<=PjF2qLWocw20bYq-9rSKy zU-Z3Hem83%u6F(s~(@D*X@y;zeKy!xlvbW|aTp&D_VK<13d!B@gB*x>a{g053xLX%#CN zv>><)A3U8w_v1<*kQ#4Z-7*aCraTjSRk+LAhg2|#m3&>kfbrgQhr1C(#X|?`oFC=QIjqSF_pbzom&yLiK8vROG*9g+^qWc3|)R z4J=i%ZP=3$AJ707j=||r0Y2apv42b5Vdp|6-VO>kz}RLWNY=2t9?(WS0PUGYH4DAc z@`x~Y4V%qZgoIsdAb=ke64IXsY*}+qh+WIR=H%pMgg*0X`}{vfHd zrijI1Qcu;2Q-i{n>!Hl?WpH0Bt}6C#q1!7cHz?3m?ulSmxtAdceg%9<77!M{!cOt6nEddMB}{u2ilih1d-YW|WY{Ii8+onl@%3P;m$QN>Z-2rh#Tt1@`YRIe zF(@HVVQ%3rNv9&OS3yza66BdedKDXl&?gaLY8A70za%Yh>Vm|B zxFr2uFZ{5H^)vmXfRK+WyCfY0Ddv2fYT(GJ zEF*Uy^_!rO{W`Ox??SEvC|D|E5mNuH)UqJ-UQlqn&IXNpp}rD}$t7tuSo2jN>|Vpq zg0VP&YdwDduOZ$mNP87OqUhbY?#J(+F}wIW%jz~A8K5$W0u|x}R>bGl3nc>kTCEdp zn7Nyw_@NUyh=De*!JA@8_iDl#UZ0`-OYnVEKauzZj)H zK_ft^Reoi6UIi{cmhF;kQs8*ItW|mzuGh$th8f?$6RzAZ)V{%XGL`Vqo9rpIM%226 z({Dm8VKqb|Z?RDocHi^Y^y|8G4mgg!ZCYYDK$osr5B(NcB>qF~{spS{5`IMf)Avsg zd<74F5x-XaXd^E}$A%~Z87o2q+$1lev|A7=ve9Cu6W>;N@sw|Jv(*12Z*X&rSJ6*| z+DN9b>TT9uVVMth-M`mXTVRR-pu#GRCm_{h?*~z%j~1YFN6DV1LCvU=E&Gi{Cw`aRkRw@$|O2Tp_ut9R~L2 z;m=^R7lUJea?5v7pcjSq|6#+~GeW^T-~l=Og>LdsG#TKh-{FR20Z)yzq5)JxExx5) z`W@&D#Db+9^SnfNvZx`YA@Q)1;+Xf}vMDeEL=FsM8SG%WXoF1)*S3$08aHaovN1K= z++O$y?kO$_RJzC5#M<}@vBfvtP0oX3{93p<)ilSzSMs;D$Px?T5P(Iyy_&dl$DhuG zxY2g%92rbdC$`PYb2rF|+zn}_(&;ryDsZ$h;G5^-x2bg=*ZXZ*g?6LR?$~Cou&jkV zmp=lBs40-#s<}RhR|FwZBc?sMdQ)>oBZG(VQWbSXj^ZZe7%KhJmQ;S zm)pgVV9#OMNH_%GyM!)St<8Z(E;+7@h+(P1SR)PA$k3T}eXoMhr|E{4uC)i=fG|v)ox~ z1^DZ9+#^kFL24rMd2j-$oj=a#;ciGAy|#J*h~KcV`h9lW$W(ECq{!Ba>Cy`h^57vI zJTi*&un(o{b?GMv!-&1=IexD)usR_2=-?rj0s01vJb`_{dJp{~B+>mJpI7#H>8R9e zwd&4oPrzyt=JaY{$g9yK5j~oTrbIMd7CJZx3{#}MD$M$TrKrE3c}2Asomk#b+0iG}gZ?>-^?0n6%xwmUPTZD5TvLX5>f@Zf-VYQm%zokclLf%K9 zbISjd8iUjYL1EfQte$@#YyH33Rz7?{*z<3em)eGN5XfL#t8_sLX}nXoR>=dMHRST& z2ZZEp%vrHItUo|Ryipe2WIK3G>KQrg)_ARq!pkC?5w4{0b$2>W}bZ&jO1-H zXCBZJ)p0F_LoO#)EBp1ftXAo~Uxhtd;~k6<_!%X?05=$10Pz6SL^yGe+)6?h@nam- zNaKQ3E4v`ymMbk-ai2!NFlYxG#lPtnmhE68ROw=q;NHP<`2~LA*B$J3b-I|@C>TCw zi4R7JwfpB7y1=h4;sr#BJN6f&iK6|=IYxO6eL=&~0kl=hN64y#j0lm3!&WI%$^Ehn zEK8L7;^x(i2Z`G+Z1@;Ds$QS)!^bQ?>m0Nh--)EUJ+%$3E398%d>S@doamI9F6WOdr`Vq@lHv%nWt>9QP8+= zmF&v48l`l5hFb{kWFrQri?+yNoD>+;V!lL~fj-)hb)CPIx5AZkl(#n-Ea5nX$MdNH zYegZWPgwj3R17iz3n-lZgbnD?jN>DjB=tlKM`R&$7fWAIFB?oAqzy;fXR_9t!$`tL z6qeR&K-x~cBdxI-ef+l^-El3A-gFsS-zw|8Z@~;e98FKvDs8T_V)78(NhAfSKg^T&R8_&Pt*xVcd-q62gEKk81La!cu`s;3yVL62J(qGmGIK1 zY?dJk&Lgnb7&t8JOrA!sdCRndE*r?Jk{l6YtJ&E2t5QqE{0P_f0t3cj&QYody68RAaZ?`6O={J$v`6u3iDuI2hGf(O~U#bR+twro`;H(TpEW{o5rT;|8f(t z53fqe5l#PfO`6{E;*SC0mm0P(J_AZMu`ohVLlMtg8ZUlyK)9zCinbYm7ZWzrvhjoC z#moLEj~;A500Tqx!=aruVQsa(0mtpALyN~`9-3D^TE-^7?iqRURq5$)yf^@g$h+Af zd>>ndal6?_JZW@5sM^iad2?9Uxf{p1bn&)`5Wfe0(K7&EFHGOVvXR!mNm#ar*#~5Z zdGN3W3>kca1#)VU!ImzbfujRr17~}PIeb-m7Ff1wTMr-%U6q_6A$Bh_;D)<|{(D(U z+6-iBkeP_gX`u+tL#c2$kuJV2JhYePR*XQ>QxVT%fT6=O;WB(^4u##B#+!;oE**Ff zblBsMF~iom15`hDXkqKZRVC%4%~|QEbhCTHY>0U194S!Y57_%aHPOWQ4#zV*|B+1mnebe8RBLpkGVyZi4eO zmYE$7e=g>Qha5WGC?mXWku`hU9P=aAZ1cnMqSGhTe#Umqh!aQri*Bi@d5kMe#0+p`AD+V*Y93o9Pv+vqFs3%) z!H6R(!Lv-XWdXhJye#bB#|m}v;#thAuVmrsKGw$&Pb(#cUR>41d|DH2$uM|E+y@z_Zxl zF2)!&3irEN7Us^nps)g=gbec8E{@c|+vQcM4_eBWg`I9_UL^#CQ*LFNjSUL2n-yea zcNI;WkUr_8Jiap4=6+0Tqk*3o6h`c4c|+30#QM6&Y@=*;+nsffX^ye1)`i5hOc#^t zS=P3N>F_7(SiH8RxM}e`8lXA2d0sX&toF0s>40MZ-yn5d+C&vJFDaxJ?+K)f_KRG=5Jpsn5_Hgjbu>h3)8}ceR7E}OYR_phE zJl^A=DSH*tdJil+)TsA?Ti8?2CgT2=1Wg0bapw61OM_xHPz;Tw24+ja`1*@rt9-iV zu%lV#D!*~i;0wa`26Q*cCmd_Qs*x^^_X|B5S!$ol^0o!5(gp&^mQdDCM7BaK#Bc9O zs(|L(nxTGT)}B;tyGrc6$&Fw+q>DrR!oo&2HTNBP|3xhf#WVNz6z>fg#&30a+-fX- z>Cm85gZrE=el47DWLbCVf$+N3uCGaYwP(wz1FJIGv}llj?J@9=2*Hy;?5q(@wFQiw>TW7wQWNXNcdHYgZo(dQLAubi z@6RTd%n-b&RQ2l3aVa4ZcSjOg=%m(2C*QJj) z@dAA?!EtNAky<0Pe9rDFydaGVlVjsS9(6(4S+HR_!FdCjXI=fq88PO3%4VUn6rA1s-WjD z$7(G|Rfqc!yA<4VT?_6F$C`9EtL=g$g*eYl&}$8?H(nw#p1g6a$sk{DFyOKSz$WA0 z!XIC-92OQ-U$Q5=opMtt!jC#3tooA8Vk?9{zGSx~0b(6H@MN?&R&b zc;}CP#d0zWBeh_6t9(G2h&-{Bj5cAk+Ob`a-i3s1U$M;S=gD{#bl584`>)tj#?Qcv zQNs@Qf>fihWhk^05-;M$u0!*p@bK5{VSY(aIQ%u>D^3XBubI0WuaqFT8d2E$4ZF1v zIH#e7&cRt5c&Nn8ve;l|5V`E!05K1R(;$SO3Q-S*6Cy(LVKz8kBi4b3Pk3i!)TRNF zmGIzUY*-rcm5}h|VK&DUBd%+tuMfv1o=TK9SW*AkMj|2%2rUK2@>`a#&k6hv$C5pP z&GXL927T)<56Rp!PeElt(%q|NlNAMNZ`336{R&|E~^a}BQa-FIg zmRqjSGR1iOhZWM0LJty87A~)7Af_b(m#5D>rR;UIEao@3CNw@hu&KU0|ZLvbQ zbrG_S!kF(^|D=zChNUsy*Q4PN!=wevRs|Y(wD7O*SPpy)3cJ3;o*X0Qg@o(hu|xd^G}0UxkCibNH>sZw-FW8 zu8K;w0hKvsn~n8hO*3S(p&5`2Ts}D*aYn@lbRC(t7gFK)?N)Vxs_k%^5mGMzko6jI zpNh)`W2&IS7TsA`9+5g_C5l)-#43GgisM)0LQg2Vb0AUw9yq?jM#&|Tr8oK_aqDp#nGVi-MK*hqLkO|5vd-fc~b>N1w=>x zQ@rD-6;>g>pWs-}ygTnebm!Z%d595np>;@QKSSAfP_-+z53xS~tvMNNF4WX(tu-Uu z(VY#m2}PN1o-DpdlDZc-ZY@TSWc0m&6S%YdywLUo>sjIU8)3d{<>2uqK%wcJrgPg< z5$SC}Z<03G@vuX=o(peNuKsYVa#cmlODVrw#DObOcs(!D$(YD?ob?p9+N2c4<(h0c zMp9K;4NX}$|!Eyqw2XT!9y{0Alg8R67*cB z&B@}$2cxdDsttHd+;-*@;+y3#;hw4(1970cx52>p%? zO07K4xd!3takh*N6&9ReS@wqlyiJ8yiFrNpFX=@zNmQ-}r$ee>LDdRW<(1}^A=K6I zQ%V};;&^~^#Rxs3q)}*|QjT(=uX5o8D;Yi^(gWuuj-!>G+!@f+CMFP_N@=Ah7RNt^ zrgQLZ5$oe+T~nFmELqW_KO$I9!7edcY>NmFo&v8nT09mJs!p-O#AtDUleeKKRDPnxy-lPu zU)v-!pJLC#EO9slK0mSi5z*qz$PVn22_C~BRzQ$u(c)c^h1e})KuL6OiKiX)aY`+V zEJTYdl37$=|No*6dM-%1$JYfJpF{w4>dQ32lvgS z1dgiw+f-=huN?PxV6hfI{ zxac3Hd=ZvUqHgISO;2XSx%X@54!1*OgCeqgF)#J!19IB0!l&L2C`(rgPmYT7P?pA!D9Chq@XzK(XI?f+Nji|I5vNL& z#&P||Q{*E1CIB^nASD{w7lUIY*)xcyYsa3(vE4ZKOuAr81lfqXWELl+A*2BhnLlWB zEcwxs!s9T5e_bbkdr}yicweCTc7rd|%r##=oDUz$lvBcz^f-7Bt&1$`=iWtZHyZJY zlZ48<(Q+D)KRN|Rh*N&KUFMG&Yaw*mbtI z4cOl+;c~|w07>E+cWClO{jTfmOTYYTlW?alP3e-qZxUu9@$c$E&G0^n`-_?lFTVn9 zh`p!E3r-7}rj2Sch{{e!5OGb7q~SP+?)@mxmokXxsCqdHKeeJ>%; z|Mb~#{vA021#&HZe5&Nr<^_-laN}9wWl|k|R=9_z4GKq9LIrUTSzb^hdD6EEP%(+h zG-#vFg8=+!NDiNeR4ghg_)IPcyRgz78cS$Q-T*pPS7i%@uuQZ|oF!SR1PPEv_;)^m<~ zu7)0n?PFC$sKa-REAR);#yb!!_Ygt42SVTYa;(h(4=me^uK*UXS?eA2nq4Ia(}#KBfXcP{Yg^OHP!xbFKG zQ_$>D>1K-|U)MN#@#~)D9=*?qH0Gbhzj(?#`xcLWdbEe+@ALeV=Xt30j>Xk21_T1T z&GWj)kZ-EP84dq?2Ffnp-Z0wpZi{j7+c>Ad^9#-|i}kz-hRVXlsL&&~$R`DHGeRdE z^Uo^9Cx+Ztvaxrb<6)pO)Zh%~)RMKmdG4LaX=R~6^%jcYXybS^filbxCnTLl#{G7# zPP%|!KA!Rt{4D5kyD`u~0<}2dnmt}tUU-S~$6HImH)4M1#;TWObmtdzzCVicd!jfW ze!y;+#r5Krm}_jfy4`KsmkPa&{JCBn6O*bmfUa4ryvE{Gxl=C=Pitp`5j3Iqea|`D z@m+bgl&hY@>_$KyYY@kZt!zg~E;ooNNWB%R-ewTf1@Sza9+CGL#RB_zHnxtppU-sm zhd>{Tk21d(J_AnDQHcyA67Mm;qjdQQF2p{ctPVkZ;9^ z_3({81r1-Umg*OjUx*VWcwmj%Cw~wp9uq_CPpZ5kUYs!^#4dwgfg|B|^ukAJs$Po% zg}#P*@4)=XCFb*NgqG5``^kAWBq+yN#B@A~{`=%S3zl)`STxS?}j`@JM?Q6`0CaKVIj{U0jB%V5g{5~YltOu)EhPG+}s~P*g zc8Er1&U;?Jf^+PvTKQ6j=<%LoYY~Z!Pi%Zmc8-MD`{F4X<4GCXzJ*9ZZW9`(j)N&TgJT|_j z>hL0cADDg&9g7kS9WTj8`-(|vXIW8~dle4f+~Xl-wk3v})t<9#RM(p@GR*PiK$+lz z_^9ml^BOb30oYwB30~$L z&($uY1mzX|#34D;Qg}Fc5!&(_ZALRuB7XkmYGqRa;2(`qd9tgQQXiHZ`iXg9V|&KG zt4-XdAQnbPn`k}+R*R~(Qgb_d++T&fG|ZQ+%o^sPuoQqTiBf_k2~iIC-EHL?cD2Rf z%u-xqpC2`BOVh4n?kOFG(u1J`<_vDOHnO3+XGbKv9sAbwETh|h`@Vx?mL%DCugt>h^#Ogq!M!`z^5e}ByKXiVbowf-f&d?{Zj z@by9)lu@%mXCjcEhF(S;YT|DIWRLJ@np>d9hcm!#91mV!U3|BFbQP3G= z6T6yYnI@f4y`LwOprPy4k|y=CWoNKci7*=KCjLX5>Y&(Dk*bXy2^_az8Pgzh@yZ7p zw62$OIAohMACQ0ucuEQ|=gts$G;aYqWRf|~Lp|eM`fCP@U_}&AP#VKh3|NLRWJ9wi zCVOAw3J!jnO+;{=>;!~5>OOgJD}AK_q1HTYRtMu|#7!3gzZg>E>!m3tc7Rs;~@qE8)(>SpXD^O1nxUa_4m1YznRe^d)TSdCs z<^ri@iiFT=PIH(!_#4Ih=RK#hOTN=84)-q9>7lnXAXX@E;5;3=J6znSbbejJ)!mS) zFm9qwe%~`bHOo0@w&lGcGvsLsf^Gmn^MA4N;Bg@OB5^pgf z%S!5Z@t&cgXH=n(!Zv|{kJ`9-CdH9<5+9{XnWvB~#kOu!UnNpip7Z0L~y@C4;%5FiN48vpQGAOBT-*leC+Uy@Cr!BeGIXg}M09?*)KR>yH~O{^VIC+4qM;to#c@Yq zigMfVSrfzTu>i^ZBet_Oy3u$gA;jV29HrSyxf_0tc(g_Q!LF{-mpwQcj#vFxk%1(8 zKtP0dSlZDT#Ah>I6D@c5t!SkiVw6E)xi(82*Z=lOWA5cYA&Wb1kQ@XHaFMJpR9awg z%-%Ul?wc(R_6|m{lxr*xTB-KHpb3M}idH`#Q`4m0J?*|sBJ6yidvu-g^Up;DKFZy# zs|%8vWC_!Eg|1?wYLRjs3vhS8u?E!uUMJ6s`$xTeJKosA-_;VB9q&H$C>CRwh&HzF z-p(HQwrVVwElyxXGY#rpuHxmumaj4UaQ~UxZo6?evA<@=dS2QBIplNvIN*iPWN#eH zxg0$tVJxvOMsV$}B3KCUc_|nmrwtJE)0VtiQF8*)gO3^fM#l+6H5}ygG2)kJ3=j)M zAG-t)_W)5!_OT->_i}s#bBAT8+i`}uRQcclaV*{QmMrFoGlU)TY=mADO5|sA#Qxro z)fqK=V7sP`0(X$}?SX>}PxDA*{}X0y${Mf>pLJwoGrPj&wXmHS1M2Y zu1}Gg>v8y`MTh|OC^w`>HNK>h`kcoCSk+03cuuf!q;HQqb5SBZar!ov|AQY7u(*(G z(PemO?{HmaUEvoUd;fcZ>A))747*)9kMZ*<&cDpAg65sz-Vdt{sYYM!AA-805x7-u*djrK`f=6x~DE9L9Z-61VPPm%bE4|@$ zlTb_{E$FUp?iFiK^y%^~NGA@6wG->h6Kb<2!bA9V)yYE}WW8d4r?@nO=H7s`I-Cy% z@S2+(TO8?*W>xYvtJxLspw1uzglqMXh6K~64xqol8k*kl03vhz+g;lpK`3x|O{dj~ zXm->Jl1qHU2n9fk_+~qzt{pVa%UG+@?JGTZc)o*~b5VvcxVhQ<&TL2De;je#j_P7i zU0Oq&BQhkq5pfYvkJ$Ktn(rF9f(#+PAv~&k4zCBbl&@8V`mtI)^D<)Eg&6Md)Z84M zpIly4AAcF(WWJVB*79IRlP1d7ZDO`CLr%yQdlj#UfWQH!lN{h|(tI=@p0W$ka4S5U zmA)$1ay|i-XaZ7EcwkW|nSg+V{5uB;PfI;2&(9TC-g$}r9NAvOVeIY<*oMYDU2HDF zh`MK6?@eVzHJjDig5lanh<|2USnD3oey%IzgH%q-6SKY7dz;G=H=6(=bcXKQI<}HC z!(e2^6fL}K+kj2)J60{s-eg%`v2X0VW8Qm5mEMorQh}9yveBYO*{5{cg|qfU#?+&L zGFo^l@u+PFG_a8e9JWt68(0LK8*vpn2UoarS{7XwvDuZGFLnb#)8c=X_vMKLg>w0P zo|sEl43gspi5WtXJZO-Z1z|l2WR`=(kzTQnsVrp^psR32?M&aqmwvY1a7~tkD%f`} zrwiA9(1RT;>jL|MQ$lA6(AE4)OHriiwG_lawhx|m(A0!@`ahwRt){a2oxGMEsO6({ z{PKirpjlNblj~JW;$hX2f^E`a*_baTc+2w=+|We8MRkd}2&rm#KBS>PE;OfYh2hF` z*H-QfSsj`cC|6@ERV;Wm9Yy8$feT<8$+5xn^DATAQ5%VAyaVfs1m%G+9SVZpp<-hO zmPO8zUdl__8sbWGOyx$LS72=e5;X=mdiN1=$yt@2y>;$ZsI9r6$PV!^;ydv`yI z=!O)y?Q%pN*Bj@D6DqMT*>#Z(3=e?rW}a*vEcSWm0`%skP%>U%r@P|ciLTJ^6b4Ly zGVwB$q|b+bzS2)9b?EtX>3Y#I!J!A3@&dphKVL})JfpjmBh;%RzLGB;GApH>(Ulah zvPyn^usB+1kpF{gc;^+;V01@1?|=yLnJzp6{8NiRqmsgV^?8_Y>-|DzRwda?;5-Be zb9^vYn8Z!Ore52oLeEdK?f~H68_eCa8}ZO!G;`aURki$Q)n4^*2^r9Ple9T*3zqYH zelB&+G;NK3E4jk3=}yO8mBR9vO8q9C{KOEkchblJ?_<_gyeF20lJNu@WO<0#*9(`Z z#*D29CJ2aGe$cutx?L33O(oWh%3g}YPi$iwdvA3vy}Z*>$zh5y;87Tf*ce2*#O?-3 z1d-xE_G3vlpA~E%qXvIl2g|{60mp~pIN!Dh=ui{Xp;#mWwyLwL;4R`&H(<6jMvvZF zS5Q1ds$4xYx{_F1Sd^c<*^I{?y=^pJ?cLy+w=1!$aC=5_?K{B66}4872mbHImqdqf^tAWp;TwX2u>YJr&9 z`)VMrB6+9N5oAvVlDEaZb$AyKwM&$n@^=N|KreVVtb88Wt`|4aO~UJB(;e_(Cv z5uxtxZ2V$u<(fGdE&2glv$uiL;=!VMtLJh5x@6@d*sAo94wDrhNFVRUazc46c`Ler z9+p)?hXQ|e^Xu8<=E>RjI~vio0xT6$i9pKn+o*m?wzkB{i-w7*M(!=!w1dd64HJjy z-YWe>{$`jsYm{9D(te+3xov0mXWYH-E^T#~{TaNxluSpvW8Ot z703?{7p5MJ2yKLxAlJ*0FdI^tVfDTPG$*hAEUE(M3S%D_hLRytlNu) zMtT|iZ52T@H6(4*&72j%6AuJeq2fs z!9~jaOX+1c5XJ-^n1wI>VpDe#HP$zlgI}!xh8LfN+B{m7)O}HV9!x{Ee zah0j`!KNu2?_KIUXVe|RTq@mU&hU0EtwVZT*s$XQ`x6ul$x0-+u9WNMI*iV`UJ!?? zwC!UE{XSi=V>p(9fchksirmYR%bO@qscn~TdVne4yOi-R^kFqd=bw_F3)ic2CzYNB8H$Ap526cf=J) z{7rDvBOeys;D}~b+8(2U%iyWQp3x#8BV2|wxx?7IgRKrtb`bgKNYR>sXa!o3RAntU z)qi=j{BEqDitFQBAl}J|qeS5pnUShSY+9AH{JbRWb#j>t*+CnlCq|d*AT*10W~BJ>H0YdPKrm~*kcvWdy(mQ2;o)J) z%3*Y&Sgh&8Y_$5jC>R2wC&cvXb@m~mbz7pt>dx|Qx@8xz@C!;0MY3^a{V>knFoAEU@_4eK19X zNE&8LADg&ee&o7vKa3!M+9Ow82S=)2Dctir8|Fu-`&zA>-in*kD}DCJj#go6FCY7? z*0P_gpSennkVpi^A^EdbA!~ZF@>z)NG&sa--@$pr1;>tL<+(7=NtVirB{+LXYj1>~j<7#7FwfAa=tb`$X6p=(AM zPWgo!LRw-+?UG5;(A7NS6Ri-62{+bzL;FB~3Wi|PeM$lzA-m7`bE1XG*k&Mu(fxx(Z~t8Rm* z&9>nnwnwqX=wb(Y@!vG=tp$$ExHhOz71I&Q3jr3|gUstp+oX?%KsF zWp8(ZS5ctCyal?N0w}Q7V0#qOb{8v`|K43-NlyVIFR*P*t8v@0D{&~`md|t-n9)-p zs;7o1v>_1%rdES+(<x{m!<@TTQ$88 zK{aS|7!@x<7!ym;zA`Yd7?peda(Yl0;XDmAl3s%aYz8cmyTnA;M#NU*wFSZg789P` zu@0Np2346BsJTnCQ1W6}elsW(W*8BNf`clJP%(Cc4JM;5USeNZ zz8b`^I1PsxIj#%AQj(QFpcZI40HztXlw!LQ+W{#1=dfJTh3;;IDTVu!yo@?^5Er79 zPF$x80FO&-Qdm9&|5Ma=*8#b$OSm)nH0u}6)#?$@svOjVxG`fw!o0yoC7>D{lK>kx z0`48Lz65gz3=DsQ1>46pat1{OOYaoWN<}Ht<)1@BpTyH3&FyBOBvxM4KlaOk5Zqpj zirX)b3B%j;G~$fO{|w`moo2&AvLPbm;AopF7es)lJnrye>$r_|2#7*zsDxqOZvvFaeOa7xk$0Wvt_1Y6y z1Yd8S4}Xf!1^VZhB<0=^7;cbL7L*;7u1WteXmkuKE1Pc`7u{Is)!9s^B$zp(lwX7L z1xlsFm%)i%(38)fX+2z{baY4}K(c}ETaHG3Ns3Y{|3OFlS<>UExElT;mR-S64Rl-qhWEmt2z+*k#1yJXGa zMZO*R6SNdBaSx&_nDHTLW)s5PSo{0B;xrp{K;CAiV-4J>c<6|H+DudK_w44nYtd0z zWnBu{-iScZ&jOMTE5?$?7ZeXK0f>PRC80^WhxumDR8GSu}uLkk3X2*cLb- zErW4PT3XIwTXv#+5{?3Wo(FuETT*yxO_u=K9za;I_W`(u5|v>y@@Jt$Sqe`*(^G<{ zp9n%pRK;;ZoWoFb(B4)=cv50<%Q{Cb6d=wVK9X>&Ir5AcDtQn2KX7B(TZ#!uNkb`1 z4N;bWev~L%a3ea$G@K)9=a8%o3riP5sRCB2v2fahMK9ZiQMxo_TUvm#p3xdUCm1E^ zarSFkBOeWRH_C>G`_Z!$MArMdY)cJV#BQwBZl8Qx@m4s*ZBpM%AWAzb0z~&Y!2zpX zNqvFJn*C%a=Axy7BPB>~?diP-d4OpRiKY2oz6^Q03OCZLQH3Ov`SX>SOgNXk;htXv zlAVp}80j5#%=W2{cx8RpIyA4-@2TO$05(UG(y3na5zQ$U8H9vI%Nh zWx1b72^BmT6rKPq>yO*3Qtr8V%g-7GEB7zpFw z{)y}YJdNxOskoS08>jIjtK3B{Jy2@d=*>7OOJ}9hIgCsJHcJUmd@0*dq2DBKhUIhw ze$c+8AvY~s_d3XRH<8Vwf#;6<#EI|KBv_Op!+7e)fVrIt-+On#Nof;Y7v^R{Sv=m4 zz#^5yW=zGy?H%}J0l#BIV|Rxh8iL*y2%hfFYvX$^U>QUF84cikCaBdLP(?SUQ<{_Vb~ ztuUhg!&z2{h7F(bsG3>u3)YtCB~W!m*z{nOvPm^T**QrNHpQ-UuKNPgcNDmfbf55s zE$iB^#*rQ4GVAtZ#kC(&@~Ux;U!s)faZW|6VMBwr)yOes+oF^gp+JcKB)WoZf(<;~ z@|M!(hVjs8CJ08P-(gV}1e>qu1>?>BCPweEemU*vuRJBT*)xo5s-$zAf<9QR_^e>%x=dxuFt{Zp9(_-V& zndh|JWqy;=97*+=wwjhZciyp#Wb(34`O9YBv25vsg-@G(5AZLCXYz#N;=+bBa`Oj| zVAXqyJp3-#z#TeDwL3EK^%H@T?0Aho#J+p@xFyO@+RPiTtPRL{33MJroPWV(G=XlO z&GkNMufX9D*zEE(LyA6|jyNa})Bif*dj8x^smFB3zeIVC$DDOgGgNz`(20exRQX>6N+G+M~jR#(+O(VIe&Bg4k1*h4T8hK$7olJMt z%C$*UqVLzrr<3UYVlzT+0J}q1(-B?ro@6?NX4J};lWD(`|H))Y~o?n*m*?rxL8%vA>89{IU_gs zqR~LHR@MQ(LqGQxqm$pE<`+<9Y|wa<6l4O7DPeCE@&~Kg1qr@F>=j@yM;(LIp#PRC zz+N`;)7243_2>DcGDhKMpXOk2s-y(D=Ij&)S^&_^b7F&BM+|lD`0PvkTAz~pH*y*s^2lv_H)}`)pg>Upf3g|4 zxNR@@1)4N&`+N!heHj36Z47Roy?wrAKXqg{SIyt(Bw4rEh693Qy|a8iRm56w(QE<( ztK%i?L+DmEfa{<)%^BFlt|Q>o7^#WnXmP1{s_j7eZoa)4UgB(mMy&+VUT5{D{iimu z?@{O6uETO_ZoI%Ybjf=&=(vn#gvgjv zb{I~9X^`fc**9GulyO5?GdqB|9(`#)bfzx=ed$iUji^<9(V}Ly67p4F`edI?eS)4Tm1G*5E{L15J+!B+y0<%j8NCbW% z{I~>-``RaVgK+X<>LQsWvx)tEA0cmVkW>28g1An0GU9ev-Y?9&z&Zo+wEnQu_t`JM z(4THIm4JZB$C`t(B;g}g5Rk`7)K23A@)`+pUNckn%3n$}6RGCC@=2ulQ{4MIXNDGk z8yaB_sl!tcbEvP~l~#&c`EV+O01+%|0MqYVOCL%UX{7M5GF= zUT1w;Gh4bh+F`5Nj3JsqGptLUf-l}$=4=OyLn$(nF^=b8WN2Dtm5Ie4@oYQ7sm&tNM{{U&;)`Eq*ti` z=fuOcpTmPhQrK8Xdc!DUY@FqsH5v4FY93S{e{`Baf1B4h(>W7)xmw-~XEVzL53@+Q z_fEP`7&_e<-H4BUBR>Pkg&~QJa_t8A%r!HD$hsZ-_288lRmMv$3TWi+`5?(n zUXO81>JW0kjFK-k3GlHR6WLLgTLu}Lket3)q1gH+Duoa`xTZP+KIsK;XXB}&$frFi zCwxu2^X`ijIGzIl_ybYF22VR zb~XHTS$8TN-qn-RM>={^adP7;G&P35bpDbxM8M@&XhynZca`&>ihBWVwhDlhrvL*} z>XP%YUd^}wFJzJE8$rYf<-!H_I`rJhH9RGU(aES=%v+^9nFe9M$kdSph z!Vz=B^&230;@9Pq$^}4r`E_|JqG3jrwH$Pp|3R;rxpG9xnm$P z6MBJrRehaF$4$O~s3=>Yw!6TtqE=mFu68d8pozEu?`Wef&^S#y+7i?NmCro=79s%lBu|3F)mc_res2cy9zKdk*lJ50iQ;z%}wev#4!! zC+q5p^O3=lgEqkE6EgWanG5yz+Sv)^n}EIaFn`me?o0Rx@Hf&O5&9JSkK8+(-hKZC zSfT|-9v;Ryz!*6RQZu|jlvP~Ykf0n73y|v1BK|Gk`q-X;kV&-EqL2#`hBye10=_Fn zODxbpiYPHwMZ7{<2;0H>z4E1OIwHP_&5rQp1{V3|CibYDJAn2Vn?PhHPZ~gX&2D19 zg?*46C#|%@NXkD`P3%(mgJtpfoOK5<;W^D=&kIv`a-=ukI~LAd&OZo>R)()_`1(Y( zV=_I!_X<(w-~s+YY-08DtQ@*LHzu};mE(apJ9HukC9X!?6g%3a#xxFDT>Ju;6x^m?JE`Z+4T-E_|B>3xo+Q=qhb8Z8v zM8H!CTr5olY9yizkngk6(OzSCQHD79@+lB}f(zWV1YRk@GpcJMe#<$g%k}7<*@(*H z$7(w$xz*XW6$OA9n9x5u@Zz|XE?CW4ZxO7~*tP)oz6vD^=V0}R{WD?SD4lIs!y)i5 zd<)*dRyI1KH3pG~n^Hj1K|my5sU|`mFvh1f3OQJs%GO*uz^<>w1gpC$3Z55#7{mIX< zJU%uAwW=Wt@p!GAYwBhWW=L^4(3JOy-*7x2BfQV1S!fp|2#X2s-uxfwwBH9 ztqQ~hin2Kn$pwD7xu68Z&5=!rI^DpBk3snl{oA%ae71SNzKIlN;oK@RVzc-DCJui|Emfjitg z=h&7NLa!qP(A+tkQeOc*B*Dt~&sbNvJk~NjYT&W}2K^AUt4i0zu7HU|Su4R;mvr2) zG_kWf( zD3 zb%UBqdnyfW2iw zp=VEry=Q`Q{!p5C9~j3mm@I?`h&p&m&|buOHY?zA+hz+AKrMI^BX9-xY%Un$jm+l# zp0B+)#D&8zM&#%;RRxb?0Fr*?b*6SoqqX=+S}yuss+KGMPwsZ~!kD0`T`=Kn z^uiO(d;rY<(GTRDjt5K%v6uX@J~;VD3fw=awWQx!s7#XZ(@j{$U*Qv+x=K4Xl^Co` zagXF}Ou0$sw8WLhJl)CY0O?3BzOc)lA=)}mHIyE{*R%qk_SGk9gn^vW)e0V5Zzbq0 z)m@_P$|*j>u2uPcX9uEz+l)FoEAWbvHzQ4@Bn|wkufU^Zji2Lgcv`ewI~8Glae1gX zcm1GFBQPi{U#kXfD$^@1+}}CM34W_+t%=jIwD>l`+3&Mbb6IIwc@Zqwb?Awyx!738 zU2X7~iXrr4hPw(Xgbuit52HCn3ChZV!AF#}s;E_)sPqY}0<5+WkNLg;j{qtlm`Mch znLi;Hse$!ppu-7=&kja``9B~R4X3@lH`t#d{LsZ+=Ek(3UYTA}p^hOG=q(@KVoZ3I zgCEs3^1Yiqd%ZCGm8iOgC8fSyaohvfYQtNM4=iw^tE|iFyUm`!6}{FSc#C3SUWN}% zIf$mL)SBYfni2)w#6Z>V?YR5?bXO_JL-?}mul~27$&ErZG5#exj=PIP$L0w3Q zHNg{MGqfsd5kBh_drwV*5>0un6a!e7%T15auP1o7-#3wmbaE2nxQ**qrcUy4cLFZO z7VaK838UoxOcxLGbsq7Xu@Wf1&#DcXMJoUBKC9l2>h!t28~RMjxR*$hE5b6v5nJ0n1Orh3;mDKVy?{uoJ1pd*l`j_tR8(z7j!M4d-q*O z9-N8g)Dbjy5WmIaal~;vkvKTyihoCVa1gFS(7qw~wxpF4smiRA=Z>Iv*jt$b^X(bN z5sneIK9sU^`#940PR)oKe>{&&d{*_x$6%fpfHwEX^LWH3kP|2Ezubv)5ATtiM$pWD zJYXfa3;H9bnpn&`oU=V1Wh^L@R)e_Hbh>wocnX6-r#uw7f{5t*FAMg|?29@soFV)L z&Q4Um#($mSjgSG^0X-aBO6o4}YGUiPUQ97QhwZQ0y}2p|B795*8JMkwMv6Q7pgK^B z+w9*(cbsN#2JTe{5(FjN7ThIB00bZ=kTCShuZdMvUJVN-Dh~lDB`T}2elTSt$fX3D zT%b!6l^-Cvi^^LXj0zfAB_C6L6AR;mC@OkCUW-Cuu%M`Ad)0i0xFbn9>lY!_>6A|( zaZajfVnx{I*YNTNt-KDmBY~qs-MytsmnT0xl4g{aKk$aS(s;RsFImBzGv{{r@zROlce(@%sQSJ=;(_lXr35yVg9cI1_ai&v`>CN`ZlZqvBMFS~f$ zdhru3h>gHX;U5zS=yD^F5y2u0qBP5HQ?BSJtg{c=QdQg`0Q7E>Xhqx(-D2^xtdbW| z(`px$;_j^AUa8#mfTE=)h(F1=-w&O_Opv~8@{9)_9)TRMuqXD>&-mrI6jr>iVD~r1 zZSs4g==0$EN-d-}guCVFJLpi|Ng&zpx`XyXN6FqV&$xqb&$@s)kPn1TY~My-=6suc zK$L&;y|DfMhd2;T?tdrEt+qT*;{;G1Zi-ZAmeB<~c`__lETtvh40N$`SSqCf%uBYW z^>AvQV~+*1F$GF4sc)PjLsyWZ@r;?@F@ggt8NqJOv1vh*;w>V|eViVGyLd?TyUwxF z;0;J!Qxp=NR^#r+eL9GbuL15tehpUWx2sQGHANNdBm+L$S?G?Ezq^xKhu>fygh<=Er(V0kUgs!7d;z+V3g@u)(kouOy&qTK>XmmRIqsaRdi?;@^aa#J9?cLO zgIoF~KypOfRD}H}a)W`iaLZ^qA`SJ0U`)1kHfB1`wOFqj3`1NuSYB7PZ#3N|i1ErB zUDYq#MW>@DD2-ik9{i!I?Ot=D@?)2LX)G0z{DG{4@bRc#Z{icvusAcCn*#_kDY0g{d1h+FKo2=`*+ z5vcAAbKkXFEKiHl>Knn}|8$Gpi~t&kb~#bQZvpNQ*`2-?sQ#e@deOKR#=4S0z2PA( ztfQ+sZ9M%zh;3p0k!jR2)2qL8(%bn>h&69cq{|RwV6iH{Fp&;VyuzCBQlD*HfN+GI zr$5Foe?5_2hlS&zT6xzb`U1*kg8BDexn^j~ z<8{V9wsFj@TJ4tRqiuvVD+O@>0b<)SD`iHP>b?5lX(N&S690A?S};6+Ck3tAzX#-Le6}M zW{$ndJ`Z)5i-H#@F_*c?wS&UEjK(W(3OCuiJ;!p*Y56a;_BJ2*wag7y&}|J@4xx_d zh`jnC+9bv*S&`~F)9Kr~_)BbMKz}o~EE!sWOYHgT*ctT2D6x}yx~jK4MiJQk4EwxG zKJqwyE;j}=var8NF^W4<<~G8{W(o^Ad?_W`jyLD*#A2gpAQs-G@-uEanpUWCm7A6f zr^>!i3=q&U%7t+EHa;gIp5WYx659nQnHO9HL*i;gOFfMZa0-BaSt-9MZ%DE!$JA<6Ep{@62uB#sHKKtcy*`JgYt~-ls+iG+?`Saa@9iE=2}>KKvovg z8AuI{$Ws^5k@*-wuz(P$h279BAua5;8qFcRsN7*{pP-L%xYwmR`k@m)9*}n}qGK^W zCI{rsMRan}Wd=Dyn{P$OG(AB1E1jBB`XP96vl_`Msy8 zHI<)m5I@&NFumYcd5KCRV8A>66umw1INPBbpe#Gi&OuproW~pL=b>rH|3uXzlIOgP zoqkG=gDF~edZ=soakfEC+c_O2|DX!l+@ZYV*ZiF}$Ug{ETx@e0eTDvkD1X1YS37UA zDxdVwyh%>pLWFjXuK5hNv_9b*Q?1)!FB;Q!~xYJ$gcFr%IKjCoi3t*<`Z{>xW z)r+hZzcxUM`F>IC3i-u-g3J9bKD|Gp{ z=cv`2QQFsOc2hWH7eh`d-<|I4QyP_CirMe;V9JE4E&;2sRA=&}2KC^;%(?cCgNx&p z_kymumi_V0q9@1`tHue90)_w|2A17Lw@xI)I!%+tP5)qSyz)xWhjM!7S5K7xf8~5$ zQCOHHNa)yw!Wr!FwH3#$Tfodhdh-Q)0=#OEv9$mdf@^33hXo2*@tM=`CV4mFTDQnj zI!HJq4_ZcZ`+qdw+~`4QNn_ohvPAb2W%s+2vC0ypQiuSY%l4UN^b29CY+VlT%Y6Bs z<ynO`S}%eYx)h4%W($|e%P0S z02EmM{n&Mm%@4_WD`8)bRt|*ZNh_&@)zuNr>%S13M4jwYlzSKD#)RZGD{0}#PPT5} z6r~;wvyZ&NKHkR>J?B{Re(qo2$)@h-m>!sb_H%6FdIv`)o@4s`)g3Eoh9LYwj`z}0 z;7l0r#SHNm0r9x-hOsjwmk!qwLq>F zm4DhjO$fQBItbNuG0L31-RZ4JpF{}2m+>__#%9X*yi5o6KL*njS2@}+@QPsHn$r1r z3Ewxgk0Hlcq5Rs*bU^$uSOIvZzWq2d`^n$DOs9y)*v*ifvX+k29R(Tal(qD+5m8F2 z>a5|CW4vms0lN<6k0}n`qOc(1o$wVv#;`c$m;DPsLc!70bN0xW*V2Po$Cyp?nbHjz zJY_IKL)fk4=4#I|))x^C$;}s$N|XPyj%J}}&kD-7)=^jAW3Z7`vZjar?Cm(<`Q;*OP!)8lktl&5jIfGgSC= zKUdUCy`bpuAT(2$uK}QT)b>5&|8VZna~b^0bdSrO0XL=*fH=HL9YU4-)~j?7wCh7) zeYnE@4ch__vBlqW1;Y7Ufp;tX%aW&brg%i(xLbNlct5GM_k%!KNo;UOT>@Me zNjAwJ4X;Vt(JL_Gh*-MgfA1@}&xUK$AnuR5Wx%;;VDb;(gfaoknU*}U_@BFW1#h%Z zmhag}lOC((dVvPa4T~*46~5h9*q2>IaF^plHCvEui+5ze0)#SLnP*!pprOyBp)dzP z1`VT=gA2dorvkxEHt7`#p`bM^Ah!4CHD}bfp<~^CTRrrN+vWWmF~q0KH#gF`DYedG zcZ{Q=D#4*^PmUUyNq01}Y7iCv86brQsrubNLm-ZeaBRht^;NGplHR+&6tUQ783N$l zrpj+tV3c2h9zbrWpksv;IertpE$}P-9 znzH}O&dpFSJ2mOt*(04dvs%A=Vhb&t)Xd)XlWeYiq|i5B^mAFenX~UIe^=YkW7BGM zl|;dnwET5Y4Ilgn!t(T3pKdE>#B5`~LCgM)zm0_h@{BhCbZLXbgZ%0n_>8r&f8hi3 z1}z-k#{L?>nB|JZwYpE-;IAL9(S957!AXW+VKYne_ktN~X3upX&lSE&=R5+i&K?8q zx{bZIkGlXgvqpq>WQc7ThxCsKL*K8a5NPb=p7Xv&o2PfBaS}GfTj*}{9?Uq|FQUy4 zi@rk4Kz6isI99=LV)fm|9tg_)WK1V*%m6NLnU1-$4UuMextpk~1rF-F8Zmo86O*of z(E=+ra-018IBd$ckI)bKf|lRW%zg4dWtusujdj9gaI0u_l>wTLW^@6P%~>}2^IfKP zw<#C3)CIer?c$!i{%B_>?4{)o>Y#9*g%aERa&{#hhqf*D%L^*$2;k$b&1?flBJ=*TlXKFLoC!G?nahdtB?rCI3=@ZGum6H?iGeIddzW zfGGyNsGhA*Beb#J0P(l6w*$}hYj3g5uhn%V9>S zdIFY(zxwmE2?k8B*xOzsD{s-MF-KTNWS;Nx`~c$F$&=pJ`V(Rvtw0KD(AtpXnp(r( z$CS=iPoYbfIk^K9t8|2&3d`TVO&`fT!aj%UM*H?z$)+|C&Ot)j^aR=$=QL%uv5b&B z?j4$$I&Ux49BH?#>sA3T2Aqzod6&OK2hq9v1be-`m*FI7@s{C*|-vGy_klD!2Ad%;I0JyI&UAG!CT$>;#u zN1};sfz|(^(*N6kH7FOpPsgR;Wd^I<_3cLRWp@YrXksoze|ewgB*rSnt`SbbU8LBH z5L8kDRobEV=?HWnTky>fXfj9@Zvpc60Uev&#DanC?l{~g?exv57*}4zC;s|kQdbX% zODi6rvszyE0d;sipK&t*RoY-U1G2lLeva5)4^_+@^(>fB#P$n>R0Ol)JFd?GexN8Q zon;?K#G8tTRK#Y*-};I2+*stkgL%N7=nFCUQiz+s%D& z{x82siwVU|=11A+y?jc2TOZ${-j8ms#`{QxHH$aV3fX}lTZ3cL9DYmPw*w%6HzH^= zu}2?&i%@=F-S^bqQn;I=9nYxK_4wU`--Aa%-W37k49D$Aj-yNmh!O8pN3odWc|7IU zmQsaw4#YUhIuP|CJOyZlP24*JljwsWY?)`n%$EEHeqL0Y{A_%O{n3KiaL)+X+@9HR zK`8hY*c+$oS5=gzy3ER4|3!9h=oFh5ya<+aqO3u=s@W%*3MK3dNGr36^!|b-_A+|j zbJ#DKQ;79mb&&gpm>P`IQMix+_!qEutcGe~7SeN33QuE=*E8oNTZOep6ZZ#2>>$SURL2SSY8T&Y4;_LAA==X`6pu2G-ymIsS`9WZ-n_Y2;lapRrtMx_Vh*Ob41UqM5hzp;QwZt!jxDp5 zxdyFEWutoyK)#uuI!}r@xM;wSI_9;onK;&ov@$OQQ$JDK zkS=)4tbD7My~>G|*FoD9-C)8~`N;2ugOlIhaT=Nx9mgUnN70yLyrRcRwyb7iB*dF+ z8v9sDoo|$+VTX3bum-=N^W?uhU?Q`e~MQdl2Ij(jf~d$m?) zaiN!+PbCU|4qo&`sQWN4e4TyOLuwt>xUN*$WmHy#lwD_7jh|QKQ=iLFU?x4(j0dbW zt7-qwP z%;MYKJ=;9Zo-NoeHB-Ek*I{2e%69V=y7ghzTF`$*OlH7-7!TYW5IQW-J&L&->4GB%x1fe5#rWL5qX>Lg$X!fyM9;ku%0PH7< z6EOt=n(O6EnNY8iDn9@58IGG+xfIORLL7|013JW?@H^B5g%6~mVWb&;&NGI^)L#_yh$s??M54VOtUI$|C*-tN;^VCyIhRh}M-#?-E zc%#TH;v%!j95R>8Bae|kk;jRf%qI)T6J#M-M4lv1!5LsNd73;!mXK#jBRNcdAxFqj za*P}&C&;hlBsoQz$Qj}zmx)5!Ne8(>I^j$)MVKmV6#gu{Ccw8$*eq-j-VojtWMQkY zO?X>)M|f9wPuT7i-bc8xYGDt83GYSF;aZ_is29Exz81a_4hpA)CZSn4Eu0a~3g?9L z!Uf@?a7kzpE(_O%R-sM!4LF;2p+mSK+!7G$P6!H3x-+_qx=Xqi-4)$c-8J2HU8}B5 z_nS`9wd+z+Qd81W?n)V#GCt+rlm}BDN|}}7b*0QsS(EZo%8&Y=^^N)?`v2$~^vCrl z^uOv)>i6^mFd7a4QEz-yEn=#4!A^9u$jQpMKA|H_* z$;N7kFbMOE&9z-JklVNpgw1w@<~76-Qw&D2as zz;STJCBvH)E_DajammKAK+7`qmX`HcSCj6)doPu@gfu}#u*GmIz+KbErBo0cP<+lX z%*^}!9q51m@B8xk4Ci^C^PJ~A=bUH#E#Gg?(0gH;&YG^#ouj)(2Sf0-C#4L2FAm$~fQ)*!)qwGv46J415;PSt zyaC-C3Cj!iMI-NbS(kZ3hd%>$gDR%v24Lh6F3`w92PYkza%i&NbeY$;+3na;7>7Fq z43uvML})dt{NKW?L4a2ML@Oy~zKOQ&9WUBz{|k_*-gs9-5u5a-G;Z)8@O{P778;E^ ztz?hc%%8@V;ChYlQ8TZB=e%tEz(ydqf^nOA+|{s=o%&Mh7x@QIX+wtxQXE}05k7VM zSlDiuNdCdKz^J-j;{f;|$HwN9TcrIYkNlR_6w6qw&#K@5+I~l7pr9t zvMy4Oly?#wuSmmv@4kNB@^9x%nC*NcT~{&7u@0=#dQgPTo@jg(*p%q@U5dpNO|{Nt zN14Y1Qa%ELdy+T0xO@5Jhq9r2`6$C_tlx*=e-B?SD)lHpzOXR-Ce(e^pMlhHpJcei zzor#Fj%j`gojTJ;?wtW%5wPKPj&bWH$sxM$iQpl{g#M1F@Ks&eHPF%I!Uj~joa+oW zdoY-Ux_|aRN`-ysqk@mOWx$l2ZeI<{z|;H`zG?UJ=>0Xr;`UwVNmzbCZH3(L`cm1T z|45Pf{cS<6cItzGX@s$_?LN5iurukhA-xm)R(BXu3j0jZ=USSd>JpPHnI=CBGKwg6 zvyX~jXJiyj{Ee%A?KLO821CAG9Xp&~3P~pKpL*S#V z{#yDD!0l%}`m$gcOZ?(vpX`zP!fSQ5H?>Rv5m0E0eVMzY4i*5UZn=78G}dWFZS3|Q zY1BX&T*R)jnLy84YnM!9=~c(y1fMNz!kUh0BhH33Nx_mS$Vk_}9AGnwVM>37J6hS6 zVwjPf;m@|Ry~Wbr{33dEOa%YIBa;mNKivfD)0h-!lK9iOClwO{y_#QO)AJF|{Q|q5 zk8uP%n{`O2U`+(>jGlt2KX0&P{of!YeNM}2z%o$!) zHVA1$1Pi-WB1Ph*`4r|ak=DT1a&dsY_6^KBu0j3@(Ue0>40oS|fBZL6T=#JI-&zOd z3Gi{(8h+tP#Bgw zoZ+^qR_gV$tYIBJ5_C8LA~|V(_YC;kZ{xQZ5Bn;9f5Yz+{Qhhg3JhTOAx^Vxy9>l= zUSB$(D+t`MN^=K$#{gT-m<=0ZwtlZPSaTX0pZ$mSN||u^Wa55lig=Sv-7m%9#M%H` zvR{hT*YZVyzAujk+ibRQ8ez75zqEYrX+9{>_f<+=gVcTjq0fR>XSTlO9&L1_p5_TE znYWhKx_!RrNY6uhkN>8l`vo`Iac!r-lS64QlxjWAwNRb4hok^oR4PUHJLzj?@MC=zLDeinW}itUb1;dkWgKx?COq#Hj_GNFkPo&?LLG&1EhZ!ITI zIU-WRYlg&jFRWSj!Zu{@HpjSO*z@km%-syeDE8?ADJg1A6ci$YUK#%gd63D*)BHp^ zyL3PrB93Gc2cre9>cpn(>a8&ncK3(&X=tq`Oqp+Z6<9$Y}15`xrG5^ABHUp}v zMUmLW0n-2`gVaswXS3)&3UDckoc$~0L?O}9SeX-guu+N?%&CAykE#esmXiq_ z{VFdEoE(2@f}02X?*UebChD6Yk}b#5fK*48k~h;!D^jh}= z$C*=B!ImA8x`mX$D2{|9>)5-8q(S++ZM(DnWBX6m0(f}*-WIe+P?a%8YoQHTjFOlz z-4W>!k^%`IINo0tn)KO(v&*8LkRB$Sc0?|lzDzc~2e)@)Hu!>CzCz3V2D{u;XfnRU z3;B=grIltGc1yqSEtT9x(^9gsU6O!tTs^DLx6u1K&6z5cg?KLMHK1VM1hB!~we7Zo z*=KJ9lzm%({+9%Dlq9&|0j;M=!7bLP6kysWj_|5Bq0cP1pk-5cHnn%?MQvo@t2H-Y zo~d337M`Z@$eY_n)zCIg5b)Xm(#8&#W3W5TC!zMiNbZU(<2teoL3j-OK?MM$YTeiU zRE;fx#c|Sre_tkEN8oTcXHOLR2+2u6e67^>J?o4Mlw5yCDi%!>@Oh5{`#n9bvcxbO z(2a(t;%tuEl0r4S!J(Ao$C+jycX)Ah<5l;P@-x>=FIOmQAig0B&o)iozC_`-GNH#v=_TeR-u+UR778_ zpehsmWO`YrR%ObAu9oIJ6UO4McVW&ajGR?xPi1wgdUD*kqxc@SP9v=V$v}PBB^3;_h9qkAn@oAeb6)A zToDg5VO#X0cE3l;O|{nY-Cp|tzIQd;Cu(6NIn1dqrqBo8#c_~xu`(1W9%Yv+q@MX# z5(JmNJOSG=RXu2^^Ts+g)5=}`(_*;B-Gy`?rJkUKFp6f#zCIn=OV8J z27sYYM6=TYQ}S_o2uz8x>26@HeY-sX*f3GhRMXMY92R*3*VEZ6fg|<{ID0i9=BuZ# z0>OUkibHDgzXliB`?-L{9b9SegX2lW599a);s*i{odA z*WkDV@r>(0tU-Jl?_6)^L51yna*?x(6Ko02Rbs;HmY9q#j_~ATfc^cO zcY(7D)($!uaA$2oVkC^T3*deW3F*)=89C7c=8X5^s!Oi&^}zE(K7nA--gq*oseds1 zjaH>PZDq9b$a7*WFcdk(gdpQZ{)Q6;k{l(XjCtooZ5KUy5`x`7e?eN~d z%>M|@E z5?I)Xkw?PPEgEr3q9NYEcc!)0q^-TmR+kn0yn6t1V*R0p&*RK~O!my8#O&V+3N)f&yQHgud)Y{t^wXkO)3D#-0DEU34l&<;U zkV1Egnqg|658qP~2caV+PQye!EB;uC&~jHLNr7XfCJ4Z_0-jk~E%qgHDsh=$GQ%Ey zg}+-_I3%E=D;#ps5AotHc=0YdTS+qPK?4+w7x;w0hj{JL2hlHNp{c*LHg1}dlv*`A z-%u>5&2I{t-yT%OIX&qAG`;=45+}u}>79i7VcDEiya|A4yY@KGj0ci&WH&UkB>nNc z?=00?%^3$);DWJ+KclQH{vit{7^y$NLBR;5l*gC1w2hFm&0zUcqcoQ``0(|RS*5QXRaRDHfrJs+sgS84mRgJHFf=lj)vII9b!YtSIz zgO##dKS+-ZzXXNKC7$U0yrXewIvU4S?DeS2-S!n`RlOEn90Z3wKTKB4P_g5iT4LCg zA7KGd&Cge`RX<9pk&Bi4P++`n-G~W3xj^^`UxStXDD@oKz?ZZVhR05@BFNi|ikI3X z!b3N7Ss2=Kbw!Lr0=TycoC~RXaqAXkfL_=N`_BX-05&U3e^g4#ujN~Oom|tg!gv!x zLjWBmq%RTP8)QviECZ#D!RI=(xh$4Ete|f)=H=pb=+`TK^rMR>Lm{Ry-sk>6j`cqO z#xuKkWY)C8k$B&h<}cD>@z%-Fq?Y&gJZ_`bCZ=?~Xos2Qf1BFLL9@D{odwZDPx-U8 z)$sil?A%eQ@1yszeZS9_LpZ#v*zQampP2P}+~tz4id;EW>960a3@`xAJmGWaOg!+k zg`%;RZ}KIuM}LC&@cjS~O{my0_xac|HMAC{+y-IXg})2p5BMpV-2UA1(q8Z==C>T^ zqiC;4_O+@Di)z0q7%=f=laCnLbP}WuvC7f*i1v&$Yp#U5%OPB&0P2P&O#|#R_h0@A z23(RK2A;oKS{YxygO*{WlbDfAZL`^l!_l{WT| zW70}&oKpN26M0|HkZZ9HXUWH(UysL3YK9xtdVOALn;hEzU5O`$?9VE+YN zW5a|C2oqC*8oJ|SA0LNivX);gX9tc;Um+CjXNyiqrnwD#7m&O*I!OB80002G<9gfr zNws{A&j7oz?|`NP4@s!wYSmS?;4V{BhT#s`xPxeX#kK~y$NL7OS+`4@+K+ffM=dW0 zf#3-#x^pd0^-)Q*6zB(wnv>WC-{NNfD$E>|?|mQ3JSjP&YWX>=AN#6{pP;i!NdpH( zSM^DFz|`^)z*PiE%>(n-@pT~)qaP%GEg1(nBs4RtkLgcI-3>LMD5F(%^Sg1@vRek! zsFrU(M75;Q`-hnIl$1Q7hA%iopBl10Yqhq00Ys+NKSv1Gdq@LTg!KkQ0M~%Gl7mlt z4B?$fD?l^3jj%8jzgX4XhwVQlrG%1Ddhxs!Bs+esr>6UdKTFRJY=LQ&V1A)S(;@;6 zuZ8Ondk(R+b0x$?#Byph&Ea!p#9G0)`7<=~VeT7k?9$JGH^jv2ag}KvM!|dxm_)!f zsq++;**6#H)`Iqd-_l9a6E0~n}Gf~8f<@I?uV@`XSBuwbd}rC$<1sfOTQ^@ z1Ik{5S}sD~kzTfUv}QSKD0*36i^hu3udQsQMUxyJ;GaXaaRo*q-?y@VSv2X%VQ>o9 zZ{O2sIpA*0J#YnddeiUr?01jvf}-PpJXHEUzSO(F^B7IKJn0@R*(j+Ie0+2?S^Gix zuP@!xm=`+GwWUEg&=dPa0JM}5=@xjr5MEKHv2KM8enDfHx{JKR7nJFZS1}0h%+xFd zPJ{zEK4Ud= zqMh~ZYB&WXK?=_VWD;F!2IQy)__%}(3+%d9jgV^XQ=@UuZvEV@TSeyrp3m(Y)=_8( z&^U_hN7lh5s#RkhiDd+()e1lEnp05!^L#5d+^fnp?)jcu(6D!c z4NA%ejeEampGVS@XBxm#PfpUrf&Szlpxm3Ju_U(gM!2wS32o(W)uZBIpi!%vmsy5z|xJS zP0?J^$nM|Tm_A!G5%w7P^10dIiEQ9qOW7OQn%$ba+#X;r(b+bY=hU!;$LFwhVB!QN1(8kGjP6tnbd zX=G>l(Db|deu80SRs(;hlx?n--jlEL{>)e-C1C}WP{GF6NTwv(tkQT*#;<}f#Nxmh z93o1BdtJLqCtYothP_1i&kIS6r&h6Le@xlmGIRau#*1H*!7s8J?v$+Mr~ zk;*3PI%}TukYP-Q1K@cP%Zi-mVYY5}7C=7Wm#Elf5&6fTIYN+Qx|+j)948cjQZ-8}KZLuXU>=u`P0HQqtym)o<}uZFJc!Fl z#M|&LOBRf!v)0b7R8qHq2Jg#k$a;U~A%U`4F!bE97Hd?|WOqVyi$&YW)N1(hmd+BI z3{nxcM_0KSHkW0y?9Lh>*@$>Scrkz&%5#>^s^xFCA#R1e66Vx=EuM@Dq3M%~8Sc+4 zD{|`UD@8NdKoS$G`2qN2(sb(w?H;x35ci8%i`t!%k(?KHAa`n+#{HWw)NRAl&s0M3 z^ug%TUZhMzN^Zv!8`?Ri#R>uIT{e1i{SU!R7LzzyzX=TBp* zyTM;z-qTVq+YSD$dQ(iWZXfUE$pm~*2oO&+);NR&_dgM$&lsex4BTtsukXGGqHitq zVj=Fj)hd=W4@@GmEG%&38AOUIcb(Sku5x@K1>CB|C}@$k2i~*JtrCaJitmx18CBZ zl!3{z(E^C2->}@zvtttl>~gsV!UNEX*Ro#cr3@Is&N;8X@(8y6yjoli`_FkPCh`Fg z-XSaOe;MU`8%6Z8Kd_7Efn4-}C;M32c_}UWcWx^?WT?&p*BV^Mi=0p!qY*mGnDv5W z7``KAOvY2u=V3_J0yPG}kAMYJqf{AQo+Av5s?ZvO0Gn_g&dknSa=6#HhhjrO$A7b3 z7vNM688q~qCVWX!rhVA9!TM#^sTefD)k3lzC^m=m!_ZmdS`kVefu=eJvFZL`Yp^Sq z)(tV^GOA+GgKPwq8ua^B+9zo8uGC&!HfYCt{NW-AG~6J z8CuXW*6aCjr4l&M!$wqILl)!a}Kr0BEHe3tC58n|}KhCAHA` zO&MBjsxD*pJX>y7EEGB>L0Tx*ZwRM0brLfE1K6^DCy}$@cXtv+O$Ae6h+>wisZ?z> zd_Q~OryZl1;SQ^qEwgZoAdrFy7Tl`@1mI zKtqtNt*Wn*B%@HjPLSP=0il0J4HX_j719f674@xn9_-W4a#LHkZ>UmzFxf!>2>7%Z z*ZhM&7E@ZU>chpIKNeLgv0XTWCk#f(s?0-nF9_(rQ6JD4;GuzSWpst6df0RnBOr6A zi*A;KC)-EF1iNA(ww;h)rWW@vqf6;I>-b-x8kcEr`mP`dFdmJD5hv|9X?i0f z7jeR zWMS|A3b3PG_W7?;QeVpDSK!i~BqRg?ZKSczM!ueu4`-TiW{7$Qdqd?{$rO8@dwjyj zLEA|O@Fhmf_ArbJ6*lCGG%)cROnb(opM@JjFo=iNP&fkW^h!0gGeQTkc(@|PhhO7g zKq6?vf@`3U?YSZ;y_)$mDz;g+wHXtq!K&?e0VH_NWj|h(9+`ZehnJhJf85-ugzNFK zOxf73#Q-gyE~z-29!=JM&HTXOTuf{dBXQMu(CJ{Z!iS}BWPI)6>7^|FH-NIA z=6zr@{hQPu8kOR}c+5|osPceWpm1k{3l^mmia_YofEieHX^6>&AeT5Gs3y26N`iw3 z&b<#+?0JyhvR{9b`lh=ePd1}<53=H`A*Y6Nij?nK01Tnp@m7Xm$AItul%HOb0jPBAc>CJc##Dm3t|E1dQfi>J@>yQhrWHbKB=Cv}?-_boH9N#@S}Kz02%2+yiZ{- zT9j*EVV-lIXL|@jk8ax8JItyIe%>YN3$=feu8?GfBrL9ZlK339+qw9W7j4e>l3{*_ zl;uHwBE&OEATq^~#4>N-cLu-D5Kq01*NNYSZtd^|Ck-DSfzT$2+8{y`jn zh{bg=vLO*i+V>}d;HpY!?}V-{aIZ#3ocNnyD8(@vWswX(-{HQO-|oNnGk+R3<}{{D z)+z28;Q&OLj^F$EeG})E+Mdr85~sKig;Q9Q5>o$NOjvz*=y27NPmbx`R~CMnd`T&S z82LzWNXv*7GZj;A+M1B&(|ux#N3G6xiix7j?;H*J=WQt#?oNN0VF>|vW z-5eh{lC>_0PSHgL05mW}J7_f1mz{I=a5~0yU;Py7?ik0`+>jExY#?o8f!-+`gkH`h zRJ_fKZ%93QW(0(aHws4(p?c&g{4CZdlqhuj03XV3+>rY9S_1f0V|GZ*;>i&2=@(6& z9{=|-mm}6HU|e%8VEt}N!+Shs18plZF~uT~3k;M8YauCPuiTWTLcHbhu)FNW>^qq_8o+OTA>LKY`8pUFw#y2$J@8{}jhQ*{X*GQ%JgG zIiuB`4F^?Kg5}Z>!5mf5X>vH*h3qDh;*rNP4c*k4Noz(U8Z~LcvEBOB{@ULqyQooM z$;w9ElKM|pfTJb#KXI8>)RI8~)eMQmAUotP>@nJV1SFLxkP0UGjRj0cV$qh{odp58 zqzd?1n9{Na+s<)~mzCaPN{86Mu%?^pKFo3$Tm< zrl-|`HGgYLGh_L}Q`jn!~V6FwR+4xJ)u$TbBBoM0*^AXfQ0N;oRUbton2rRY|Cz7enq* z=;aQL>9|7&9Y5=T2XrQ+AQIeJioSSKvusFriKZTSs75Y>sXQF(Wa2e=tU3=|bAmxS zlY*mYAWMMU*mTggN-Z;&g*r)5Y;p|iGajp>iGP{vIN|&s2dEyL*BuGV!cE&0*%ee@ zpp(3En=7-2x3gbU|9Wta(z)QM5;U^l={QZlhRaznZQn9-&WqU@(X$I*B)=f{+8}Ej zW{PwC3hePg_yJ#hia|=3*k0KM%y$Ro)KC5@^q*b>`4@(g{&Cnz42NcB2e#Htl3>Qp z=11-5v#Cx}UC&5@kYRO@H@xME%%GN;uf2oCg~Ry{mKytB4=~NCC9MhLrIix zQsxJs`IXGcHL0t&12iSLe!W(%-yC{g2@)i45I>N~^PN-N!@_!cwR~~hcttD71MXgN zy!tZ?*7v+hHcK2Rs7qSWlx_M@EkcGpvA{d{0HQ+Po6FAC~R-eHqxWLZ@ z9N^Cu48&CcVEq@cJ|33j=nfhSTSiQDeCC8_s-b@BBj0ypE53G)0UnPNJoLR&)vt8p z41GJ|=TmmTeTBdya>CjF>n@w+3r82#H@Om)2g^0!S(@z%pqr(8frd_*tx&SpenM zIo^zXY2^k~q`=UuRwNBDFPd>+I}4BK1%5iJ8$fB3p_qGlPh4WF&~ySS_X6MmYwM5d z&+%GVn~MXRE|Rr?AP_uqFRN%8i5oWZ_gb0ZE{I2#)cjmRZE>X*m2HM8RZEUzSHr>3 z*X{jswf3dCQp*c35l4D1h`-tzT_i9Z@nvo`NW=_CIn-`;GNL~BWqaQ_2kZ;xc;D{# z`hm9>ye_P!4`+U9nA&RWFJU5nsR|bGqXXu-zcqXo%20yfPRmzBcd{xVmE7@d_POB( zYX(eYV&08;*|}aZ8=Uq_e1|Hc%^hA(hL7$D{6bo9qmY9rL_#5Yl%eS;qs?ochYl2y znmNXvH?P26G>;rtb2}uRm-s3bO+Oy&Y0{MaWznsw}^S6f2Lv0SXnyVDAssQy^3-+|%8p=ac7t*!l^lea6rBJe``0NUMqd`jS zH-9ID#ZT_(sLP|M%d(6-h+}f(=rVVS>^|bl`6ds1!jSv06AeI$BDReqCC(X^xFaPY zDW1#ZZLr^;@{C}jP>r9mW}`y|Lwic$y8&t&M=q*e>2-S42Z^=}J^UJSWXHHQ`#Qrd z@=-9cz&k0bt2YStO7G!}1%S`8dzH^nCKw9~<`ftTR)DMz5>p9Vhh>czNp=s&Snz(j zxnj%%$k+{^7UUKfkq7Q@lQD=-p*=2MJ5Vg+fmUp>x?w;!7EJV*JLglUdMsMo{FfmX ztI_G^IsQ3L%5lzrUYU(q+Rd-~7hs8Ou{QByNNp+Q1wZ5{rU*4W#g9&&?--lmh!Mbm zVL?wjs?dKQ5CVo+y& zoHnK9G<4Rzbbm1v==Q*mpxh=ryd?-#>15qz&HyP8O4}CK)hpxc&;U0fnYHs~W8&Mkn8 z7sfpJy^`|f3exNOT=-=Sh1bqV{D%5dbK6UK5;?CRr>p(yT~1s*0cpP??VN%u^AqY} zv@Ez|a9MBsV*EqwXen-T(gIZ?NL}c*!(eZbid>~gIY^h`su8|1P?~7nU-;|!hXLqZ zzJSiwWwxX5<}VlM#T7uQ{AoqjjAUp>(=0AN~h-}I&C4zo_J=Nd$g zcbxngVajmMr?tM6dwU7`_CmZHsTM4XU@r4b1HaSw4A3iO-d=J}$xYDJTO#GA8StCp zKBCbLJbava9smF$h4pGdXP*Qik`{nbZk~=^zFw$?3PRkPiue^T$#(|+^$Ol{sLEjD z1_UnhbfMf2p$evBD^^*5!*vu6cFAL{b57)sPpQUmsHnoob6N7KEcAi;xg1n(TQ{$+KBzn092N>96;a2* zpYn!Bn%KRL4`~~#3>DPd>Pc8v$NK>+&La&Q6Bh%DC)_&fAoXJcMXBeOLlmaBk1hti zOEg}l8FR5eYXblax>yT9jvcux9*!yjK8iipDjCH}wzgHu?@kT`SYS_H3y3$GC{nQi z?Z1z8_ew*1-EDna7*n@p*$8`qAS7Jn_q_!=OWj(>+qwXMiRF2vM@Bz|C&|MKc8U^$ z=~j!k^nRkXpP+O&{lwkggOBD85+&1-t;2hc2K|XKP{g>0}&QBlykgWKqq%@8BF?QqRG;M zC-;zCt(58^j}8V=l(4{>1xUXy+dAPIeK~FF+*lQg*ka(iRj@L`Z@W016}7=sc_O>g z2C2H9J?4{!OO-p>avuau4Frewu}_M7Iw?e;T5tS+&Ly$m zebU(I2Z_W)C$`L47H*fejknA1VO_yLR#>`U>MOp^7W>g4KV$3tfHZ=lJD}ZO&jq}? zb9ha0VZqz$017I&e?hEQ*z~)-@Lhjb2$*mB-8eMb3WcEgD9@O?@nNCcF9JVc`rY_` z7rDK4>V*)*EgcOsKI|gw!^T~hir!5*>OhoDJv|6_sKOmSQBLK9HB5u(5kwho*gI^h zdeh#>{H1zRaBHEb#v%Sc9XBoy(702_%L2r^HRf(l^_n`kMgCdIsVJw8Z&D{63oH!k z;r!d)KzE@6(P27NvJolq{qisJk}f#d7;fo&|rjx@+cM4~AYUx56H4iIQ+KCsdWS0&AMBPZ!_M%ZeJNNy1$Y&ENtAncI>XD< z1Z*$I6|?^lWn(_(b@iG4JGv@LTCI>YQ+ZUl2+wHrX=p5;LTrQeB0q|Fa+}GTfd^RR zujBEG6=za=WvjXO<7}V62J7%%8tYUw zcFaAR#MC8qRjkrziCyY6HX38eX#OH!tiXnA!X3{2^wr72>Y}z-!ns zNq$;OFBfAD>nF=G$+RN6{RyU>g0@h&iB{&ov*}M+T)QalB!8uR{{mSaD)v0Z-2|5N zP}CSeUV%3aaZDAk`3NfKphmu@ImH(qVqXQxFGru^{b4*jaR`x+9fv1Df$>o4DQ-Hn z-x4gxip_btAIsWPeDgsvQnw-W*1^%xLY?BTt7!R@@*3#WO0y)qCzB<>pM)v# z%Z}gpPp#||txOBPZ(CWVR!)sO#cddUx(J%45J`lgVQ(15Yv8VMiVRW0b@B{UO@ENh z*U5k2s(T(bIYb_U&}k2QGejOAdWz>9FyMYqf;K2bHba}guayOd$}dD-02x#X43lW& z5^`^Jhb2uYx3|>ga9!*~$&lnGr!cm!1KpPIp^5><6;nkt;+w*!NSQAOw^us_e{F2L6` z7`r#^#`y~YN5}bh|Mz@foY!}puflmntz|kGlNX0!NkG_M#!<#PII?ENIeq_D{O6ju$VI_4(EUO+pSB-CkU6}sXie?s+UFQ zARW?=`Ac9k@+bM}1@6VTqz?;r-%#3TvB9nE;|Mu7?hif{=*E8o?INuaBQS{7mPnt= zMSt+Wdsuh9+_&=|kRMTvL^y$6@Uh8yd0?+k<0{^(+V1p1BdKj8x30rFqH+`aQn zNC+vnfZQcMwpTA(hyTHQwEkH_p$|J75T!Pi3pz;l!Ud}Z{f2DX{uFOg=OddCv@tfg zi~P_0_ifuIiS})i3;#XFU9e2dea|M@)7_#Z>m7t)BpQLv&6{9XL&r4$ zrd{eGcYkelC*)j;oR;Q(dcplMs(7JQG?JI--avbfVB~mKEo%qLdK>eB-Z;yKmU-3} z3|#Z>-s^mX=OLfpQDA3eAE##j4B3}=+&T+8ZMyYg|3urw@niD3<5~ zVR!Cv!8|J$5EVC|4$`0sIy}ZrAC>(z-b*)y#y_L&B!AjRA%iXXB%kTK2_E!z5vLiq zCx7}A{H?;iD6yxbEt zX$>3PO-`A363iubdx5FIcq#QHtObLOy-~L0qyIF2|<; zUd5YbRZ7nDVQ{KZN+k1z%MdcUb0gx^a+ad}rq^j`UD{plCV_VO&F=DH+4Zc3jq4!~ z(g%ZN;^D1=ebkYIK{UZO^uXvA?Czz2Y!TM@!GMfozxI$PgW3IU58`#avs^XehZ4UAbilTK~P*vqwL0LjJLJ$ykteu zP+HYOGs{j!%bA!IR<^OI7`boPyFB+0En=_21W~^aHg+&mi^0fym)j1pLGBxVb8!`9DW%v{|2uH*Ru!(8=3xb~z!<1OipDxz#h_fHz+VLU zzxT7VX*(gp_~W5-Mhp!;>yYNfC~~h3E{f4|4DDlM~S&ux<`Dk&{C`Z}Yb2 zFz2nE8|2>Xk1h_z_3LoGrMVGzZBw*}zkEw;OmVyfNUQsNp^uH~DaQ{x!3l_7Rl>hc z8j5fIg855z!`^YQ_9yQdtNah5MXKx$56HUCrPPskSG zp99GPM>Ecm`ZKUZ79U?Ki=-GPz0w(}9kqg>sm8_0eW2H_RM_%3*%bc(AH2XiKQ5?$ z(`ozWVd+8Dgps1DaF?9q3)@&poScT-OBHrIPOgq5`vQ_BydbJDx@5i1PV|y{$D`i@ zEw?}QE`@k_DD*ZEYU#K|VY+y^Kl02)o&iYNq2{5`eB`0yLWNC>m;Yip!IP2aQKaOm zc_?H?9>F{`D;(x51s3Qxa&@_s-lZewg#XP61l+svaxM%W?zgh+-g4CR`@mec*rUO{ zV}LE^*Z|y^%8Kmb8ZqU&ireZj_*bk9x8zwv#_R1jd0rc)F#PE|_#3i2v~hi|b|{xk zGTYxoK-#EA9N37}E3RwKrR6FeGJY&Po&9(7p4vhxJjA7-;nax(IGee6w>JR2dn%>H4L z4gF8>GW1v&)&vrSpr##yPPME(0b@j38wEA(6vA9IRG%QU-LwRGJg$AMoE0R&hQ;*DMYO%`{rv+oehZXLTsFmlppQxco+CoA1$dVrco~N4L%l{ zC@0HkLi-0N0*FAn0WFvo?N2Amy}A;F`#S6WlItZ|)*Qe;N4K$!$#UXjw|E#3oGezo zsTQ^Y|2;1tb(or(;vEPt*K4<;F&w?MM`z8mw!!l6_hdPt$E)Lo)#-3%A>U$RauqHo zxgb|$z5B>LEL{=phG>W~F)yxI^Y;{M;kdMN+e3{btvoSd;lx=PM%asp?%rZIYjjF1 zNLHsjh_Iw#aoEe6m@scLd##V$H-8q;j&+&R8VN2=(t@q_F2yO<7LcXQkBjPm59Ao6 z!NZ;i<`tR6)rwGX~M zx3=e5!TpXBibg9W6xxX_;wFE^(}8El`k3WTlaBMbZ7#bG7tdCb-MZjC+Q_pK#(#%m zSlzdd7#MyV@yOzS%nq{Ndll_lbPRKvb zV*r z1Oi2%xx5fx{Q|}(8l&{kdl#ZJP;YJFOAoDFK4;#-yd{5qZr+?la4hK^jdjq@Z3-O^eH@wdp97FZ`>j94sE`JUA>E~aK5mnS+W;A<@i;V4 zkA?1S%nfa7)VCVu7FB$Uf^?Vs`2T0Bt>Q3Zo> zt02aJU{@`vY4?AND+lQ2xB1FL&{blJYT-ZmP1bNjem7|8--&+7*#eM*h=Y6b6gU|E z&dK~cwq|L3#TZWn#b*bK^K{XG(J=w|at>+CHD@f%;|6U=ud2{l*Os&*7tu)m&VR3< z@s>o?7jy)Y|q5LwgHn$NLZ0g~k>vo$lLHly)OgDJPE zhhR;>Zz{s9s-L`4oW!2!k7jFS&-IsM#8GTD#U5jS?=L6i51goJF|7zO320^ktmcV9 zEWn*OzKG*W92el|!0|a87vVSqM>~#LIL^m$6ppz-4Sa8&rX>p2D|(9-rOmt*Z4=az z6J7d!-6pnQ_k727b2_ejCLe*pC}0+jW*ncyu@{b0aqNoYr2k*R8PFKTL3p-ukuD2^x$_fL*}{{7=AT;nV-FxDo=~5;p6>c5m3xw z{h5V@=6Qb7%kHMid$nu60Mr-OCI22I4<2!h-|%UgtiipFY0jd! z5$O#wtYf^^XEeQJEJEm%FBU?T+Xz+pSX3GWDaZKqa^_FNYWX;yS_*0gL{rfE)y(m7-!6v+mHsW4lQW0xwJT+rAb=RbjjI!+CJ z*H*H+y%+R09^;=M`V$A^IPEx|9U?~$JjOr32=jjEnTAfGl^x3Ov%Dwdnffq=&r-Mi zxA^oxCHR;A@UqW_$a~U{11wJqFFtKkm?qdk)W-(gbs*9rg{a5cQvw(qY0pDvj6huo z@aF@;kkweM$AI0$K73R*n~w3OgKAIAa6spoK_*byLCp!>e>VMwwevA>F*4VqGC4Rr z>!XU-et^hNRQHjIz1~nV?$N34b7Iz71PC@v`_HfHK$8kW|R+=i+ zQj4I{a+Cx4IonbG=Md%?mx_A+2O@bIwyIIH*^kSg zNt)~Mr(ntx*sjX%);2b5lza(Q$KtyCXsqL}b3MTBM`Iay4AOtLdo%=lRlFI%@uTIq z)E8lg-t;b+L1_db={dImoAWpP!5DR9_gC29=&LQ($`ZJbfRDSHulBPji`=(+u0ItT z&RTGFgBq!3xR8q6|MKsjVUf*Z{sYYK(Ki8Qj$!%$eh2X*G(Flv970(62lglU-Ni2v z@mw4+=2v5C7dqFF7)5mV#con`PgehrQvVMM2!>9s_Om^~DBo`DCAyQ;v%~S98ieRJ z=EK$v1-fH!f#^1XC__Z@Fr>mML;!ZT>1{}~?t*fJEaWRAs>$^gIfDXJ7}1ip-{j6= zT5E{zo`FM#0a#P$Vg!Jx&v63U(tX))aGJ5065W5`{pl@JUHWn-tlAQ7TlcV+)8)jd z;6P9l5Vf}GKaTilaEVwXyR!nUBwZdg>S;eguHA)=khc7CM3#l1mFU$FoKl>Sz2Ysr z5-RyU*opqX1=dyk@$&rxGh~OPImdN@{r?y%KPzI6Kk3uB&H=xNg^rUgus)jXC8CWa zTT)iCEjcR&L>uS88AC)H=K$byj!(mHx}ReIfNYD7Q~h^drsE=i$}4ny7W`ab#(0cG zFvd@{!uC>pDp(d8(37xq7cFJ&mWI(dwqjT4(g@bk_>l?Y4%j6BHcsxHT*ZGmKvWf) z31&v*g#}ns{N` z;y7`@y^8<`M(M+1!`F$%fre_X^D=*yoEZnL0$jdzTmAy8{Rc7d_askKHOGZk_Uw51 zGnD-i#N`v@A;aKb9SGTuW%{5yyfvV;ijQ=uxdYH*FuMT{cw1Z8M;7~rbh#!6JN)!k z!6o$(w%-9)6k9$4lJ9Ds1&`1P5W)T%WWTzPdxJDn%Q5DTqaW>wE-Mm}>}WQ=(@!veZI>8oATjxge|VTQqjdMFhgtGec~4vw=U7n^Ov^{$ zG29%OyRpzl_p9RdKGr-H10u{_{j7SLoY=EVfXVag#8`f+pF$l@&~vM`65G zyzIN_^310z%fL~SB^h)uoTC+0q5($dDKH*KdM1#=a}eLY7e~Y|eBEvaOj{y5`q8&Y z6T*ZsZuB=8*^PmX+?Yj3{~iwIkg2m3GvooxoTK@H8K!CCx@O+LUO@YZ0_-1zUK;o1 z(*2XCY2K6Yu!*hvZ_dzU%K46cSV0?v#4i8TyShI!I3%M^h!i58g!U@K5)5IlrB2rO zL_8ri$1*=|bNb!W8l!}`$*`^tfSPK~toVXDNq@fvwzTTs{$58kOCDbraxpoh)32*E zkqa08*rR09o3TOJP z&Cv{$O!%gOW>)7# zk)8B2s;#sjM&LLSFN_t=kO#u!d9R1n&X89~@iH6tq?|DDB46tn2BA#_%=k8B36Q9g zgyT)yPoPWv8MsVAR!viXA=qh#FXSda+y10HBK{si``$)RH(R%VkPHslLIt-?syuH-7T^rJle{Bnm?xZoa* zt;ci-C5dDDCvc|*e@;~%1=}tgM8^=Gqx47>Wj8)c=g7-cpY=nq4UcP1ol05HD;AT* z7>#U#S_!I{SB2E91KPjfPEtCx6f6!SubtP`hJytjAPek%e{Nhbf&{g*^R26#gD2Cq(j!@8TnDk*2*S7BbVfpST+&;*M?uaFuc&2 zwDKo-0~fAIL6iCo%iAy}(c?al|UwMeZL!0vO@~6(X;{ohbn+?bxEl`L) z^_USN@*EvvAD5+3rxRg$2V0xU=%aig7$O`Q=+a3-a)EU%%YRmWTXzy_UMQRnF#U7# zP|ZoctCfv^PCg?ZV7+tY0np0CwO+ZS6K`_63WPAlZL+{EIPxYS4O*cDVT*F*OJXt` zH%I!t@kVP`pezA0wEl=_ zgZ*fynw_v_Zf@)xnu-mZ0k}3tP!kY$!i(&Axo_BZv~~hjbz%>)>v{PJ`%zxypBrCW zLU4#~i52wJL;+N!^ZplJkSB}zKk_(#u(1@6Jrm1T z$wHy{!}LEHV_6xF;W$r6u-)K1g*qRm|J@HC!2d|(I*6mk7i^^CU^N$oyyf&?KCJ9} za-!=sLoq?*LU3si(9Nb{@X+BkO&td1>``2#fv~Tcf29#gH$0ubr1@?B_Y z0)Vwm-f=b!R_c;5H|{9t-lp5-0cZmY*y{+4eh0TzEE1#^#9lM(Kofdb626i18^ILn zz)L|1ms*o1nrw654zf>+?;0w(^QC-VU~<;SKr^MR#Zpw4Ur;~#al2!umi zG;)X8EJ)p{gd&Bu10lv+&1cUpwq_RMhj^(91`Eq^@STe(E zRa+th0iayx>tU7(gFlths6BmU)(yU0HRx-PFGGBb+Aqmc?*_N2SJ1iZ`~`&DO?!wm z?>c|hXCI$80nY4@UdH15Oy3LR|BASyJ)Tdp`0>vp!QPR<>YF=$9^$zj@ln3q@pBN* z>4*>YJv;t6#Irl%168xm_KFOJStnH@vEvbLz)(==PZf%(q1#WhO+%Hs`6$;7-W$2| zV-V;Epa8O`itRVWZLv&17LAXjKRGTEXb!m|7{(#36=s?d$Q9Es(>50I=KsAa-IjrP z9W()CKpEZ7VtX9%>*^aK$buWZPA%^StYXuwk0ag;$5Zu=PxccGLy`F;jE?$Q4KA>^ zSq3Bi!~fna)iwz6LmfAZ?l;iZ5AnTf;iQAR0iu}pLaTt)5{t+A!OIdC$#)0B2Bwvq z1S(5FH4WkFKCCJ5iI;V$w?vdZc;RbRAe+^6R~x#T=Y7paEtX$a6}<-+%b!N*p-Ou0 z{*sZMUWgG4y=1mW_wwvs|UPjw=Sz*MyZRDI>1k)2?2f%8(v9W1?vo_U<$&bm#XGLu)c9D zmG{6t2KwGahrA)*i!CGB;SsIS5cnt2&~}fHhSg*WM8p%7anZvuxO#!S(|&vc;sq;Q zQ@xl#$vQzW-XoAA48CCRP&C-H8(^*Se}167^j+!^lk&k~3D{Q) zMlav!3xMi3!0!c;RJEv>X|Qg^jlBF-*rqIlBK#gP@vd2ho#;K7B8hOKt^go0%(bz& zh=P&CJzfk{lK^-GXj!L$g9KH?fQq!=^cXv_OnyX$5h(L5lLuodcneiaE7uhW20_G6 zXy1DiD;!PsuJ`ic>?5}8i>TcR)ihbhk#o{5dqR14e`#4^2qof zd1wXcF|cWb_@6vV6iD`k#;VY3JmxTa_C>k7<{A$_%$zUEJI4NqVO}!a1ZxwOX}10d z_RY|y>l)RM2I&wnn+OAw+(SOQLUJ7%`DE!w{>EXFlo@bEKAW{l?v?T*%vV;$NducM zlO$f;*!%=ug|G&r8jWm=@S|;h+f8Bru2u4rqLzddIUzFhz9cUNPWBNWTjG?zLg-TK ze#2_HuZT5A5kA_>vL7MrYqMXGD`!A31(KdrwB*!b*Pz?D1}B1s4U5wOjq?|!@%F~w z8a{?%Mju+$Sg7hn&R`|&w(G#N?S?&-JC{tneb5QRy6WTha1JcI*2ur&9{+CLpZTiX zDCS(_mzA?XK%z_N?HL+3;O*6@7ZKFH8Ji@KsQ`#-W4^p@U^SfocQp+Dl7<2}sJC7R+N`#us_|`AVN=Z`)nW4*--$Dm z+SrH!IWhh^e@pdyau2@7*R@{b)4cSJ@t}XX2C4V{H3f35h_%h60GqZ>2HFe1+Ugj; zY{E5e_gv@E-gW4EDUgyBx99%RN%ZfZMvTnAPq)@APIR)u$M zWpV2v61)M{aW-td{ARq1e?XT0%6jk<*sSdi1rIkF8bd=}d_y_=b-ny;&+qxCSSd(` z??IkLD+LPu&tdxiCHv2tur>Idi-*~TH{~4=J1kLlHJsZ-Be{z|gktLmdhbEl4t*D3 zTi%kRZPk1Ra-29wMy)P@BEmfbIX;Dt_}kVv^oweqiGk)LTu~S}*Psgx$JhKxvuoQR5Lmo$9|Bwy%9z%Zt zV-LL{f>OT5-}brqtA4s1xMT+oT3>10bYM^8!q7Ip(v#9yaJ(Pv&D;1A4;#5r{w~_Z zA1faLV`Tuzma!R>zGyAJQ~zDYKSnwxxzkB!(YPeuqzgw2~}vz8 z0mG8X+S{nL1-p71gKa+V87?-?CW>r>9MtV z=!Co~EQ#DD!07Xs@`6975KK7Y-j&m%s)?tlV%ERJFJ&;fV4wqA@c!lRqT}kT`C0#e zllukO?k(~Qi(vZcPsB$26dceJG1i=d2nHBLaPTG-dZKF8`a?&KN;QYx1wgx+M2s@0 z;J%iKArfYyIKu7BC8q@83@uR~WSrtfhsh`^QPnw};-4O7uWf~i(J?fCR=8E350jX0 zp?6Y3`~2f?N>sKCB#)#$;&x%nEVbgLK9=~NJQw1xAAM}&d-5>yx5Y@wI0_uv3;w2@sTrRHb72K@sqJsGrcu7p(TGU#+RA$%`O<>vnx7n%=N!$9AIoiC*j zz;;oRAC*&kAQXL&r^MB&)d_*z2ROY7e&o z)A)*wRzSZI(+M%aDTS$! ze>uR-(Z9tWOu7m`pw%r2%AK%ky$a4o%9_s5*DbSeg)XWqkTHjAukl5UixtQ%aRHZZ zSML+(IUGq}36z(P*B`}|&iEVi7kUZ%*~0&()#d&B`3(M&{oiJF>?0dvKhknmv$k@xB#!fUCuk21N+9Y{l!uyzt8wqK$yo85+xrJ+YhP7^cD^H}un;<= z4cc8D>dN;}nR@MEpStTkW&YQ zv@qXf=^LQxkD;^zQvvL$()CT>VqGVmCB9C`&sFKaY7$hTPjqlX^2bXu{XxqOs6|^? zV%8Du4!_75C78KMQVM{#Ld#EKKd!^9zLd%kclQnoATsPa#P4s9y6GZp3oPQ2zP-ef zY)~6@tH-yn`(Px~7&tdaNVEY)`dREGn+iAOcd5X9bZcbts=YbZc00aO?}?2Irk69kn;+Eo5NEiq(rqVg{8i6%DFif zJj(&8)zHUDd}2Dj6kH8LpY+!es2sUtsO_n@(Mw1S!rf>8bn3iGy6!MECsphW+yR@lLHk&&;RZ%KG3 zZUh?Uj;c@CEXodRr_{JlSx+d3&TUuIKV{F0ziO|ws9$}`Qtr6OSa1`?M=nQP^gYZs zSS5FFw?NW;NlyCdQW!OaW?p7b7LBO_cKT#A@YAaKGd74_!G`I+&scv1R_<8w8H=U} zJ*ujov%Ae#pr5~~Sg=q~9&3Gtu5fQG0id`L4w0h03Gc1`{W-fAW~8A$bwUMnrmtuM z)Lbjrh&XVl1N>HfV}UCiGj7;wKHpvjJ$0~xCB=)N!T4nJv5QBOlwDOtV|Zv6__I4z zT_t-U@-jA6mtW%385{|zg_Z2#QJD59f7Sn;%s6X^PiPH>doz0VUYNlVSV+qU8Jtzb zXJy_byczIBl~u7qx?i1F#gfA6wWnJPTz|qXrn<3;CA#-%YoOj*tn7nQ0{<=bEynM1 z#PRbUTtzoMgHSPI_<5U;|32e;7Qgcm$In}WR||aycJomq61g$m<*J52z^4NK8LZGIw22vr1 zi@P4^ktx=#a-G*Q0@mFewy_zA+XXI$^Ak8zoM*QHvd^M4y5MXCyawzjJ^(D_KI{lN zqF90JG-R(FWHYyiN#PhUf5Rmwd=@dqO+2q4_vZFrE^tuGix+aS*FIJw!9BrT*T<+d zH@>7vhqakC97u+mTeWlG=I~mO_c4+*Zuw6H(OM5@db>utG((bJ0c-p&z@*m6ahhsc4Q4(x~NlaL&!Z zf^*tS(9-A3lveQfj6t!1Y)gPL0-uL??0xFkYN)^-)*foKE)d{QN@ZZXa1g%k*#XCgA!$!~N>= z9c=2uN3^X-JHMNj2}ldsvbPF!Fk;@^%^iSKKX<9!0ZzbD5Ul+H_SG_ot`n0)Ou*ZK z)*I4DHwa~&*PmboKLEGkM_{)p;P;Ap$4)jp;;?oT2_hoCZc$x3VUBS?yM#7}<3p@} zhqU4C>du{PK=Lsy6kv3>z~)lJ8hJPhrVt%|9_oTni(d_^VWx;<;P9h~P~tqG;MTC$ z<@4}4;x@HHXlw(Y|1cV&hE0e&f(;+1#_t7K1%+yD2A-M=qW6M&_bz6Jrr86*Wa5?R z5c_I(DA>*GGmb@hv|i|EgIZ_R0DBXQ>v@f#-&<=2+oj-@zf~>U#fFYMuQlx&0%Vu5 zcANcxmbN=AX)FrwR>Ohocr_Y#>4N8PcX2z4&Rp@k7h??S%v3p`&D+yi-P&Dhx82P0 z$N}vxz%;-JD>2p_-6nb2IzwA%^9hIk3Jn*s!;&ULt@?;|+&87B!ll$agwYd$M%mxS zLy<~2Kr=nPwebiHj$>=?v_~r7{&8g> zJI~$Prh0a>ZYjsKYi%J{#PAXJH-g}HhqOmqN1$gac-z#D<@V0-Aqel(v^{Lfu)~<1 zmIpCPV=-+Bmgq)S_Qco-BNz32+QOX>S(FfO3FX(7Eu2$QuWbpayY?`<`v}ZSN!h*Q z=Z`gJi$Jz}0VsGfQ0(fVuR%79bI|PB4gu(Rp$6XDcsx)aH;hL7KO7A4upuquSa_gJ z0%_)aC~I>pyij1_kur{kmzP}+0OXOCL(mntHOgUa5$2KTMvEgO&XHZJx@%c?$Y@`~ zSU<2^1TY?5Z^I%-UQa;}y$B$Mxx3}E5}2a^*rFxRJlav1MYC7Uu7~453gkSl&ae%W z&w%TZ5%u^8IFHE!=HqTasu}+W z8Zu}%0$9AA=ZJCuXmw3E$6_J60o1$y9~vGexj8f*U-9_L=R@Wjt%9QP)z8=I^?-||7NH_j1+2X&V5b2PeDUo6g3aTC zx~WJLv9qq%)`K;^9TWGW)(|s4f7Z$wPCWF~F8=#0TxeJ0JgZe_uD%a}w}TmY)MLB& z?-R)I1B?HwQ#z42LjKio2QGz-St}D zmxeBdCL3~Zgo;;sH7#BVl`<;qyKZ9>^%Ls$xl9-zhqaY0N)6X~7;HPNZH5@Qq`Jg4 z#~$gWLL~gm9M(RD`acl8;@(2j0x&c!tY~}@GzgW|MUVnu)tDQXc?-9U=!N4Hc7zY_ zndEM!&;f>=nlHVf6)hw;U(b&B17q-Sc+66QVV*Su5_B%L<^?4`NRl)DQ72 zdTmVGr#?csUqHH-#XCzS(1(c=Lz#;MWRg+^TdG5W!L`DzE7&`>53bF*aR??D;7Ukm zwU0Q0U-0Y+YGZ`DzSf(LbBcU|@vP65t`_ZOiePo9>-VxWw{Oha3W`_q^vzwv)dHg^ z@G{|f?nHNKF;*&~D|H0VYki?)y{|+sR|<&;a~P1v8+~Dfm416kdVJLqal_Yoo}V4Z zmZ-Z_q-zp4u7hJ{psV(kVTdxL^*JB5D|&H*?2}3_+3NKwlS)C)n%a*<3CuH+J08ul^ZiuI+yxLS@lH{VvB zz4qZPcd#GySm!%5s0426_P}z1_U9J&5smA7pAA}fZGM<=Wre`=9|Ln8%=57Drggs0 zky6y7GbN+PdZaAF4&fG-SjzIuRds@$mMzaT{J=Ku^Oc(kRy(gY6sWUhoLS|Tsn;fu zBmutI_G{m_@gAgKM9S{8bN@391+)NgW_{LWj;z~Tuq@Mf44t^!*VAZd-F|n}jVFt9}Gp zp=f^#E~wnt3!I{jx-vLV>U*_jQnR>dNt2$C2HJN!9v~(0YPDjC=jTh{2ZIgSb=4!b z%Dg20p@5Ek@S&`k+3kbwlNgRR=lT+rS54LMKFRuLB&TGStXoNESAutT$yvjX)`r( zmnm<+kefAfGodvQM69WS1Y~w+=UX0@rzq%7_)^Jh(Sb&1720#-Kwv;;LaYF7>iSvR z7W~bt2E z74_r+HZN9Q(I@B(rt9(K$_+KXs!M1^^`V2zlynKk7u4SAColZ?PE&GaM$O);6Y!?O zn&N_?%j$-MEGhKOcj3XU3eb$|!Gr8^EC7>R)wDy*rhjgn4?59Lt4|+dX7he+Da6sb zV3(fJapsbkBwrCiGp?}kS#XfFk}gtf4zUdPA%G@?*k9j`J4=NmCxDJ0ggmY~0P{`j zAB{OTW1sr>1Tf5s6}}MiE7WCLp;(!Ve4hh1>Zc2D1NWNKp*+Wvun?PGb31)k z;JjgbR4p8h%sNoOFD`1k-$}bfUlMw98El~^Urppefy}T)m`m9?2|%6-k<|8_j|@B z_|5_)>#15Hc$w+@8#~>nYIOskB<|@Y#;M(Bhz$l(2 zBu*`yAwKM0_C2E?;kflM;Knk#0LNcAk}?>5aG*fzaNJH`a1WzhM==@&ps{lo1^Smq zpugj|`#DPASxM=Zk172f$H8@k=Hoc>B%>2?WW7%4me&aF_X?q2#6S81r7h3XI9fbW zq%&|V$rY(LN2EJ&UW-FrRnIIS8CUx(3kg2+VeMs~;wpiv(VfeRm+`KU3t}QmN1$|mdqL#wNdFp$EO1;EsxJ73#fhi2m=^WrZ_qCx(P`W9)i-P? zWk8x!TaL23qX^uayj$Ede@?I#HR|YZ**v5!Q>(vaJ0KVz0o{l1Al)P$Ys-!`-?8=l z-gTr8(OC>$`dCg90He(me<7T5)Z+U zsc8-=6}>jf%8j^&4tEoD&*Gq>;6rJkIzr^NKD|liFZ)RKD0h9)LJ495Ue~ zbR@b3)y*@}q^GpZcJ*q$Xo=-R z_O^~C*Q2Nm2({|@29_rt(6)D|jz+f9@e4e5b9HxPoiI?>sKZ9rVgCif1gK)8LvSpc zk6>?L^Soc;fQzQ=_WzQo4m4{~Yxou(KfOhbJ;u^9&uBZKWy$aR1(-YUT-y;wg5hax z<%O)UGv!S?5tq~hD~SZBk(!n08t4+`O+WQNZ>-P1@_KXU{5ZeM9UWhKTSXXf;eMhJwA_Z z5Gy~V4T9&r|NS6|_#h{=VK6ya3qPA{eUb2VvewsCG20p9mj*Zl0#}C#!)nGgLVE+0 zacj}+@uRcivpcmF(TcFAtLsS2hl7HVl*7nI;WnMuhUiD&*u_cB=to0sC$&eQ;wqxI zrNcIXZ}f)wH)Xc|z=?B?3%e4Gd9d;@>d>%IX3YtzBDR1g<4bG<#tGk8EGx@3s4}0a3n!h3n{YbZtJdb8kJo`$ZP7B=~5_~2>+-W?M!lI225w6by-4^w| zpVCp)pMXhyowl@9-E@K(O?B{(*y)D|m4d#IQsk{wFpTQ7nY+{< zPe9^)Nc*Z)l}|D!?uu(wA3KTZsZI;Ds2fi*tFcbI(89$~X}IIJ7H%lPLuVi+J<0w= zzFEK+|Am$1)`8LEKuSyvfl;F5sMEUCyo!ahnGpL~9DINLH_jd$UK}@Y=rO(4X{|fC zKKE3F{@%&QOgciIo$Ah0?7NX)Y72LAE6%G~4l|ecyzFxXCGC(BVM}rv)|?iwN&9ug zLLbsd>Y;2#kzNXEPq9z^>NGo_auCp_Ux0LZj)s&UnRh^2>f3>vQb_ z{B;}vl%d*i2D4*)`&-xgV!7BG#(gVS_+I~&CAcqWvs=?@bY-k?ggq2Qc!zeUfBjgt zQ7B6vq-4MJ(2C`so4}R%*H_Dxcwqz0<~dpeFs?G!*rY6_h?q&)LHNC|n3Fpi1AF6I z$0cCjz6x1p2*m~>@qqSHt5kN@C%;?oBf3MrvR66K8Xsr{Sz%X*`qr;3)Nw*P)pDsy z3JxnvD-TV@0Nd9Z;&o9U?3}{y;AYC_V%b1Gul`H=d(%t?qV891 zT8;YWudL6AgW9Xm0vK#JLyq(_)C(dZiFkaooOlp$4xBE-0LJ+5<9lq=f2BwY6bb>S zHR&uH;l8M4wqAl5NwMDq7SyG}E%{Lu9_|(hK5B0ZjcnUSjg?mYrRB78QMkErpncd_ zE;<6V3ECe*qUNKvpS52CQuFBy3(9^2I_?5sqou!}fWMoSuvP0jmOG~@_5GC0g-AEG zT^;ZX4GEH>>YLcZ6Pr71HThs$e`4Bbi_Xd~;uca@&hXjfgn=r_Sn2pQP|OF6c^`CT0@gDV zi3hi*aYExnnpj$6?APE3Z_IQxI0R3Wz%j6*%wGbbHxJ(?yb1gd@Fu!6N$!3}9AS+a zt_%;Q8ATQtsdSp8e5qaC!(2iu^@hVB5W^Xi$Z0n$efh(E!M)Keb1=&;2{Y=K+T1-$ zt4ZCzHa|B$tbnZ7*^MZM%JDv8TLze?v8D-G5sf8dS8XbpBmvXwvxP$dF_m+}odHu( z=$zG~9cEbZw_aQFolo#bRm^>&goPAUQ4-k8sd_-5VnT$^E6aw{18&DVMF_`|pC@kAUEpK&Iu(4i8lz zj+@{_Ho@w=u}ko#58L=HDGmljFxD6zjC&KvrTBc-!;M>tLH~OgCFru3UF9yCBGnPg z)<%o#;|mH(d;zopc_qf)6O)w{3)eyT$^@9v)$2tyb-P^dDGf7@F z_C26KypQ94M(hvZaAJjAkLy=(l;IeH>obVI4TZ$%-8T`x5yv2;y@7MyIRXkr5Em8| z&dXo8=pRo4a-^ubb|S}_7wzs8mw7SVs8kA`vqJu2e*Q~HDf(h;l55=ThfP&&*S+XK zJvPrq*IC_I$-}%8SwMlEz4l3vZ+442HoLOQfX1H%qw0sSSAEkLgR5z{y0_6>xSL(Fh3kTu+mZPxWY!_`VqZ6;4(}*} z%(uwb9pOP8w%wa=Tt^t+#;dy;XV^`-QXDW82|AI|Jj~D zyCs;8drG=HZW=eW&P3CR6(yQ3yKf@@X4XD6+_SY+$P`~T5e9>q6j zmZG!Q9tbNMGb|zm8H&c-ZtDLj3e8+JhRbeqCge^cN*?S%J}xGn>AuUw+Genb~O@_PnzRRk=>xs?NQ zI*sza)FN7W8GLTlLmj|a^YLOnJLn*tZg$u5!QlsZ|Cd@z&40&1PmF`tTZCE+8il+9 zyEzgQlu*)gXo-XOrUP?QRJuC&G<61?wQjZdAZPRho|BgMc9B(CA;x{^2< zB+bp72>UA))U1cIr^?ov;0EaVadKOzN4P@5LdwIijT{QXX`N4Mi;QUQz3a(XIWLJgMkeRr=N-T_eM`X#?$;h z{-HVFBNy)DI6A!D*PrmvUr3o8Ou=9(v(0YM(tI4s{@jK8eTs6w+W&Vp#`v8U)0Upc z;VU@cd?Kn~Llq)h)z!bV#6CZRKWMXGxj@S3Y+mFiI|-=6<61hT>6fbTLU5I}ZkKxO zcj$|K19Snk<9B8oa{w?olGi9bWfBK8oT5#cL5$hkj?5{JO@+ zf58>sU_&fs%?%mNs|MGDmS5{L$&u@!&TBhY<*PagzjCVm0`SNH935z?v|u4(nBoSd)GRdwZ%ptbVfU;OI&3)p5I(LUU%9=gD$cLS~q{6=hApu_{$1sK;H z+2r>Qb;Lyo<<4ja1M2jPKpH!vC95x7WbqJGXZqfNtZCCWz4ufYUzl^zh_833doHpb znFoM1#(AbT%e5a!Utg8(N(m{wHaYC9Hrba}Ld{sbO3At*_SUMVssoyEEAQnW_`=T1 zDdkloeajl-Jdf-s1OD{1c<|J4s41+H>O-%Gw z*c*2h%SDhUI{k3I6~l zQt9g2M*arkdr&WGJ!<`{wm6Vp60CD+mCNknx$eS_EhU(rLg9Qr_O-);{39;7eCJwJ z_)YCbQ1#2JE%r6dL?6U#uyI4&J%K9&Q*T3XetY!j-SZ9Xt`FbHzN@q^_6VFK#$Of7 zF(IqA+2rc%39)AWMV@T$JU`K{TCT7)zz`eO%3*y%J-RC-Jlrc1Xu13Mz$JK2arzX(|w)+wI_)bVKAm-GY)9zr5eQ|=UqCd>UWfk>OZvVQQyA(P-=s8rWzv^?0z zC*wg-#gFdSv$2O|a`1Y9qZWj)y6GA~S>o_TcpfwI#PyTvdRqDiuM?1Gy;;K;erWTu$i2KnT%vIB0bIP7i_aZRo4;)vSZWjxK>kk}({ z(&(FT*qTU{J=z6mXs7NZWG?nL4nlG}IzIX2IehD6=ohqssH#QyHevPX!bSN{F8XKD zjCr7*@TWrcWCR2z-7(I+tWU^Jw8Th3ebUROi$)9!HSI58TKuHFzf1k>FV-z289D|F z-0IhVu@v=3FUua^zaOIySQuT>htb{$^Fq7gnxAj~-PcW|8@h`0=@^lYLYT+jjqBU# z{H#CRrasyXb$c%6BPGy)=tIc_CMb`5PDs-#AkSfEYDJBB=A=Vyf#W?1sbKs{P-1Xh z8Ba(Gu9_Ayh2h$QaF5~Oz4ax^^@DAJXOPb0xK9ny-yzTdc7rvrdL`5upw9l$icr$% zk#^)fD*9OX@3PG3$l+w=fowJRaq%G`d#Ab;k|noKX3AH(Ve|nLy(dh5vA2`zd(TgO zuXjS=?c{{O`@NUR#{_w~C`aF!O9L!K9!!;P?gIw5AzF!xm)Twt(1&($>SaT2+RX4Y zS&+a1v^pcxqE|%c+Sn-4g^aS@Q7O|vR8*HIqw?}tfJBo(S~RUdg$=UX#-cbbgnakq zsinx?jf|3e^fGOh8|Wy~U72Z=C+Aksp78cQ)08*4^jLh!lL?BMM$3)1W4#pq4|qTP zn}h#}$}#*W1^<(kW4)DQeUvBrD81!aJf&-h&9gjJE*118EL|QPrz{^J4{|Hc0jMXW zs!Yngqg0_$q({+mT9nwMC?nD%2FTR&_(asZks2tyPcze3MgS5$!ZiBtLFUO3&5XoO z4x2eba#H#v2~8l|`}Dg%J~>3u^{0w&6jfr=sqt%JYMTBc4Ct1AKon!{Jz+ZmQew7P z1>YE$f4?sp=2~MGT}ew50S^MGLR-JnW^2FwW=obY$7v{(wMcRc&N_kep9)1TLcjZ}~1=b>}6QZV? zElwk1<)dyv8EIYbLUf2A^Jt6JFe~_9YIUwbw4O!t=ya=Lr`52=y1pE75;Gt!D}5=7 zi1-%t8n36b0x6+lOfaR)YQTd}Ti2gJRl>wrRK@AA8n)vG@tUA`tj-^iJ6zY*%?qE3 zXz4pavGTGBv!>AqT{o*4JHD)`o2-UMtcEF8gJR9H{a}5BMoQh2_0d+m+tdoH0sl*_ zhIFfQ7Vhd2YQzqX-?f)N=zBqV-?}~*g+_(Oo#xRER>M@Q;V5q>X9MEph|xVxr|HsC zn36VvSq)pQh8x!PB}j>m=*eFsZJbrslLkRC{V6DA)~t~~;(ZKJCf>AZ4+ZO$ZCziX zem7g}>-I*8W@?u9%Y7vejUYXDNHTl>cX;I#4M#;olW4dh;ywQWK$U1n6Ajs-VJbep zXebd4uZo6p(XdA}G>C@tqQQrZ5f_M}h=!q}!66zR5e-G+zgAw@9%3kqFl-eKdqu;K zqT!-w@QW+ti^(yi(2|Z;pPnNQG%gwt!yk#lJp7S{13dSNdZyOR5xezVM&Gt|i{2cu zkD9{A5C<7c#*v9+63G$5)Ia8kcSaS&>MTiwJWX#@CrGQT>VUao{Ggp7Geq)a=p=bA zn;Y`m^YrfF_vG9aJ0x}ckeM{uPeX`p-+GpDk2iBl>WS3r0g0%a{~`7nxsN8$)-DMQ zhc2;KYIeMHl$anyM`hhZ#8;?bTuzPimi2nO|E4Ea2tveq8evXfKr?BVgy&w4SAU%= z_7`#$HGG~p(X@J)sQigmSv*`+R*TIB0vlYjn3eWVG5$?;(L8aO`>4;PqXH9kA^Okl zkA#OuM0UZH6B!X67ApN@pGl1QmV6v?BoV|A*z$FuOs5YGkF+gi;h}mRiyFg|^Nm?i zkrtV0K-@SZ%Hq8;v17$t%R9lrheXMnQ+`hRTdz!R7(~5#Y3AV2XzGoLh#wYjj?5fmi0}K)nPNoz zXT4@h5%J%5RagWWli#u?F*<6UA|Yl=0uQMXiLvV@k4(tlKR!Pq zKIfk^lOqxy&F|sHg{#j@Yed37PO|)nJmE1wSwCmw*bpI#U)(wgDP zsqI)VHasZOZK8*Y`yUjyo9AYQPBvZFb)TGU*qrRqkx}0WbTa0)_5EUH_TpMb+r^mc zFH6nzb-#zk`Wc~rM`atH$AhM=glJv#h`MFZGg|q=T-nVAiXt5?8s_2IJq@Q*m*&Xq z;9rcM5m6uXyTfLVx%=+3=RULMIxsUa0-iNhRk%>3Xy%W|v;?DiGSMTlZ-p z#_-545m7M)IXbp06ZNs9bRj>-&9n9}PjE8n?(yN*V~IFD^>}dtyKISJ5y9DDuNc2P ze8BVvT_bu!(!;bek8B)nwQg1f^;&mxPQ zX6hX?)tf*!PaG66;KPO`YWsXK(U2DsV;?FR(xueFlMPd(cui3U6^T9EC;B)yO3qIt z=N`%Vtz`IBO6?l&{7cRX4BZqztnUE(U0t%GN8}kyQtC8j7$&9e>gOD1blxXr<&8*p z&Xt_=CFcUAn^R6brnd?o3B>+9%i1a^hWmY~7jv`n=_;pe$*LA4=TDMTld_CV%KDL& zCRD#4nd(W+s&LT5apNqs-sjw?lo%f_z5#I4o!j0k~hK@a^K5D;(qDA-mkm#2U>ePi| zl9bRoaF8L8*G+wHp_r`e2%&GY9iJ`~KM~yHI|4TiAJg`j9U=3Uc9~~q|B}d>E@tXv z@-h62^4+PA#7`d{4cilIh%E2BhXi^l7vg$(Jmul0E>S(mGgPIOv?qC%meHz`7?aLT zH_&Y~=Z}{?;k`D}?Q{@XM&F>-7`wf4susmP8X%5|dHuX`V(QGudF~sJY>vopGRre6 ztOea3O^N<G>yRKVBVtZ9s&dYha8&NlG zqyj7xmWxiNH+tWpqv$UyW3Gqvw;q@vUP=_{$>{Q!38Fp;bZ}Bcj7k6ay&_Hep3vco zy2~uOgU}&vi>&{lfzdgjqFxgX8$`nxt3huJ&@*ORj3LKls1^->50zQpMn;P**XiU$ z3#N=CeMK5)G42%``-pT}U!$QG^lSbASn7#}x(SBOqRhM_8HTOQR`}rzP_&6~3rCOm z8w~r?3~L{8zLJ-NSZmXSs;1d@HDT!)EpkaDsBduxT$|Y_w55K`UI4w+~CQ3<0pU{L1dw4=dnG};DfwtKm zli?H%Q^fc?5CTOOi;l20CIciHX!D_BeBt(ljK_M%WE>FVUt5}x(eJ*Pj8f6CDL8A} zL_-B9ui{648k1oWLk(s8lg3wXSEa>bqC2%OOD)x{eRVm^C`0Loy#*@k3$bVW(Fp0a zWH>JwjFQ1G8PcRIYn(A_B#tR@#xyGKB(l>4f@6vZ9b(D3RC3;svP?S3Dau(&KPjuh zf|=0hJSsV})A;;pH98&XPG7q7ej}ekZ%WRDbZ3ZLb|$7fkEJ_5G&;YNoc1*56Owa) z(K#;N*_!S=tz?mq;Otu}IbT)MsB#vB%!ywmXR_jSNY3q&^MvHwneNO^cly(vzZ#u_ zg%_}1a=xzcf`3VO_EDVUB8PAF^#F!DC$?O2Nrb!@ z>>g~6`KGzN0FA;`MnpwsoQXM9QWyu^%FDa!HK9mmTz*_;mc^ofg9YX$)TSRq6k8wA zLir6c+jA09X6WX4#t2GuOwnRF+T|Rqp!uVtWRXk&FCbPjD6$~}Pq8!!3Yi)skCWmq z8M2KAvLH>EP)w9ThNT7388WK?kB7*HtL2GO`l#c?f?aya{v#Mh9+tmn(?1aKswt0( m;SrgOrF%=Bk_cVOlpXXsa|%jT&jHV(8<4=QKOX+yzyAZG;^(UX delta 111278 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 z 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 XxW|G_W&i)Z#FHD2wl^gA8^`|x4ADG} diff --git a/firmware/Navassa_LVDS_profile.json b/firmware/Navassa_LVDS_profile.json index 8bba93becdfb15..8b8c1a6c86b940 100644 --- a/firmware/Navassa_LVDS_profile.json +++ b/firmware/Navassa_LVDS_profile.json @@ -41,7 +41,7 @@ "rxOutputRate_Hz": 15360000, "rxInterfaceSampleRate_Hz": 15360000, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -157,7 +157,7 @@ "rxOutputRate_Hz": 15360000, "rxInterfaceSampleRate_Hz": 15360000, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -273,7 +273,7 @@ "rxOutputRate_Hz": 0, "rxInterfaceSampleRate_Hz": 0, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -389,7 +389,7 @@ "rxOutputRate_Hz": 0, "rxInterfaceSampleRate_Hz": 0, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -505,7 +505,7 @@ "rxOutputRate_Hz": 15360000, "rxInterfaceSampleRate_Hz": 15360000, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -621,7 +621,7 @@ "rxOutputRate_Hz": 15360000, "rxInterfaceSampleRate_Hz": 15360000, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -737,7 +737,7 @@ "rxOutputRate_Hz": 0, "rxInterfaceSampleRate_Hz": 0, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, @@ -853,7 +853,7 @@ "rxOutputRate_Hz": 0, "rxInterfaceSampleRate_Hz": 0, "rxOffsetLo_kHz": 0, - "rxSignalOnLo": 0, + "rxNcoEnable": false, "outputSignaling": 0, "filterOrder": 1, "filterOrderLp": 1, diff --git a/firmware/Navassa_Stream.bin b/firmware/Navassa_Stream.bin index ee1a4ba25ef8482a5023cbd0c1df31002b46fdd3..a1bfa376f0ac86243a4106307f998dad90b93498 100644 GIT binary patch delta 2066 zcmeIyF-Tic6vpwF45dwJYBM-Eh^FA+ASyP4L$JX*2zi5p zLkg+SAyA5^ap3L`Z{!V22>3I5-G)aA?JX1&97`y#*;=bR#8W_Xz7LYh)8DAUSCWgaWMt6&Xxa35=UjHlRHC(LsU zpvT3J#U_kmJ0{VG84S1*!YotV=c0l^Wk?xT_9%OmeaeV(5V!gMkTQxj&J(zgF+4;I zHMcMq@it}?6n=^o?7=(^V*$sogi+ka7}n6j&&qwA<$QoiJj4_pV;WB}gJ+nd2!_Q}&i)0!UK(EUZdtEhKu>Q2pG5BtQL z{z%Jx39mamYkI&PaBEubwd3 zuOjr7A^R#K`^pH^2kL+KRm3Y!&r)yZhf9fLx>k;#sk2~k8s%7}a1PU$#4M(81s5=n za_lOY#Tv?~JH$MmqMWt{4{wl-Xnw*V)-a4rQNo;|kmHj?p`NhmSR5G4&Af(8uYkins#NQMeUia7Xv@QQ+ilUr~3{NKCF5dQ!F z&$e~j)_v#BXj+fPW1260->w;3SJqFjTZ5^eUPBD(hR_T{455Jn{TRR?S{T6zjAIz* zF^UO{VG`rGiVK**gmPJ#RNBh4Zlr|EhZ!!US!GV?D)Y($miexRySR%jY+?ty=|F_gffg}ejicBu+DiFn;6G7 zF5^DtaH!W1`4okqc#c8b#4r{xf+dV%4P)5E1#BtXnBe>olh{EU_b`oJ%;LWCKzXQi z2F9NbH{QBCb@%4OoqFBfX)q(Qmey*o8^!jx@bt=4LvwyyFQ0g21}f%g#T?!?b>~fJ zr1&+ohw6B!1}6VGRFi)U)f7YJ3siig72oi-kD-b%RFR{hx?6v= zx*n^hzA(me&-^AMj|sFfgK5lR2A^RTH!z0<%wrAZnzc}_*(WUFK31`>kDWz7%Jm9j z8!cpAQev4x#$+00OiC$48Aq^+0c_zIcF@8-3}F{#j2is}0}7NedKP7jS}0>QiZRRrm}z;&LwnF#$z6<%9^sSl(8w_H>J+W>Cevh>8l>ixioXi%aRwv zGjWd-(}#+!*%uyXWp2^w&Ry*N;5|rrbYj%7e#q?|%WZ9;0di From 733624feaaaf4516bb73a2ba378c5c85043f47d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 23 Dec 2021 10:04:34 +0100 Subject: [PATCH 073/407] iio: adrv9002: api: fix -Wframe-larger-than= for arm builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the frame larger than warning when building for arm. Signed-off-by: Nuno Sá --- .../adrv9001/private/src/adrv9001_arm.c | 84 +++++++++++-------- .../adrv9001/public/src/adi_adrv9001_rx.c | 72 ++++++++-------- 2 files changed, 87 insertions(+), 69 deletions(-) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c b/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c index 70265f5341d423..9f162219fa0500 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c @@ -36,6 +36,10 @@ #include "adrv9001_reg_addr_macros.h" #include "adrv9001_bf.h" #include "adi_adrv9001_hal.h" +#ifdef __KERNEL__ +#include +#endif + /* Header files related to libraries */ @@ -101,8 +105,8 @@ const char* const adrv9001_error_table_CmdCtrlMboxCmdError[] = "Command error" }; -const char* const adrv9001_error_table_CmdError[] = -{ +const char* const adrv9001_error_table_CmdError[] = +{ "Error occurred during an Init Calibration. Check that no signal is being applied to the Rx ports. Check that " "correct external LOs are applied, and synchronized, where appropriate", "Error occurred during a Tracking Calibration. Disable tracking calibrations, reset and program. If enabled " @@ -251,7 +255,7 @@ static __maybe_unused int32_t adrv9001_DmaMemReadByte(adi_adrv9001_Device_t *dev } regRead |= ADRV9001_DMA_CTL_LEGACY_MODE; - + /* bus size, 2'b00=byte; 2'b01=half-word; 2'b10=full-word; 2'b11=invalid */ /* core_bf.bus_size.write(bf_status, 2'b10); */ regRead |= ADRV9001_BF_ENCODE(0, ADRV9001_DMA_CTL_BUS_SIZE_MASK, ADRV9001_DMA_CTL_BUS_SIZE_SHIFT); @@ -323,7 +327,7 @@ static __maybe_unused int32_t adrv9001_DmaMemReadByte(adi_adrv9001_Device_t *dev returnData[i + 1] = dataRead0; ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_2", ADRV9001_ADDR_ARM_DMA_DATA2, &dataRead0); returnData[i + 2] = dataRead0; - + /* 'single_instruction' has to be cleared before reading DMA_DATA3 and set back after */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x0); ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_3", ADRV9001_ADDR_ARM_DMA_DATA3, &dataRead0); @@ -1040,7 +1044,7 @@ static void adrv9001_LoadSsiConfig(adi_adrv9001_Device_t *device, uint32_t *offs cfgData[tempOffset++] = (uint8_t)ssiConfig->cmosClkInversionEn; cfgData[tempOffset++] = (uint8_t)ssiConfig->ddrEn; - + cfgData[tempOffset++] = (uint8_t)ssiConfig->rxMaskStrobeEn; /* 4 bytes of padding is needed for alignment */ @@ -1561,15 +1565,15 @@ typedef struct duplexMode_e duplexMode; uint8_t fhModeOn; uint8_t reserved1[1u]; //< Reserved for future feature - uint8_t numDynamicProfile; // Number of Profile. =1 means only one profile and no switching + uint8_t numDynamicProfile; // Number of Profile. =1 means only one profile and no switching mcsMode_e mcsMode; // MCS mode selection: 0 - Disable, 1 - MCS Only, 2 - MCS + RFPLL phase sync - adcType_e adcTypeMonitor; // ADC type used in Monitor Mode - uint16_t pllLockTime_us; // Required lock time in microseconds for PLLs, based on ref_clk and loop bandwidth - pllModulus_t pllModuli; // PLL moduli - uint16_t pllPhaseSyncWait_us; // Worst case phase sync wait time in FH - mcsInf_e mcsInterfaceType; // 0-Disabled, 1-CMOS, 2-LVDS - uint8_t warmBootEnable; // Enable WarmBoot - Load initCal cefficients instead of running initCals - uint32_t reserved[1u]; // Reserved for future feature + adcType_e adcTypeMonitor; // ADC type used in Monitor Mode + uint16_t pllLockTime_us; // Required lock time in microseconds for PLLs, based on ref_clk and loop bandwidth + pllModulus_t pllModuli; // PLL moduli + uint16_t pllPhaseSyncWait_us; // Worst case phase sync wait time in FH + mcsInf_e mcsInterfaceType; // 0-Disabled, 1-CMOS, 2-LVDS + uint8_t warmBootEnable; // Enable WarmBoot - Load initCal cefficients instead of running initCals + uint32_t reserved[1u]; // Reserved for future feature } deviceSysConfig_t; */ static void adrv9001_DeviceSysConfigWrite(adi_adrv9001_Device_t *device, const adi_adrv9001_DeviceSysConfig_t *sysConfig, uint8_t cfgData[], uint32_t *offset) @@ -1607,13 +1611,13 @@ static void adrv9001_DeviceSysConfigWrite(adi_adrv9001_Device_t *device, const a { adrv9001_LoadFourBytes(&tempOffset, cfgData, sysConfig->pllModulus.dmModulus[i]); } - + /* PLL phase sync wait time in us */ adrv9001_LoadTwoBytes(&tempOffset, cfgData, sysConfig->pllPhaseSyncWait_us); cfgData[tempOffset++] = sysConfig->mcsInterfaceType; cfgData[tempOffset++] = sysConfig->warmBootEnable; - + /* 4 bytes padding; Reserved for future use */ tempOffset += 4; @@ -1990,7 +1994,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co uint8_t singleInstruction = 0; uint8_t spiMode = 0; uint8_t spiConfig_A = 0; - + ADI_ENTRY_PTR_ARRAY_EXPECT(device, data, byteCount); ADRV9001_DMAINFO("ARM_MEM_WRITE", armMemAddress, byteCount); @@ -2009,7 +2013,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co /* If Address is not on word boundary, Or ByteCount is not on Word boundary */ if (((armMemAddress & 0x00000003) > 0) || ((byteCount & 0x00000003) > 0)) { - if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || + if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || (ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4 == spiWriteMode)) { ADI_ERROR_REPORT(&device->common, @@ -2053,7 +2057,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co /* setting up the DMA control register for a write */ ADRV9001_SPIWRITEBYTEDMA(device, "ARM_DMA_CTL", ADRV9001_ADDR_ARM_DMA_CTL, regWrite); - + /* Enable single instruction and disable SPI streaming mode by default. * If ADRV9001 SPI streming mode is selected, then single instruction and single instruction are disbled */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x1); @@ -2176,15 +2180,25 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop uint32_t dataIndex = 0; uint32_t spiBufferSize = ((HAL_SPIWRITEARRAY_BUFFERSIZE / 3) - 1); uint8_t spiWriteArrray[HAL_SPIWRITEARRAY_BUFFERSIZE] = { 0 }; + uint32_t ADDR_ARM_DMA_DATA[4] = { ADRV9001_ADDR_ARM_DMA_DATA3, ADRV9001_ADDR_ARM_DMA_DATA2, ADRV9001_ADDR_ARM_DMA_DATA1, ADRV9001_ADDR_ARM_DMA_DATA0 }; + uint32_t index = 0; +#ifndef __KERNEL__ uint8_t addrMsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; uint8_t addrLsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; uint8_t dataArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; - uint32_t ADDR_ARM_DMA_DATA[4] = { ADRV9001_ADDR_ARM_DMA_DATA3, ADRV9001_ADDR_ARM_DMA_DATA2, ADRV9001_ADDR_ARM_DMA_DATA1, ADRV9001_ADDR_ARM_DMA_DATA0 }; - uint32_t index = 0; - +#else + static uint8_t addrMsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; + static uint8_t addrLsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; + static uint8_t dataArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; + + memset(addrMsbArray, 0, sizeof(addrMsbArray)); + memset(addrLsbArray, 0, sizeof(addrLsbArray)); + memset(dataArray, 0, sizeof(dataArray)); +#endif + ADI_ENTRY_PTR_ARRAY_EXPECT(device, numHopTableEntries, numHopTableEntriesByteCount); ADI_ENTRY_PTR_ARRAY_EXPECT(device, hopTableBufferData, hopTableBufferDataByteCount); - + /* Trigger appropriate SPI Interrupt upon table load */ if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) { @@ -2200,7 +2214,7 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop } ADRV9001_DMAINFO("ARM_MEM_WRITE", armMemAddress, byteCount); - + regWrite &= ~ADRV9001_DMA_CTL_RD_WRB; regWrite |= ADRV9001_DMA_CTL_SYS_CODEB; regWrite |= ADRV9001_BF_ENCODE(2, ADRV9001_DMA_CTL_BUS_SIZE_MASK, ADRV9001_DMA_CTL_BUS_SIZE_SHIFT); @@ -2248,7 +2262,7 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop dataArray[addrIndex] = numHopTableEntries[dataIndex]; addrIndex++; } - + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR3 >> 8) & 0x7F)); addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR3; dataArray[addrIndex] = (uint8_t)((hopTableBufferAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR3_BYTE_SHIFT); @@ -2398,7 +2412,7 @@ int32_t adrv9001_DmaMemRead(adi_adrv9001_Device_t *device, uint32_t address, uin returnData[i + 2] = dataRead; ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_1", ADRV9001_ADDR_ARM_DMA_DATA1, &dataRead); returnData[i + 1] = dataRead; - + /* 'single_instruction' has to be cleared before reading DMA_DATA3 and set back after */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x0); ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_0", ADRV9001_ADDR_ARM_DMA_DATA0, &dataRead); @@ -2463,7 +2477,7 @@ int32_t adrv9001_FlexStreamProcessorMemWrite(adi_adrv9001_Device_t *device, /* If Address is not on word boundary, Or ByteCount is not on Word boundary */ if (((flexSpAddress & 0x00000003) > 0) || ((byteCount & 0x00000003) > 0)) { - if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || + if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || (ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4 == spiWriteMode)) { ADI_ERROR_REPORT(&device->common, @@ -2498,7 +2512,7 @@ int32_t adrv9001_FlexStreamProcessorMemWrite(adi_adrv9001_Device_t *device, /* setting up the flex SP DMA control register for a write */ ADRV9001_SPIWRITEBYTEDMA(device, "FLEX_SP_ARM_DMA_CTL", ADRV9001_ADDR_FLEX_SP_ARM_DMA_CTL, regWrite); - + /* Enable single instruction and disable SPI streaming mode by default. * If ADRV9001 SPI streming mode is selected, then single instruction and single instruction are disbled */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x1); @@ -2761,7 +2775,7 @@ static const char* adrv9001_CmdErrMsgGet(uint32_t errCode) { return adrv9001_error_table_CmdError[6]; } - + return NULL; } @@ -2818,7 +2832,7 @@ int32_t adrv9001_ArmCmdErrorHandler(adi_adrv9001_Device_t *device, uint32_t detE ADI_EXPECT(adrv9001_ArmMailBoxErrCodeGet, device, &mailboxErrCode); errorString = adrv9001_CmdErrMsgGet(mailboxErrCode); - + ADI_ERROR_REPORT(&device->common, ADI_ADRV9001_SRC_ARMCMD, mailboxErrCode, @@ -2920,7 +2934,7 @@ static uint32_t adrv9001_ArmProfileWrite_Validate(adi_adrv9001_Device_t *device, ADI_ERROR_RETURN(device->common.error.newAction); } } - + /* Range check parameters in adi_adrv9001_TxSettings_t */ for (i = 0; i < ADI_ADRV9001_MAX_TXCHANNELS; i++) { @@ -2936,7 +2950,7 @@ static uint32_t adrv9001_ArmProfileWrite_Validate(adi_adrv9001_Device_t *device, ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.ssiDataFormatSel, ADI_ADRV9001_SSI_FORMAT_2_BIT_SYMBOL_DATA, ADI_ADRV9001_SSI_FORMAT_22_BIT_I_Q_DATA_1_BIT_GAIN_CHANGE_8_BIT_GAIN_INDEX); ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.numLaneSel, ADI_ADRV9001_SSI_1_LANE, ADI_ADRV9001_SSI_4_LANE); ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.strobeType, ADI_ADRV9001_SSI_SHORT_STROBE, ADI_ADRV9001_SSI_LONG_STROBE); - + if ((ADI_ADRV9001_SSI_TYPE_LVDS == init->tx.txProfile[i].txSsiConfig.ssiType) && (false == init->tx.txProfile[i].txSsiConfig.ddrEn) && (init->tx.txProfile[i].txInterfaceSampleRate_Hz > 30720000)) @@ -3113,7 +3127,7 @@ int32_t adrv9001_ArmProfileWrite(adi_adrv9001_Device_t *device, const adi_adrv90 cfgData[offset++] = (uint8_t)(init->clocks.armPowerSavingClkDiv - 1); cfgData[offset++] = (uint8_t)init->clocks.refClockOutEnable; - + cfgData[offset++] = (uint8_t)init->clocks.auxPllPower; cfgData[offset++] = (uint8_t)init->clocks.clkPllPower; @@ -3172,14 +3186,14 @@ int32_t adrv9001_ArmProfileWrite(adi_adrv9001_Device_t *device, const adi_adrv90 if (ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_TX_PROFILE_VALID)) { armChannels |= (init->tx.txInitChannelMask & (ADI_ADRV9001_TX1 | ADI_ADRV9001_TX2)); - + /* Tx channels must have a valid and enabled ILB channel unless the signaling is Direct FM/FSK */ if(ADRV9001_BF_EQUAL(init->tx.txInitChannelMask, ADI_ADRV9001_TX1) && (init->tx.txProfile[0].outputSignaling != ADI_ADRV9001_TX_DIRECT_FM_FSK)) { armChannels |= (init->rx.rxInitChannelMask & ADI_ADRV9001_ILB1); } - + if (ADRV9001_BF_EQUAL(init->tx.txInitChannelMask, ADI_ADRV9001_TX2) && (init->tx.txProfile[1].outputSignaling != ADI_ADRV9001_TX_DIRECT_FM_FSK)) { @@ -3468,7 +3482,7 @@ int32_t adrv9001_DynamicProfile_Write(adi_adrv9001_Device_t *device, int32_t recoveryAction = ADI_COMMON_ACT_NO_ACTION; uint32_t offset = 0; uint8_t cfgData[ADRV9001_DYNAMIC_PROFILE_BLOB_SIZE] = { 0 }; - + cfgData[offset++] = dynamicProfile->dynamicProfileIndex; cfgData[offset++] = 0; // padding cfgData[offset++] = 0; // padding diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c index 623f616122fe48..a0daf037579629 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c @@ -98,7 +98,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Write_Val // Maximum combined gain step must not exceed 29000 mdB ADI_RANGE_CHECK(device, totalGainSteps, 0, 29000); } - + /*Check that the gain index offset is within range*/ ADI_RANGE_CHECK(device, gainIndexOffset, ADI_ADRV9001_MIN_RX_GAIN_TABLE_INDEX, ADI_ADRV9001_START_RX_GAIN_INDEX); @@ -126,7 +126,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Write_Val } ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + ADI_RANGE_CHECK(device, gainTableType, ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE, ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE); /*Check that Rx profile or ORx profile is valid*/ @@ -174,7 +174,11 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, int32_t j = 0; uint16_t numGainIndicesToWrite = 0; uint8_t lnaStepOffset = { 0 }; +#ifdef __KERNEL__ + static adi_adrv9001_RxGainTableRow_t lnaGainTable[127]; +#else adi_adrv9001_RxGainTableRow_t lnaGainTable[127] = { { 0 } }; +#endif adi_adrv9001_RxGainTableRow_t *gainTablePtr = NULL; uint8_t minGainIndex = 0; uint8_t indexOffset = 0; @@ -199,7 +203,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, { if (i == 0) { - lnaStepOffset = (gainIndexOffset - (lnaConfig->minGainIndex - 1)); + lnaStepOffset = (gainIndexOffset - (lnaConfig->minGainIndex - 1)); } else { @@ -223,7 +227,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, } gainTablePtr = lnaGainTable; } - + baseIndex = (gainIndexOffset - (numGainIndicesToWrite - 1)); minGainIndex = (uint8_t)baseIndex; ADI_EXPECT(adrv9001_RxGainTableFormat, device, gainTablePtr, &armDmaData[0], numGainIndicesToWrite); @@ -327,7 +331,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Read_Vali ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcMinimumGainIndex_Get, device, instance, &minGainIndex); ADI_RANGE_CHECK(device, gainIndexOffset, minGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); - + if (((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_RX_PROFILE_VALID)) == 0) && ((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_ORX_PROFILE_VALID)) == 0) && ((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_TX_PROFILE_VALID)) == 0)) @@ -473,7 +477,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); adi_common_channel_to_index(channel, &chan_idx); - + /* Check that Rx profile is valid */ if (0 == ADRV9001_BF_EQUAL(device->devStateInfo.initializedChannels, RX_CHANNELS[chan_idx])) { @@ -492,7 +496,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcMinimumGainIndex_Get, device, instance, &minGainIndex); ADI_RANGE_CHECK(device, gainIndex, minGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); - + /* Save the current gain control mode and set to the required mode */ ADI_EXPECT(adi_adrv9001_Rx_GainControl_Mode_Get, device, channel, gainCtrlMode); if (ADI_ADRV9001_RX_GAIN_CONTROL_MODE_SPI != *gainCtrlMode) @@ -670,7 +674,7 @@ static __maybe_unused int32_t adi_adrv9001_Rx_InterfaceGain_Validate(adi_adrv900 adi_adrv9001_RxInterfaceGain_e rxInterfaceGainMax = ADI_ADRV9001_RX_INTERFACE_GAIN_NEGATIVE_36_DB; adi_common_channel_to_index(channel, &chan_index); - + if (device->devStateInfo.rxOutputRate_kHz[chan_index] < RX_OUTPUT_RATE_kHZ) { if (gainTableType == ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE) @@ -709,7 +713,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Confi adi_adrv9001_RxInterfaceGainCtrl_t *rxInterfaceGainCtrl) { adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&device->common, rxInterfaceGainCtrl); @@ -740,11 +744,11 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Confi rxInterfaceGainCtrl->rssiMovingAverageDuration, 1, 10); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); if (ADI_ADRV9001_CHANNEL_CALIBRATED != state) { - ADI_ERROR_REPORT(device, + ADI_ERROR_REPORT(device, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -823,12 +827,12 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Set_V /* Perform Range check of allowed gain value */ ADI_EXPECT(adi_adrv9001_Rx_InterfaceGain_Validate, device, channel, gainTableType, gain); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); if ((ADI_ADRV9001_CHANNEL_PRIMED != state) && (ADI_ADRV9001_CHANNEL_RF_ENABLED != state)) { - ADI_ERROR_REPORT(device, + ADI_ERROR_REPORT(device, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -1446,12 +1450,12 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_PortSwitch_Configur } /* NULL pointer check */ - ADI_NULL_PTR_RETURN(&device->common, switchConfig); + ADI_NULL_PTR_RETURN(&device->common, switchConfig); /* Freuqency range check */ - ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); - ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); - ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); /* Min frequency must be smaller than max */ @@ -1479,7 +1483,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_PortSwitch_Configur "Port A and B freuqency ranges cannot overlap."); ADI_API_RETURN(device) } - + ADI_API_RETURN(device); } @@ -1488,7 +1492,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Configure(adi_adrv9001_Device_t *device, { uint8_t armData[42] = { 0 }; uint8_t extData[3] = { 0 }; - uint32_t offset = 0u; + uint32_t offset = 0u; ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_PortSwitch_Configure_Validate, device, switchConfig); @@ -1513,7 +1517,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Configure(adi_adrv9001_Device_t *device, extData[0] = 0; extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_CFG_RX_PORT_SWITCHING; - + ADI_EXPECT(adi_adrv9001_arm_Config_Write, device, armData, sizeof(armData), extData, sizeof(extData)) ADI_API_RETURN(device); @@ -1536,7 +1540,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Inspect(adi_adrv9001_Device_t *device, ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_PortSwitch_Inspect_Validate, device, switchConfig); ADI_EXPECT(adi_adrv9001_arm_Config_Read, device, OBJID_CFG_RX_PORT_SWITCHING, channelMask, offset, armReadBack, sizeof(armReadBack)) - + adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->minFreqPortA_Hz); adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->maxFreqPortA_Hz); adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->minFreqPortB_Hz); @@ -1559,7 +1563,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_RANGE_CHECK(device, gainTableType, ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE, ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE); ADI_NULL_PTR_RETURN(&device->common, lnaConfig); - + if (!lnaConfig->externalLnaPresent) { ADI_ERROR_REPORT(&device->common, @@ -1586,7 +1590,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu ADI_RANGE_CHECK(device, lnaConfig->numberLnaGainSteps, 2, 4); //ADI_RANGE_CHECK(device, lnaConfig->settlingDelay, 0, 0); //ADI_RANGE_CHECK(device, lnaConfig->lnaDigitalGainDelay, 0, 0); - + if(0 != lnaConfig->lnaGainSteps_mdB[0]) { ADI_ERROR_REPORT(&device->common, @@ -1597,7 +1601,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu "lnaConfig->lnaGainSteps_mdB[0] should have the gain step as '0' only"); ADI_ERROR_RETURN(device->common.error.newAction); } - + for (i = 1; i < lnaConfig->numberLnaGainSteps; i++) { if ((lnaConfig->lnaGainSteps_mdB[i] == 0) || ((lnaConfig->lnaGainSteps_mdB[i] % 500) != 0)) @@ -1681,12 +1685,12 @@ int32_t adi_adrv9001_Rx_ExternalLna_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapRxb_FeGainDelayIncr_Set, device, rxbAddr, (lnaConfig->lnaDigitalGainDelay + FEGAIN_INCR_FIXED_VALUE)); ADI_EXPECT(adrv9001_NvsRegmapRxb_FeGainDelayDecr_Set, device, rxbAddr, (lnaConfig->lnaDigitalGainDelay + FEGAIN_DECR_FIXED_VALUE)); ADI_EXPECT(adrv9001_NvsRegmapRx_ExtLnaDigitalGainDelay_Set, device, rxAddr, (lnaConfig->lnaDigitalGainDelay + EXTDIGGAIN_DELAY_FIXED_VALUE)); - + if (ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE == gainTableType) { ADI_EXPECT(adrv9001_NvsRegmapRx_GainCompForExtGain_Set, device, rxAddr, (uint8_t)lnaConfig->externalLnaPresent); } - + ADI_API_RETURN(device); } @@ -1774,11 +1778,11 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Loid_Configure_Vali adi_adrv9001_RadioState_t state = { 0 }; uint8_t port_index = 0; uint8_t chan_index = 0; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, loidConfig); - + /* Validate state is STANDBY or CALIBRATED*/ ADI_EXPECT(adi_adrv9001_Radio_State_Get, adrv9001, &state); adi_common_port_to_index(ADI_RX, &port_index); @@ -1813,7 +1817,7 @@ int32_t adi_adrv9001_Rx_Loid_Configure(adi_adrv9001_Device_t *adrv9001, /* Write LOID config to ARM mailbox */ ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_SET, &armData[0], sizeof(armData), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_RX, channel); extData[1] = OBJID_GS_LOID; @@ -1825,14 +1829,14 @@ int32_t adi_adrv9001_Rx_Loid_Configure(adi_adrv9001_Device_t *adrv9001, extData[1], (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_TIMEOUT_US, (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_INTERVAL_US); - + ADI_API_RETURN(adrv9001); } static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Loid_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) -{ +{ ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, loidConfig); @@ -1844,9 +1848,9 @@ int32_t adi_adrv9001_Rx_Loid_Inspect(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) { - uint8_t armReadBack[4] = { 0 }; + uint8_t armReadBack[4] = { 0 }; uint8_t extData[2] = { 0 }; - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_RX, channel); extData[1] = OBJID_GS_LOID; @@ -1865,7 +1869,7 @@ int32_t adi_adrv9001_Rx_Loid_Inspect(adi_adrv9001_Device_t *adrv9001, &armReadBack[0], sizeof(armReadBack), ADRV9001_ARM_MEM_READ_AUTOINCR) - + loidConfig->loidEnable = armReadBack[0]; loidConfig->loidInterval = (adi_adrv9001_LoidInterval_e) armReadBack[1]; loidConfig->loidThHigh = armReadBack[2]; From 75b4c6c461c6801a26b527e56b81ac22b3546d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 23 Dec 2021 10:05:18 +0100 Subject: [PATCH 074/407] iio: adrv9002: api: fix mixed code declarations warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the mixed code declarations warnings for platforms using C90 where it is forbidden. Example of this is compiling the API under the linux kernel. Signed-off-by: Nuno Sá --- .../adrv9001/public/src/adi_adrv9001_fh.c | 130 +++++++++--------- .../adrv9001/public/src/adi_adrv9001_tx.c | 109 +++++++-------- 2 files changed, 121 insertions(+), 118 deletions(-) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c index 2ed96d33f8b80e..83a1f24be56a51 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c @@ -57,7 +57,7 @@ if (device->devStateInfo.frequencyHoppingEnabled == 0) \ ADI_API_RETURN(device); \ } -/* TODO JP: Determine if we need to validate the whole table. +/* TODO JP: Determine if we need to validate the whole table. It's difficult to validate the hop table due to the following: 1) At the time of receiving the HOP table, we don't know the channel sequence. So a tx or rx gain index might be valid, or it might be a 'don't care' value, programmed by the user. We could potentially enforce the @@ -65,7 +65,7 @@ if (device->devStateInfo.frequencyHoppingEnabled == 0) \ 2) There doesn't seem a nice way to validate the rx gain in API, since there is no state of the FH operating gain range. The best we could do would be to ensure its within the absolute min/max. However, this could be effected by point 1. - 3) Validating the whole table before its written to ARM might be valuable, however, it might + 3) Validating the whole table before its written to ARM might be valuable, however, it might also waste time. Especially considering we can't validate every field in the table. It might be better for ARM to validate it once received, or on the fly. */ @@ -75,8 +75,8 @@ static __maybe_unused int32_t adi_adrv9001_fh_FrameInfo_Validate(adi_adrv9001_De /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); - ADI_RANGE_CHECK_X(adrv9001, hopFrame->hopFrequencyHz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, hopFrame->hopFrequencyHz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); ADI_API_RETURN(adrv9001); } @@ -95,11 +95,11 @@ static uint32_t adi_adrv9001_fh_GetHopTableBufferAddress(adi_adrv9001_Device_t * adrv9001_ParseFourBytes(&offset, hopTableBufferAddressBlock, &hopTableBufferAddress); return hopTableBufferAddress; -} +} static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) -{ +{ uint32_t i; uint32_t j; uint8_t numHopSignals; @@ -139,7 +139,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } /* Can be unassigned but throw an error if it's set to analog*/ ADI_RANGE_CHECK(adrv9001, fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[0].pin, ADI_ADRV9001_GPIO_UNASSIGNED, ADI_ADRV9001_GPIO_DIGITAL_15); - if ((fhConfig->hopTableSelectConfig.hopTableSelectMode == ADI_ADRV9001_FHHOPTABLESELECTMODE_INDEPENDENT) + if ((fhConfig->hopTableSelectConfig.hopTableSelectMode == ADI_ADRV9001_FHHOPTABLESELECTMODE_INDEPENDENT) && (fhConfig->mode == ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP)) { /* Can be unassigned but throw an error if it's set to analog*/ @@ -184,18 +184,18 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De "Value must be non-zero in Tx only operation"); ADI_API_RETURN(adrv9001); } - + /* Check mode*/ ADI_RANGE_CHECK(adrv9001, fhConfig->mode, ADI_ADRV9001_FHMODE_LO_MUX_PREPROCESS, ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP); /* Check tableIndexCtrl_e */ ADI_RANGE_CHECK(adrv9001, fhConfig->tableIndexCtrl, ADI_ADRV9001_TABLEINDEXCTRL_AUTO_LOOP, ADI_ADRV9001_TABLEINDEXCTRL_GPIO); /* Check operating frequency range */ - ADI_RANGE_CHECK_X(adrv9001, fhConfig->minOperatingFrequency_Hz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, fhConfig->minOperatingFrequency_Hz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); - ADI_RANGE_CHECK_X(adrv9001, fhConfig->maxOperatingFrequency_Hz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, fhConfig->maxOperatingFrequency_Hz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); if (fhConfig->minOperatingFrequency_Hz >= fhConfig->maxOperatingFrequency_Hz) @@ -209,12 +209,12 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De ADI_API_RETURN(adrv9001); } /* Check RX gain ranges */ - ADI_RANGE_CHECK(adrv9001, fhConfig->minRxGainIndex, - ADI_ADRV9001_RX_GAIN_INDEX_MIN, + ADI_RANGE_CHECK(adrv9001, fhConfig->minRxGainIndex, + ADI_ADRV9001_RX_GAIN_INDEX_MIN, fhConfig->maxRxGainIndex); /* Max index can be equal to min and no greater than rx1MaxGainIndex */ - ADI_RANGE_CHECK(adrv9001, fhConfig->maxRxGainIndex, - fhConfig->minRxGainIndex, + ADI_RANGE_CHECK(adrv9001, fhConfig->maxRxGainIndex, + fhConfig->minRxGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); /* TODO JP: Investigate requirements for TX attenuation in diversity mode. Will min/max be the same, or will we need a seperate field? @@ -243,7 +243,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } /* Check frequency select pins */ - if (ADI_ADRV9001_TABLEINDEXCTRL_GPIO == fhConfig->tableIndexCtrl) + if (ADI_ADRV9001_TABLEINDEXCTRL_GPIO == fhConfig->tableIndexCtrl) { ADI_RANGE_CHECK(adrv9001, fhConfig->numTableIndexPins, 1u, ADI_ADRV9001_FH_MAX_NUM_FREQ_SELECT_PINS); for (i = 0; i < fhConfig->numTableIndexPins; i++) @@ -252,13 +252,13 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } } /* Configure gain select pins */ - if (true == fhConfig->gainSetupByPin) + if (true == fhConfig->gainSetupByPin) { for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) { if ((initializedChannelMask & (j == 0? channel1Mask:channel2Mask)) != 0x00u) { - + ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].numGainCtrlPins, 1u, ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_PINS); for (i = 0; i < fhConfig->gainSetupByPinConfig[j].numGainCtrlPins; i++) { @@ -267,7 +267,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De maxPossibleGainEntries = (1u << fhConfig->gainSetupByPinConfig[j].numGainCtrlPins); } - + if (ADRV9001_BF_EQUAL(adrv9001->devStateInfo.initializedChannels, CHANNELS[ADI_RX][j])) { /* Validate Rx gain table is within range specified by fhConfig */ @@ -285,7 +285,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De { ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].txAttenTable[i], fhConfig->minTxAtten_mdB, fhConfig->maxTxAtten_mdB); } - } + } } } @@ -294,7 +294,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De static __maybe_unused int32_t adi_adrv9001_fh_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) -{ +{ /* Check for NULL pointer */ ADI_NULL_PTR_RETURN(&adrv9001->common, fhConfig); ADI_API_RETURN(adrv9001); @@ -303,12 +303,15 @@ static __maybe_unused int32_t adi_adrv9001_fh_Inspect_Validate(adi_adrv9001_Devi static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhMode_e mode, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t tableSize) { - uint32_t frequencyIndex = 0; + uint32_t frequencyIndex = 0; uint32_t tempAddress = 0; + uint8_t maxNumHopFrequencies = (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) ? ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE : + (ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE) / 2; + if (tableId == ADI_ADRV9001_FHHOPTABLE_A) { if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) @@ -331,8 +334,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate tempAddress = adrv9001->devStateInfo.fhHopTableB2Addr; } } - uint8_t maxNumHopFrequencies = (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) ? ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE : - (ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE) / 2; + /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); /* Check for NULL pointer */ @@ -352,7 +354,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate ADI_API_RETURN(adrv9001); } - if ((hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_2) + if ((hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_2) && (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP)) { ADI_ERROR_REPORT(&adrv9001->common, @@ -364,7 +366,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate ADI_API_RETURN(adrv9001); } - + /* Check fhHopTable->numHopFrames are valid */ ADI_RANGE_CHECK(adrv9001, tableSize, 1u, maxNumHopFrequencies); @@ -374,7 +376,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate } ADI_API_RETURN(adrv9001); -} +} static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal, @@ -426,7 +428,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Inspect_Validate(adi_adrv } ADI_API_RETURN(adrv9001); -} +} int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) @@ -472,7 +474,7 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, armData[offset++] = fhConfig->tableIndexCtrl; armData[offset++] = fhConfig->gainSetupByPin; armData[offset++] = fhConfig->hopTableSelectConfig.hopTableSelectMode; - + armData[offset++] = hop1SignalsPortMask; armData[offset++] = hop2SignalsPortMask; @@ -491,14 +493,14 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, armData[offset++] = fhConfig->rxZeroIfEnable; offset += 2u; /* padding */ /* If in gain select by pin mode, load Rx gain and Tx attenuation tables */ - if (fhConfig->gainSetupByPin == true) + if (fhConfig->gainSetupByPin == true) { /* Load Rx gain and Tx atten table */ armData[offset++] = fhConfig->gainSetupByPinConfig[0].numRxGainTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[1].numRxGainTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[0].numTxAttenTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[1].numTxAttenTableEntries; - /* Create a second offset variable to point to the Tx atten table location. + /* Create a second offset variable to point to the Tx atten table location. Rx gain index is 1 byte, so second offset is offset + (ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES * 1) */ tempOffset = offset + 2 * ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; @@ -573,7 +575,7 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, } } /* Configure gain index pins if selected */ - if (fhConfig->gainSetupByPin == true) + if (fhConfig->gainSetupByPin == true) { /* Configure ADRV9001 GPIOs */ for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) @@ -632,7 +634,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a fhConfig->tableIndexCtrl = armData[offset++]; fhConfig->gainSetupByPin = armData[offset++]; fhConfig->hopTableSelectConfig.hopTableSelectMode = armData[offset++]; - + hop1SignalsPortMask = armData[offset++]; offset++; fhConfig->rxPortHopSignals[0] = ((hop1SignalsPortMask & 0x1) == 1) ? ADI_ADRV9001_FH_HOP_SIGNAL_1 : ADI_ADRV9001_FH_HOP_SIGNAL_2; @@ -662,7 +664,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a { fhConfig->gainSetupByPinConfig[j].numTxAttenTableEntries = armData[offset++]; } - + tempOffset = offset + 2 * ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; /* Rx and Tx tables */ for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) @@ -699,13 +701,13 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP, &(fhConfig->hopSignalGpioConfig[0])); ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_TABLE_SELECT, &(fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[0])); - + if (fhConfig->mode == ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) { ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2, &(fhConfig->hopSignalGpioConfig[1])); ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2_TABLE_SELECT, &(fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[1])); } - + /* Inspect table index pins if selected */ if (fhConfig->tableIndexCtrl == ADI_ADRV9001_TABLEINDEXCTRL_GPIO) { @@ -728,7 +730,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhMode_e mode, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t hopTableSize) { @@ -738,7 +740,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 uint32_t frequencyIndex = 0; uint8_t numHopTableEntries[4u]; uint32_t hopTableBufferAddress = 0; - + /* ARM Data is written directly to ARM memory because FREQ_HOPPING_NUM_BYTES is greater than set buffer size */ #ifndef __KERNEL__ uint8_t armData[FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; @@ -776,8 +778,8 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 hopTableAddress = adrv9001->devStateInfo.fhHopTableB2Addr; hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB2Addr; } - } - + } + adrv9001_LoadFourBytes(&offset, numHopTableEntries, hopTableSize); offset = 0; for (frequencyIndex = 0; frequencyIndex < hopTableSize; frequencyIndex++) @@ -792,7 +794,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 armData[offset++] = hopTable[frequencyIndex].tx1Attenuation_fifthdB; armData[offset++] = hopTable[frequencyIndex].tx2Attenuation_fifthdB; } - + /* Write the data directly to the ARM memory */ /* 'offset' is used to represent the exact number of bytes to write to avoid writing over the entire table */ ADI_EXPECT(adi_adrv9001_arm_Memory_WriteFH, adrv9001, hopSignal, tableId, hopTableAddress, numHopTableEntries, sizeof(numHopTableEntries), hopTableBufferAddress, armData, offset); @@ -801,7 +803,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t hopTableSize, uint32_t *numHopFramesRead) @@ -828,7 +830,7 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, memset(&armData, 0, sizeof(armData)); #endif - + if (tableId == ADI_ADRV9001_FHHOPTABLE_A) { if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) @@ -854,10 +856,10 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, hopTableAddress = adrv9001->devStateInfo.fhHopTableB2Addr; hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB2Addr; } - } + } ADI_PERFORM_VALIDATION(adi_adrv9001_fh_HopTable_Inspect_Validate, adrv9001, hopSignal, tableId, hopTable, hopTableSize); - /* Even though we are going to read directly from ARM memory, we can still use the GET protocol to + /* Even though we are going to read directly from ARM memory, we can still use the GET protocol to tell ARM how many bytes we will read. ARM will return an error if the read size is invalid */ adrv9001_LoadFourBytes(&offset, armData, sizeof(armData)); @@ -873,7 +875,7 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, OBJID_GO_GET_FH_HOP_TABLE, ADI_ADRV9001_DEFAULT_TIMEOUT_US, ADI_ADRV9001_DEFAULT_INTERVAL_US); - + /* First read number of frequencies in hop table */ offset = 0; ADI_EXPECT(adi_adrv9001_arm_Memory_Read, adrv9001, hopTableAddress, numHopFrequenciesReadbackBlock, sizeof(numHopFrequenciesReadbackBlock), false); @@ -975,7 +977,7 @@ int32_t adi_adrv9001_fh_HopTable_Get(adi_adrv9001_Device_t *adrv9001, ADI_API_RETURN(adrv9001); } -int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhFrameIndex_e frameIndex, adi_adrv9001_FhHopFrame_t *hopFrame) { @@ -989,7 +991,7 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, ADI_FH_CHECK_FH_ENABLED(adrv9001); ADI_NULL_PTR_RETURN(&adrv9001->common, hopFrame); ADI_RANGE_CHECK(adrv9001, frameIndex, ADI_ADRV9001_FHFRAMEINDEX_CURRENT_FRAME, ADI_ADRV9001_FHFRAMEINDEX_NEXT_FRAME); - + /* Write the size to the GET buffer */ adrv9001_LoadFourBytes(&offset, armData, sizeof(armData)); ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_GET, armData, sizeof(uint32_t), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); @@ -1021,9 +1023,9 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, hopFrame->tx1Attenuation_fifthdB = armData[offset++]; hopFrame->tx2Attenuation_fifthdB = armData[offset++]; ADI_API_RETURN(adrv9001); -} +} -int32_t adi_adrv9001_fh_Hop(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_fh_Hop(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal) { /* Flip the hop signal */ @@ -1060,7 +1062,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_NumberOfHops_Get(adi_adrv9001_Devi default: ADI_SHOULD_NOT_EXECUTE(adrv9001); } - + ADI_API_RETURN(adrv9001); } @@ -1092,7 +1094,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure_Validat mode, "FH mode must be dual hop for hopSignal to be HOP_2 "); } - + } ADI_ENTRY_PTR_EXPECT(adrv9001, spiPackedFhTable); @@ -1120,7 +1122,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure_Validat ADI_COMMON_ACT_ERR_CHECK_PARAM, tableSize, "spiPackedFhTable[] size is not sufficient "); - + } for (frequencyIndex = 0; frequencyIndex < tableSize; frequencyIndex++) { @@ -1197,7 +1199,7 @@ static uint32_t adrv9001_HopTable_Spi_Pack(adi_adrv9001_Device_t *adrv9001, /* Issue SW interrupt 4 or 11 to load FH table A or B. The SPI reg is self-cleared so there is no need to do read/mod/write. */ adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADRV9001_ADDR_SW_INTERRUPT_4, bitmSwInt, ADRV9001_SPI_WRITE_POLARITY); - + /* Restore back the original values of ADRV9001 DMA control register */ adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADRV9001_ADDR_ARM_DMA_CTL, regVal, ADRV9001_SPI_WRITE_POLARITY); @@ -1237,10 +1239,10 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 if (ADI_ADRV9001_FH_HOP_SIGNAL_1 == hopSignal) { bitmSwInt_A = 0x1; - hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; armAddr_A = adrv9001->devStateInfo.fhHopTableA1Addr; - bitmSwInt_B = 0x80; + bitmSwInt_B = 0x80; hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; armAddr_B = adrv9001->devStateInfo.fhHopTableB1Addr; } @@ -1257,12 +1259,12 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 } else { - bitmSwInt_A = 0x1; - hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + bitmSwInt_A = 0x1; + hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; armAddr_A = adrv9001->devStateInfo.fhHopTableA1Addr; - bitmSwInt_B = 0x2; - hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; + bitmSwInt_B = 0x2; + hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; armAddr_B = adrv9001->devStateInfo.fhHopTableB1Addr; } @@ -1303,7 +1305,7 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 adrv9001_LoadTwoBytes(&offset, fhTable_A, hopTable[i + j].tx2Attenuation_fifthdB); } ADI_EXPECT(adrv9001_HopTable_Spi_Pack, adrv9001, addrArray_A, fhTable_A, numberOfHops, &numWrBytes, bitmSwInt_A, spiPackedFhTable); - + offset = 0; for (j = numberOfHops; j < (2 * numberOfHops); j++) { @@ -1349,7 +1351,7 @@ int32_t adi_adrv9001_fh_HopTable_BytesPerTable_Get(adi_adrv9001_Device_t *adrv90 ADI_EXPECT(adi_adrv9001_fh_NumberOfHops_Get, adrv9001, numberHopsPerDynamicLoad, &numberOfHops); spiPackBytesPerTable = spiConfigBytes + spiAddrPackLength + spiInterruptBytes; - + payloadBytes = ((sizeof(adrv9001_FhHopFrame_t) * numberOfHops) + fhBytesLength) * 3; *bytesPerTable = payloadBytes + spiPackBytesPerTable; diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c index a250a0e0369bef..dad674752fb722 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c @@ -168,7 +168,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_AttenuationMode_Set currentState.channelStates[port_index][chan_index], "Error while attempting to set attenuation mode. Channel must be in STANDBY or CALIBRATED."); } - + /* Retrieve attenuation mode */ ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Get, device, channel, &txModeRead); if (txModeRead == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) @@ -195,14 +195,14 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Set(adi_adrv9001_Device_t *device, txChannelBaseAddr = Tx_Addr_Get(channel); device->devStateInfo.txAttenMode[channel - 1] = mode; - + if (mode == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) { mode = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI; } ADI_EXPECT(adrv9001_NvsRegmapTx_TxAttenMode_Set, device, txChannelBaseAddr, (uint8_t)mode); - + ADI_API_RETURN(device) } @@ -220,9 +220,10 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Get(adi_adrv9001_Device_t *device, adi_common_ChannelNumber_e channel, adi_adrv9001_TxAttenuationControlMode_e *mode) { - ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_AttenuationMode_Get_Validate, device, channel, mode); - adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; + + ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_AttenuationMode_Get_Validate, device, channel, mode); + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_TX, channel, &state); if (state == ADI_ADRV9001_CHANNEL_PRIMED) { @@ -959,9 +960,9 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat { int32_t txSampleRateDiv2_Hz = 0; adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + ADI_NULL_PTR_RETURN(&adrv9001->common, tone); if (tone->enable) { @@ -980,7 +981,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat "Channel state must be CALIBRATED"); } } - + ADI_API_RETURN(adrv9001); } @@ -991,7 +992,7 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Configure(adi_adrv9001_Device_t * uint8_t armData[12] = { 0 }; uint8_t extData[5] = { 0 }; uint32_t offset = 0; - + ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_InternalToneGeneration_Configure_Validate, adrv9001, channel, tone); adrv9001_LoadFourBytes(&offset, armData, sizeof(armData) - sizeof(uint32_t)); @@ -999,7 +1000,7 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Configure(adi_adrv9001_Device_t * armData[offset++] = tone->amplitude; offset += 2; adrv9001_LoadFourBytes(&offset, armData, tone->frequency_Hz); - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_TX, channel); extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_CFG_TX_INTERNAL_TONE_GENERATION; @@ -1014,10 +1015,10 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat adi_adrv9001_TxInternalToneGeneration_t *tone) { adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, tone); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, adrv9001, ADI_TX, channel, &state); if (ADI_ADRV9001_CHANNEL_STANDBY == state) { @@ -1028,7 +1029,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat state, "Channel state must be any of CALIBRATED, PRIMED, RF_ENABLED"); } - + ADI_API_RETURN(adrv9001); } @@ -1039,12 +1040,12 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Inspect(adi_adrv9001_Device_t *ad uint8_t armReadBack[8] = { 0 }; uint8_t channelMask = 0; uint32_t offset = 0; - + ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_InternalToneGeneration_Inspect_Validate, adrv9001, channel, tone); channelMask = adi_adrv9001_Radio_MailboxChannel_Get(ADI_TX, channel); ADI_EXPECT(adi_adrv9001_arm_Config_Read, adrv9001, OBJID_CFG_TX_INTERNAL_TONE_GENERATION, channelMask, offset, armReadBack, sizeof(armReadBack)); - + tone->enable = (bool)armReadBack[offset++]; tone->amplitude = (adi_adrv9001_TxInternalToneAmplitude_e)armReadBack[offset++]; offset += 2; @@ -1202,7 +1203,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_PaRamp_Configure_Va { ADI_RANGE_CHECK(device, paRampCfg->gpioSource, ADI_ADRV9001_GPIO_UNASSIGNED, ADI_ADRV9001_GPIO_DIGITAL_15); } - + ADI_RANGE_CHECK(device, paRampCfg->rampClock_kHz, ADRV9001_TX_PA_RAMP_MIN_CLK_KHZ, ADRV9001_TX_PA_RAMP_MAX_CLK_KHZ); ADI_API_RETURN(device); @@ -1289,7 +1290,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, uint32_t refClk_Hz = 0; ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_PaRamp_Configure_Validate, device, channel, paRampCfg); - + // Use Analog RefClkDivRatio, DEVCLKOUT Divider not used here ADI_EXPECT(adrv9001_NvsRegmapCore3_RefClkIntDevclkDivideRatio_Get, device, &clkDivRatio); @@ -1297,9 +1298,9 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, refClk_Hz = KILO_TO_BASE_UNIT(device->devStateInfo.deviceClock_kHz) >> clkDivRatio; paRampDpClkDiv = DIV_ROUND_CLOSEST(refClk_Hz, KILO_TO_BASE_UNIT(paRampCfg->rampClock_kHz)); - + ADI_EXPECT(adi_adrv9001_AuxDac_Configure, device, paRampCfg->auxDacChannelSelect, paRampCfg->enable); - + switch (paRampCfg->auxDacChannelSelect) { case ADI_ADRV9001_AUXDAC0: @@ -1318,7 +1319,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_SHOULD_NOT_EXECUTE(device); break; } - + /* crossbar config for AUX DAC 0/1/2/3. Bit[0]: xbar 0 select: 1: TX2, 0: TX1 Bit[1]: xbar 1 select: 1: TX2, 0: TX1 @@ -1381,7 +1382,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, } muxSel = dataConfig; ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, muxSel); - + bfValue = (uint8_t) paRampCfg->triggerSelect; if (channel == ADI_CHANNEL_1) @@ -1394,14 +1395,14 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigStartDelay_Set, device, paRampCfg->triggerDelayRise); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigEndDelay_Set, device, paRampCfg->triggerDelayFall); // Set Ramp Clock to max for LUTWrite - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_ENABLE_PIN) - { + { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStopSel_Set, device, 0x1); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStopSel_Set, device, 0x1); @@ -1411,16 +1412,16 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStartSel_Set, device, bfValue); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStopSel_Set, device, bfValue); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStartSel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStopSel_Set, device, 0x0); } - + // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioSel_Set, device, (uint8_t)paRampCfg->gpioSource - 1); - - + + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_GPIO) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioMask_Set, device, 0x0); @@ -1446,16 +1447,16 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, /* Configure the delays */ ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigStartDelay_Set, device, paRampCfg->triggerDelayRise); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigEndDelay_Set, device, paRampCfg->triggerDelayFall); - + // Set Ramp Clock to max for LUTWrite - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + if (bfValue == 0x2) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStartSel_Set, device, 0x1); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, 0x1); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStopSel_Set, device, 0x1); @@ -1465,7 +1466,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStartSel_Set, device, bfValue); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, bfValue); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStartSel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStopSel_Set, device, 0x0); @@ -1474,7 +1475,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioSel_Set, device, (uint8_t)paRampCfg->gpioSource - 1); - + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_GPIO) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioMask_Set, device, 0x0); @@ -1484,7 +1485,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioMask_Set, device, 0x1); } - + /* Enable the clock only after all registers are configured */ ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Set, device, 0x1); @@ -1521,7 +1522,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_LutRdEnable_Set, device, 0x1); /* Read PA LUT data */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampLutRdData_Get, device, &bfValue); - + if (channel == ADI_CHANNEL_1) { @@ -1532,7 +1533,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1UpThreshold_Set, device, paRampCfg->upEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1DownThreshold_Set, device, paRampCfg->downEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1Asymmetric_Set, device, (uint8_t)paRampCfg->asymmetricRamp); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkEn_Set, device, (uint8_t)paRampCfg->enable); } else @@ -1544,10 +1545,10 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2UpThreshold_Set, device, paRampCfg->upEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2DownThreshold_Set, device, paRampCfg->downEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2Asymmetric_Set, device, (uint8_t)paRampCfg->asymmetricRamp); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Set, device, (uint8_t)paRampCfg->enable); } - + ADI_API_RETURN(device); } @@ -1658,14 +1659,14 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, uint8_t triggerSelectValue = 0; ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_PaRamp_Inspect_Validate, device, channel, paRampCfg); - + // Set all AuxDAC SPI Words to 0x0, Set Mux to 0x0 (all SPI), restore after LUTRead to prevent unwanted output on AuxDACs ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Get, device, &muxSelProgrammed); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Get, device, &spiWordProgrammed[0]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac1_Get, device, &spiWordProgrammed[1]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac2_Get, device, &spiWordProgrammed[2]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac3_Get, device, &spiWordProgrammed[3]); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac1_Set, device, 0x0); @@ -1676,7 +1677,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore3_RefClkIntDevclkDivideRatio_Get, device, &clkDivRatio); refClk_Hz = KILO_TO_BASE_UNIT(device->devStateInfo.deviceClock_kHz) >> clkDivRatio; - + // Not possible to return the configured AuxDAC for each channel based on XBAR..._Inspect will always return ADI_ADRV9001_AUXDAC0 paRampCfg->auxDacChannelSelect = ADI_ADRV9001_AUXDAC0; @@ -1693,7 +1694,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, rampClock_kHz = refClk_Hz / paRampDpClkDiv; /* Convert to kHz */ paRampCfg->rampClock_kHz = rampClock_kHz / 1000; - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); } else { @@ -1708,7 +1709,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, rampClock_kHz = refClk_Hz / paRampDpClkDiv; /* Convert to kHz */ paRampCfg->rampClock_kHz = rampClock_kHz / 1000; - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, 0x0); } for (idx = 0; idx < ADRV9001_TX_PA_RAMP_LUT_SIZE; idx++) @@ -1727,7 +1728,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, /* De-select pa_ramp_tx1_lut_sel bit */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1LutSel_Set, device, 0x0); // Restore Ramp Clock to configured after read - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); /* Set PA Ramp up/down threshold for Tx1 */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1UpThreshold_Get, device, &(paRampCfg->upEndIndex)); @@ -1740,7 +1741,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, /* De-select pa_ramp_tx2_lut_sel bit */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2LutSel_Set, device, 0x0); // Restore Ramp Clock to configured after read - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); /* Set PA Ramp up/down threshold for Tx2 */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2UpThreshold_Get, device, &(paRampCfg->upEndIndex)); @@ -1763,7 +1764,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioSel_Get, device, &bfValue); - paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; + paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnable_Get, device, &bfValue); @@ -1772,7 +1773,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigStartDelay_Get, device, &(paRampCfg->triggerDelayRise)); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigEndDelay_Get, device, &(paRampCfg->triggerDelayFall)); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkEn_Get, device, &bfValue); paRampCfg->enable = (bool)bfValue; } @@ -1790,7 +1791,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioSel_Get, device, &bfValue); - paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; + paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnable_Get, device, &bfValue); @@ -1799,11 +1800,11 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigStartDelay_Get, device, &(paRampCfg->triggerDelayRise)); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigEndDelay_Get, device, &(paRampCfg->triggerDelayFall)); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Get, device, &bfValue); paRampCfg->enable = (bool)bfValue; } - + // Restore AuxDAC SPI Words and Mux after LUTRead complete ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, muxSelProgrammed); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Set, device, spiWordProgrammed[0]); @@ -2055,7 +2056,7 @@ int32_t adi_adrv9001_Tx_DataPath_Loopback_Set(adi_adrv9001_Device_t *device, { adrv9001_BfNvsRegmapTx_e baseAddr = ADRV9001_BF_TX1_CORE; ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + if (ADI_CHANNEL_2 == channel) { baseAddr = ADRV9001_BF_TX2_CORE; From 591dfa9ee3b74acbe5aa9ccaafa39136b932bfca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Tue, 17 Aug 2021 16:08:12 +0200 Subject: [PATCH 075/407] iio: adrv9002: api: add api to get gpio direction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an API to allow reading the direction of a GPIO. This change has to be re-applied as it's still not merged into the "upstream" sdk code. Signed-off-by: Nuno Sá --- .../public/include/adi_adrv9001_gpio.h | 49 +++++++++++++------ .../adrv9001/public/src/adi_adrv9001_gpio.c | 32 ++++++++++++ 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h index 68f201360348d8..a3eb3ff0d59b57 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h @@ -120,7 +120,7 @@ int32_t adi_adrv9001_gpio_GpIntStatus_Get(adi_adrv9001_Device_t *adrv9001, uint3 * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_OutputPinLevel_Set(adi_adrv9001_Device_t *adrv9001, - adi_adrv9001_GpioPin_e pin, + adi_adrv9001_GpioPin_e pin, adi_adrv9001_GpioPinLevel_e level); /** @@ -158,58 +158,75 @@ int32_t adi_adrv9001_gpio_OutputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin, adi_adrv9001_GpioPinLevel_e *gpioInPinLevels); - + +/** + * \brief Reads the ADRV9001 GPIO pin direction for BITBANG mode + * + * This function allows reading the direction of the GPIO + * + * \note Message type: \ref timing_direct "Direct register access" + * + * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure + * \param[in] pin The pin for which to get the direction + * \param[out] direction Current direction of the pin + * + * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover + */ +int32_t adi_adrv9001_gpio_PinDirection_Get(adi_adrv9001_Device_t *device, + adi_adrv9001_GpioPin_e pin, + adi_adrv9001_GpioPinDirection_e *direction); + /** * \brief Configure specified pin as manual input - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] pin The GPIO pin to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_ManualInput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin); - + /** * \brief Configure specified pin crumb as manual output - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] crumb The GPIO pin crumb to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_ManualOutput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPinCrumbSel_e crumb); /** * \brief Configure specified analog GPIO pin as manual input - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] pin The analog GPIO pin to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin); /** * \brief Configure specified analog GPIO pin nibble as manual output - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] nibble The analog GPIO pin nibble to configure * \param[in] source The source signal to be output on the pins - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioAnalogPinNibbleSel_e nibble); /** @@ -224,7 +241,7 @@ int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *ad */ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioCtrlInitCfg_t *gpioCtrlInitCfg); - + /** * \brief Configure the ADRV9001 GPIO for the specified signal * @@ -241,7 +258,7 @@ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, int32_t adi_adrv9001_gpio_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioSignal_e signal, adi_adrv9001_GpioCfg_t *gpioConfig); - + /** * \brief Retrieve the ADRV9001 GPIO configuration for the requested signal * diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c index 30800ec233900d..a52a549e67eff3 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c @@ -224,6 +224,38 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_gpio_ManualAnalogInput ADI_API_RETURN(device); } +static __maybe_unused int32_t adi_adrv9001_gpio_PinDirection_Get_Validate(adi_adrv9001_Device_t *device, + adi_adrv9001_GpioPin_e pin) +{ + ADI_API_RETURN(device); + ADI_RANGE_CHECK(device, pin, ADI_ADRV9001_GPIO_DIGITAL_00, ADI_ADRV9001_GPIO_ANALOG_11); +} + +int32_t adi_adrv9001_gpio_PinDirection_Get(adi_adrv9001_Device_t *device, + adi_adrv9001_GpioPin_e pin, + adi_adrv9001_GpioPinDirection_e *direction) +{ + uint16_t gpioOutEn = 0; + + ADI_PERFORM_VALIDATION(adi_adrv9001_gpio_PinDirection_Get_Validate, device, pin); + if (ADI_ADRV9001_GPIO_DIGITAL_00 <= pin && pin <= ADI_ADRV9001_GPIO_DIGITAL_15) + { + ADI_EXPECT(adrv9001_NvsRegmapCore_NvsGpioDirectionControlOe_Get, device, &gpioOutEn); + *direction = (gpioOutEn & (1 << (pin - 1))) >> (pin - 1); + } + else if (ADI_ADRV9001_GPIO_ANALOG_00 <= pin && pin <= ADI_ADRV9001_GPIO_ANALOG_11) + { + ADI_EXPECT(adrv9001_NvsRegmapCore1_NvsGpioAnalogDirectionControlOe_Get, device, &gpioOutEn); + *direction = (gpioOutEn & (1 << (pin - ADI_ADRV9001_GPIO_ANALOG_00))) >> (pin - ADI_ADRV9001_GPIO_ANALOG_00); + } + else + { + ADI_SHOULD_NOT_EXECUTE(device); + } + + ADI_API_RETURN(device); +} + int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *device, adi_adrv9001_GpioPin_e pin) { From b8f5687d19a7d817608673b8d8aacbaa929a33d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 23 Dec 2021 15:02:43 +0100 Subject: [PATCH 076/407] iio: adrv9002: adapt to the new API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two mains things that had to be changed: 1) Gain setup by pin in Frequency hopping can now be done by channel. Hence the devicetree parsing and the table load attr had to be changed accordingly. Ditto for the debugfs interface. 2) The digital interface gain has now RSSI parameters. So, when changing the control mode we need to get the complete structure and only change the mode. Otherwise we would get an error from the API since these values cannot be 0. Signed-off-by: Nuno Sá --- drivers/iio/adc/navassa/adrv9002.c | 126 +++++++++++++-------- drivers/iio/adc/navassa/adrv9002_debugfs.c | 27 +++-- 2 files changed, 96 insertions(+), 57 deletions(-) diff --git a/drivers/iio/adc/navassa/adrv9002.c b/drivers/iio/adc/navassa/adrv9002.c index 2f341cc640905d..12e742fa6b5cf6 100644 --- a/drivers/iio/adc/navassa/adrv9002.c +++ b/drivers/iio/adc/navassa/adrv9002.c @@ -94,7 +94,7 @@ #define ADRV9002_HP_CLK_PLL_DAHZ 884736000 /* Frequency hopping */ -#define ADRV9002_FH_TABLE_COL_SZ 5 +#define ADRV9002_FH_TABLE_COL_SZ 7 /* IRQ Masks */ #define ADRV9002_GP_MASK_RX_DP_RECEIVE_ERROR 0x08000000 @@ -898,25 +898,8 @@ static int adrv9002_set_digital_gain_ctl_mode(struct iio_dev *indio_dev, const int chann = ADRV_ADDRESS_CHAN(chan->address); struct adrv9002_rx_chan *rx = &phy->rx_channels[chann]; int ret; - struct adi_adrv9001_RxInterfaceGainCtrl rx_intf_gain_mode = { - .updateInstance = ADI_ADRV9001_RX_INTERFACE_GAIN_UPDATE_TIMING_NOW, - /* - * Reset gain to 0db. The reason is that depending on the gain - * table and the profile being used, some gains that make sense - * in one mode, might not make sense in the mode we are trying - * to change to. - */ - .gain = ADI_ADRV9001_RX_INTERFACE_GAIN_0_DB, - }; - - switch (mode) { - case ADI_ADRV9001_RX_INTERFACE_GAIN_CONTROL_AUTOMATIC: - case ADI_ADRV9001_RX_INTERFACE_GAIN_CONTROL_MANUAL: - rx_intf_gain_mode.controlMode = mode; - break; - default: - return -EINVAL; - }; + struct adi_adrv9001_RxInterfaceGainCtrl rx_intf_gain_mode = {0}; + u32 gain_table_type; mutex_lock(&phy->lock); if (!rx->channel.enabled) { @@ -924,6 +907,15 @@ static int adrv9002_set_digital_gain_ctl_mode(struct iio_dev *indio_dev, return -ENODEV; } + ret = adi_adrv9001_Rx_InterfaceGain_Inspect(phy->adrv9001, rx->channel.number, + &rx_intf_gain_mode, &gain_table_type); + if (ret) { + mutex_unlock(&phy->lock); + return adrv9002_dev_err(phy); + } + + rx_intf_gain_mode.controlMode = mode; + ret = adrv9002_channel_to_state(phy, &rx->channel, ADI_ADRV9001_CHANNEL_CALIBRATED, true); if (ret) goto unlock; @@ -1385,7 +1377,7 @@ static const u32 tx_track_calls[] = { [TX_LOL] = ADI_ADRV9001_TRACKING_CAL_TX_LO_LEAKAGE, [TX_LB_PD] = ADI_ADRV9001_TRACKING_CAL_TX_LB_PD, [TX_PAC] = ADI_ADRV9001_TRACKING_CAL_TX_PAC, - [TX_CLGC] = ADI_ADRV9001_TRACKING_CAL_TX_CLGC + [TX_CLGC] = ADI_ADRV9001_TRACKING_CAL_TX_DPD_CLGC }; static int adrv9002_set_atten_control_mode(struct iio_dev *indio_dev, @@ -3288,36 +3280,29 @@ static int adrv9002_fh_parse_table_control(struct adrv9002_rf_phy *phy, } \ } -static int adrv9002_fh_parse_gpio_gain_control(struct adrv9002_rf_phy *phy, - const struct device_node *node) +static int adrv9002_fh_parse_chan_gpio_gain_control_chan(struct adrv9002_rf_phy *phy, + const struct device_node *fh, int chan) { int ret; - struct device_node *fh; - adi_adrv9001_FhGainSetupByPinCfg_t *gpio_gain = &phy->fh.gainSetupByPinConfig; + adi_adrv9001_FhGainSetupByPinCfg_t *gpio_gain = &phy->fh.gainSetupByPinConfig[chan]; u32 pin, p; int size; - fh = of_get_child_by_name(node, "adi,fh-gain-setup-by-pin"); - if (!fh) - return 0; - - phy->fh.gainSetupByPin = true; ret = OF_ADRV9002_DGPIO(fh, "adi,fh-gain-select-pin", pin, true); if (ret) - goto of_put; + return ret; ret = OF_ADRV9002_FH("adi,fh-gain-select-npins", 0, 1, ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_PINS, gpio_gain->numGainCtrlPins, true); if (ret) - goto of_put; + return ret; /* assign gpios now */ for (p = 0; p < gpio_gain->numGainCtrlPins; p++) { if ((pin + p) > ADI_ADRV9001_GPIO_DIGITAL_15) { dev_err(&phy->spi->dev, "Invalid DGPIO given for gain ctl: %d\n", pin + p); - ret = -EINVAL; - goto of_put; + return -EINVAL; } gpio_gain->gainSelectGpioConfig[p].pin = pin + p; } @@ -3329,8 +3314,7 @@ static int adrv9002_fh_parse_gpio_gain_control(struct adrv9002_rf_phy *phy, size = of_property_count_elems_of_size(fh, "adi,fh-rx-gain-table", sizeof(u32)); if (size <= 0 || size > (1 << gpio_gain->numGainCtrlPins)) { dev_err(&phy->spi->dev, "Invalid size:%d for fh rx gain table\n", size); - ret = -EINVAL; - goto of_put; + return -EINVAL; } assign_fh_gpio_ctl_table(fh, "adi,fh-rx-gain-table", size, &gpio_gain->rxGainTable[0]); @@ -3339,14 +3323,60 @@ static int adrv9002_fh_parse_gpio_gain_control(struct adrv9002_rf_phy *phy, size = of_property_count_elems_of_size(fh, "adi,fh-tx-atten-table", sizeof(u32)); if (size <= 0 || size > (1 << gpio_gain->numGainCtrlPins)) { dev_err(&phy->spi->dev, "Invalid size:%d for fh tx gain table\n", size); - ret = -EINVAL; - goto of_put; + return -EINVAL; } assign_fh_gpio_ctl_table(fh, "adi,fh-tx-atten-table", size, &gpio_gain->txAttenTable[0]); gpio_gain->numTxAttenTableEntries = size; -of_put: - of_node_put(fh); + + return 0; +} + +static int adrv9002_fh_parse_gpio_gain_control(struct adrv9002_rf_phy *phy, + const struct device_node *node) +{ + struct device_node *gain, *child; + int ret = 0, n_chann; + + gain = of_get_child_by_name(node, "adi,fh-gain-setup-by-pin"); + if (!gain) + return 0; + + n_chann = of_get_available_child_count(gain); + if (n_chann != ADRV9002_CHANN_MAX) { + dev_err(&phy->spi->dev, "If set, Gain setup by pin must be set for both channels!\n"); + of_node_put(gain); + return -EINVAL; + } + + for_each_available_child_of_node(gain, child) { + u32 chann; + + ret = of_property_read_u32(child, "reg", &chann); + if (ret) { + dev_err(&phy->spi->dev, + "No reg property defined for gain pin setup channel\n"); + goto of_child_put; + } else if (chann > ADRV9002_CHANN_2) { + dev_err(&phy->spi->dev, + "Invalid value for gain pin setup channel: %d\n", chann); + ret = -EINVAL; + goto of_child_put; + } + + ret = adrv9002_fh_parse_chan_gpio_gain_control_chan(phy, child, chann); + if (ret) + goto of_child_put; + } + + phy->fh.gainSetupByPin = true; + + of_node_put(gain); + return 0; + +of_child_put: + of_node_put(child); + of_node_put(gain); return ret; } @@ -3354,8 +3384,8 @@ static int adrv9002_parse_fh_dt(struct adrv9002_rf_phy *phy, const struct device { adi_adrv9001_FhhopTableSelectCfg_t *hop_tbl = &phy->fh.hopTableSelectConfig; struct device_node *fh; - u64 lo; int ret; + u64 lo; int hop; fh = of_get_child_by_name(node, "adi,frequency-hopping"); @@ -4013,7 +4043,7 @@ static int adrv9002_parse_dt(struct adrv9002_rf_phy *phy) "No adi,signal property defined for gpio%d\n", gpio); goto of_child_put; - } else if (signal > ADI_ADRV9001_GPIO_SIGNAL_JTAG_CTRL) { + } else if (signal >= ADI_ADRV9001_GPIO_NUM_SIGNALS) { dev_err(&phy->spi->dev, "Invalid gpio signal: %d\n", signal); ret = -EINVAL; @@ -4281,7 +4311,7 @@ static ssize_t adrv9002_fh_bin_table_write(struct adrv9002_rf_phy *phy, char *bu p = tbl->bin_table; while ((line = strsep(&p, "\n")) && p) { u64 lo; - u32 rx10_if, rx20_if, rx_gain, tx_atten; + u32 rx10_if, rx20_if, rx1_gain, tx1_atten, rx2_gain, tx2_atten; /* skip comment lines or blank lines */ if (line[0] == '#' || !line[0]) @@ -4289,8 +4319,8 @@ static ssize_t adrv9002_fh_bin_table_write(struct adrv9002_rf_phy *phy, char *bu else if (strstr(line, "table>")) continue; - ret = sscanf(line, "%llu,%u,%u,%u,%u", &lo, &rx10_if, &rx20_if, &rx_gain, - &tx_atten); + ret = sscanf(line, "%llu,%u,%u,%u,%u,%u,%u", &lo, &rx10_if, &rx20_if, &rx1_gain, + &tx1_atten, &rx2_gain, &tx2_atten); if (ret != ADRV9002_FH_TABLE_COL_SZ) { dev_err(&phy->spi->dev, "Failed to parse hop:%d table:%d line:%s\n", hop, table, line); @@ -4311,8 +4341,10 @@ static ssize_t adrv9002_fh_bin_table_write(struct adrv9002_rf_phy *phy, char *bu hop_tbl[entry].hopFrequencyHz = lo; hop_tbl[entry].rx1OffsetFrequencyHz = rx10_if; hop_tbl[entry].rx2OffsetFrequencyHz = rx10_if; - hop_tbl[entry].rxGainIndex = rx_gain; - hop_tbl[entry].txAttenuation_mdB = tx_atten; + hop_tbl[entry].rx1GainIndex = rx1_gain; + hop_tbl[entry].tx1Attenuation_fifthdB = tx1_atten; + hop_tbl[entry].rx2GainIndex = rx1_gain; + hop_tbl[entry].tx2Attenuation_fifthdB = tx2_atten; entry++; } diff --git a/drivers/iio/adc/navassa/adrv9002_debugfs.c b/drivers/iio/adc/navassa/adrv9002_debugfs.c index 0c76b9ba5dd106..cb8f09dccf3b13 100644 --- a/drivers/iio/adc/navassa/adrv9002_debugfs.c +++ b/drivers/iio/adc/navassa/adrv9002_debugfs.c @@ -895,24 +895,26 @@ static const char * const dgpio_str[] = { "dgpio14", "dgpio15" }; -static void adrv9002_fh_gain_config_dump_show(struct seq_file *s, const adi_adrv9001_FhCfg_t *cfg) +static void adrv9002_fh_gain_config_dump_show(struct seq_file *s, const adi_adrv9001_FhCfg_t *cfg, + int chan) { - const adi_adrv9001_FhGainSetupByPinCfg_t *gain = &cfg->gainSetupByPinConfig; + const adi_adrv9001_FhGainSetupByPinCfg_t *gain = &cfg->gainSetupByPinConfig[chan]; int e; - adrv9002_seq_printf(s, &cfg->gainSetupByPinConfig, numRxGainTableEntries); + seq_printf(s, "Gain Pin Config channel(%d):\n", chan); + adrv9002_seq_printf(s, &cfg->gainSetupByPinConfig[chan], numRxGainTableEntries); seq_puts(s, "RX Gain Table: "); for (e = 0; e < gain->numRxGainTableEntries; e++) seq_printf(s, "%u ", gain->rxGainTable[e]); seq_puts(s, "\n"); - adrv9002_seq_printf(s, &cfg->gainSetupByPinConfig, numTxAttenTableEntries); + adrv9002_seq_printf(s, &cfg->gainSetupByPinConfig[chan], numTxAttenTableEntries); seq_puts(s, "TX Atten Table: "); for (e = 0; e < gain->numTxAttenTableEntries; e++) seq_printf(s, "%u ", gain->txAttenTable[e]); seq_puts(s, "\n"); - adrv9002_seq_printf(s, &cfg->gainSetupByPinConfig, numGainCtrlPins); + adrv9002_seq_printf(s, &cfg->gainSetupByPinConfig[chan], numGainCtrlPins); seq_puts(s, "Gain Select Pins: "); for (e = 0; e < gain->numGainCtrlPins; e++) seq_printf(s, "%s ", dgpio_str[gain->gainSelectGpioConfig[e].pin]); @@ -961,8 +963,12 @@ static int adrv9002_fh_config_dump_show(struct seq_file *s, void *ignored) if (cfg.numTableIndexPins) seq_puts(s, "\n"); adrv9002_seq_printf(s, &cfg, gainSetupByPin); - if (cfg.gainSetupByPin) - adrv9002_fh_gain_config_dump_show(s, &cfg); + if (cfg.gainSetupByPin) { + int c; + + for (c = 0; c < ADRV9002_CHANN_MAX; c++) + adrv9002_fh_gain_config_dump_show(s, &cfg, c); + } return 0; } @@ -986,11 +992,12 @@ static int adrv9002_hop_table_dump_show(struct seq_file *s, int hop, int tbl_idx } if (read_back) - seq_puts(s, "hop_freq_hz rx1_off_freq_hz rx2_off_freq_hz rx_gain tx_atten\n"); + seq_puts(s, "hop_freq_hz rx1_off_freq_hz rx2_off_freq_hz rx1_gain tx1_atten rx2_gain tx2_atten\n"); for (e = 0; e < read_back; e++) { - seq_printf(s, "%-11llu %-15d %-15d %-7u %u\n", tbl[e].hopFrequencyHz, + seq_printf(s, "%-11llu %-15d %-15d %-8u %-9u %-8u %u\n", tbl[e].hopFrequencyHz, tbl[e].rx1OffsetFrequencyHz, tbl[e].rx2OffsetFrequencyHz, - tbl[e].rxGainIndex, tbl[e].txAttenuation_mdB); + tbl[e].rx1GainIndex, tbl[e].tx1Attenuation_fifthdB, + tbl[e].rx2GainIndex, tbl[e].tx2Attenuation_fifthdB); } mutex_unlock(&phy->lock); From 839d73ce88ed353ec5e23e824db3427f52a7be6f Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Thu, 23 Dec 2021 15:55:46 +0200 Subject: [PATCH 077/407] iio:beamformer:adar300x: Fix memory read A beam state has 4 horizontal elements and 4 vertical elements, 8 elements in total. Since the device has 4 beams * 8 elements => 32 channels. When a read is executed, 8 elements are read from memory, so a modulo operation it is necessary to correctly read values. Fixes: dc25781b59fe44f3ebe6a4f06465179d8dbffb81 ("iio:beamformer:adar300x: Add driver initial version") Signed-off-by: Cristian Pop --- drivers/iio/beamformer/adar300x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/beamformer/adar300x.c b/drivers/iio/beamformer/adar300x.c index 9d12f87d3920cc..a80f7c285c0710 100644 --- a/drivers/iio/beamformer/adar300x.c +++ b/drivers/iio/beamformer/adar300x.c @@ -690,7 +690,7 @@ static int adar300x_get_mem_value(struct iio_dev *indio_dev, adar300x_unpack_data(packed, unpacked, ADAR300x_UNPACKED_BEAMSTATE_LEN); - *val = unpacked[chan->address]; + *val = unpacked[chan->address % st->chip_info->unpacked_beamst_len]; err_unlock: mutex_unlock(&st->lock); From 8077957e8f81d539f05a7a065a6b17a2477c4a89 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 11 Jan 2022 11:00:12 +0100 Subject: [PATCH 078/407] iio: adc: ad9361_conv: Skip digital tune on AXI slave cores In MCS setups, the secondary AD936x won't reliably work unless the complete MCS sequence has been performed. So we skip tuning on the secondary device. It's up to the user responsibility to run the MCS sequence and rerun the digital tuning afterwards. The libad9361 has all the required logic and can handle this. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9361_conv.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ad9361_conv.c b/drivers/iio/adc/ad9361_conv.c index 270cbfd594f45a..1902e7d0750141 100644 --- a/drivers/iio/adc/ad9361_conv.c +++ b/drivers/iio/adc/ad9361_conv.c @@ -694,14 +694,16 @@ static int ad9361_post_setup(struct iio_dev *indio_dev) flags = 0; - ret = ad9361_dig_tune(phy, (axiadc_read(st, ADI_AXI_REG_ID)) ? - 0 : 61440000, flags); + ret = ad9361_dig_tune(phy, 61440000, axiadc_read(st, ADI_AXI_REG_ID) ? + flags | RESTORE_DEFAULT : flags); if (ret < 0) goto error; if (flags & (DO_IDELAY | DO_ODELAY)) { - ret = ad9361_dig_tune(phy, (axiadc_read(st, ADI_AXI_REG_ID)) ? - 0 : 61440000, flags & BE_VERBOSE); + ret = ad9361_dig_tune(phy, 61440000, + axiadc_read(st, ADI_AXI_REG_ID) ? + flags | RESTORE_DEFAULT | BE_VERBOSE : + flags | BE_VERBOSE); if (ret < 0) goto error; } From 229f586fdd39cf85032c692d4ad86a37ee8d8391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 7 Jan 2022 15:39:58 +0100 Subject: [PATCH 079/407] docs: update the toplevel readme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This brings the toplevel README.md up to date with the current supported Xilinx tag and linux version. It also refactors some other things with the goal of smoothing the maintenance burden on this file. Signed-off-by: Nuno Sá --- README.md | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index bb7df799b1c0a5..ae3af9ab4440ff 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,10 @@ The Linux kernel in this repository is the [Linux kernel from Xilinx](https://gi Details about the drivers that are of interest [and supported] by this repository can be found on the [Analog Devices wiki](https://wiki.analog.com/resources/tools-software/linux-drivers-all). This readme focuses on details specific to how this code is structured/organized, how it was derived, etc. -For the current master, the last point in git history where things were merged from Xilinx is commit [dd100de5395b65494a285a37a74ccceab4f39520](https://github.com/analogdevicesinc/linux/commit/dd100de5395b65494a285a37a74ccceab4f39520). That commit (being a working branched) was merged into master via commit [d1873cb62263704a93d904420daf5941f38599b4](https://github.com/analogdevicesinc/linux/commit/d1873cb62263704a93d904420daf5941f38599b4). +The current master is based on [xilinx v2021.1](https://github.com/Xilinx/linux-xlnx/tree/xilinx-v2021.1). For details about the merge see commit [67d89797e6b7](https://github.com/analogdevicesinc/linux/commit/67d89797e6b7e313f93f3683f7dd0479895ee9b0) ("Merge tag 'xilinx-v2021.1' of https://github.com/Xilinx/linux-xlnx.git"). In this Xilinx release, the current version of upstream Linux is [Linux 5.10](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tag/?h=v5.10). For legacy reasons, the [xcomm_zynq](https://github.com/analogdevicesinc/linux/tree/xcomm_zynq) branch is still available and should be in-sync with current master. That branch used to be the old master branch. -The current version of upstream Linux that Xilinx merged into their tree is from [Linux 4.14](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tag/?h=v4.14). No other patches seem to have been added after this (by Xilinx). - ## How to build For build instructions [check the wiki](https://wiki.analog.com/resources/tools-software/linux-drivers-all#building_the_adi_linux_kernel). @@ -37,22 +35,18 @@ Release branches can be built using other GCC toolchains, but in the official SD ## Rebased branches Starting with branch [adi-4.9.0](https://github.com/analogdevicesinc/linux/tree/adi-4.9.0) there are rebased branches. -They're typically rebased branches from Xilinx with the ADI patches on top. +They're typically rebased branches from Xilinx with the ADI patches on top so that it's easier to identify patches that are not yet upstreamed. For [adi-4.9.0](https://github.com/analogdevicesinc/linux/tree/adi-4.9.0) the base was branch [xlnx_rebase_v4.9](https://github.com/Xilinx/linux-xlnx/tree/xlnx_rebase_v4.9) at commit [d45e196f59364e9f5eafe46027a7d2af349083974](https://github.com/analogdevicesinc/linux/commit/d45e196f59364e9f5eafe46027a7d2af349083974) in the ADI repo and commit [45e196f59364e9f5eafe46027a7d2af349083974](https://github.com/Xilinx/linux-xlnx/commit/45e196f59364e9f5eafe46027a7d2af349083974) in the Xilinx repo. All ADI patches & drivers up to a specific point in time were cherry-picked to that branch from master. Note that since the `adi-4.9.0` branch is the first rebased branch, it's not particularly the best rebase that could have been done, but it should provide some patches that are somewhat reasonable to take and apply on top of an upstream 4.9 kernel [after some polishing]. -The current master branch has an equivalent [adi-4.14.0](https://github.com/analogdevicesinc/linux/tree/adi-4.14.0). -The common base/commit for this branch is commit https://github.com/analogdevicesinc/linux/commit/ad4cd988ba86ab0fb306d57f244b7eaa6cce79a4 from the [xlnx_rebase_v4.14](https://github.com/Xilinx/linux-xlnx/tree/xlnx_rebase_v4.14). Note that the [same hash is present](https://github.com/xilinx/linux-xlnx/commit/ad4cd988ba86ab0fb306d57f244b7eaa6cce79a4) in the Xilinx. As such, the `adi-4.14.0` is an incremental improvement for rebased branches in this repo. +The latest rebased branch depends on the current linux version supported in master. At the time of writing it is 5.10 so that [adi-5.10.0](https://github.com/analogdevicesinc/linux/tree/adi-5.10.0) is the latest. Also note that a diff between the latest rebased branch and master (`git diff master adi-5.10.0`) must be NULL. ## Raspberry Pi branches -These provide a kernel that is good to run on a Raspberry Pi board. Some of the drivers that are developed internally are prototyped on top of this board. - -The typical ones are [rpi-4.0.y](https://github.com/analogdevicesinc/linux/tree/rpi-4.0.y), [rpi-4.9.y](https://github.com/analogdevicesinc/linux/tree/rpi-4.9.y) and [rpi-4.14.y](https://github.com/analogdevicesinc/linux/tree/rpi-4.14.y). The first 2 are upstream RPi branches merged with the ADI master branch from this repo. The 3rd is a rebased version of upstream rpi-4.14.y at some point in time. +These provide a kernel that is good to run on a Raspberry Pi board. All the drivers present in the master branch should be automatically cherry-picked into the latest rpi branch. -These branches are a bit hard to maintain. They require constant conflict resolution whenever rebasing, so they rarely get updated. -As such, [rpi-4.14.y](https://github.com/analogdevicesinc/linux/tree/rpi-4.14.y) will probably be the last RPi branch. The idea is that with the next stable Linux kernel (4.19) support for RPi boards should be good enough in the upstream kernel, so that there won't be a need to keep these special branches. +As in the rebased branches, the latest rpi branch should be in accordance with the current kernel version supported in master. At the time of writing, the kernel version in master is 5.10 so that the correspondent latest rpi branch is [rpi-5.10.y](https://github.com/analogdevicesinc/linux/tree/rpi-5.10.y). ## Intel/Altera branches From f9989f2e530c42abbf1d59f4bb0c284fdf38a33c Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 11 Jan 2022 12:23:42 +0100 Subject: [PATCH 080/407] iio: frequency: ad9172: Support for dual-link mode This patch adds support for dual-link mode. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/ad9172.c | 36 +++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/iio/frequency/ad9172.c b/drivers/iio/frequency/ad9172.c index 488954bd21ce73..da57c25cf1e0d7 100644 --- a/drivers/iio/frequency/ad9172.c +++ b/drivers/iio/frequency/ad9172.c @@ -272,21 +272,26 @@ static int ad9172_setup(struct ad9172_state *st) msleep(100); - ret = ad917x_jesd_get_link_status(ad917x_h, JESD_LINK_0, &link_status); - if (ret != 0) { - dev_err(dev, - "DAC:MODE:JESD: ERROR : Get Link status failed \r\n"); - return -EIO; - } + for (i = JESD_LINK_0; i <= JESD_LINK_1; i++) { + ret = ad917x_jesd_get_link_status(ad917x_h, i, &link_status); + if (ret != 0) { + dev_err(dev, + "DAC:MODE:JESD: ERROR : Get Link%d status failed \r\n", i); + return -EIO; + } - dev_info(dev, "code_grp_sync: %x\n", link_status.code_grp_sync_stat); - dev_info(dev, "frame_sync_stat: %x\n", link_status.frame_sync_stat); - dev_info(dev, "good_checksum_stat: %x\n", - link_status.good_checksum_stat); - dev_info(dev, "init_lane_sync_stat: %x\n", - link_status.init_lane_sync_stat); - dev_info(dev, "%d lanes @ %lu kBps\n", - st->appJesdConfig.jesd_L, lane_rate_kHz); + dev_info(dev, "Link%d code_grp_sync: %x\n", i, link_status.code_grp_sync_stat); + dev_info(dev, "Link%d frame_sync_stat: %x\n", i, link_status.frame_sync_stat); + dev_info(dev, "Link%d good_checksum_stat: %x\n", + i, link_status.good_checksum_stat); + dev_info(dev, "Link%d init_lane_sync_stat: %x\n", + i, link_status.init_lane_sync_stat); + dev_info(dev, "Link%d %d lanes @ %lu kBps\n", + i, st->appJesdConfig.jesd_L, lane_rate_kHz); + + if (!st->jesd_dual_link_mode) + break; + } if (st->jesd_dual_link_mode || st->interpolation == 1) dac_mask = AD917X_DAC0 | AD917X_DAC1; @@ -819,6 +824,9 @@ static int ad9172_parse_dt(struct spi_device *spi, struct ad9172_state *st) st->jesd_link_mode = 10; of_property_read_u32(np, "adi,jesd-link-mode", &st->jesd_link_mode); + st->jesd_dual_link_mode = 0; + of_property_read_u32(np, "adi,dual-link", &st->jesd_dual_link_mode); + st->jesd_subclass = 0; of_property_read_u32(np, "adi,jesd-subclass", &st->jesd_subclass); From 0fb9f3f3c59fef3a42c64979b4828d34b8181e32 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 11 Jan 2022 13:38:23 +0100 Subject: [PATCH 081/407] iio: frequency: ad9172: Support for direct DAC clocking This patch adds support for direct clocking mode. The DAC rate can be presented in Hz by using the dac_clk-clock-scales dt attribute. Direct clocking is enabled by declaring the adi,direct-clocking-enable; boolean attribute. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/ad9172.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/iio/frequency/ad9172.c b/drivers/iio/frequency/ad9172.c index da57c25cf1e0d7..664745f6cc9b8d 100644 --- a/drivers/iio/frequency/ad9172.c +++ b/drivers/iio/frequency/ad9172.c @@ -58,6 +58,7 @@ struct ad9172_state { u32 jesd_dual_link_mode; u32 jesd_subclass; u32 clock_output_config; + bool pll_bypass; signal_type_t syncoutb_type; signal_coupling_t sysref_coupling; u8 nco_main_enable; @@ -107,8 +108,8 @@ static int ad9172_setup(struct ad9172_state *st) adi_chip_id_t dac_chip_id; uint8_t pll_lock_status = 0, dll_lock_stat = 0; int ret, i; - u64 dac_rate_Hz; - unsigned long dac_clkin_Hz, lane_rate_kHz; + u64 dac_rate_Hz, dac_clkin_Hz; + unsigned long lane_rate_kHz; ad917x_jesd_link_stat_t link_status; ad917x_handle_t *ad917x_h = &st->dac_h; unsigned long pll_mult; @@ -149,14 +150,25 @@ static int ad9172_setup(struct ad9172_state *st) dev_info(dev, "AD916x Revision: %d.%d.%d\n", revision[0], revision[1], revision[2]); - dac_clkin_Hz = clk_get_rate(st->conv.clk[CLK_DAC]); + dac_clkin_Hz = clk_get_rate_scaled(st->conv.clk[CLK_DAC], + &st->conv.clkscale[CLK_DAC]); + + dev_info(dev, "CLK Input rate %llu\n", dac_clkin_Hz); - dev_info(dev, "PLL Input rate %lu\n", dac_clkin_Hz); + if (!st->pll_bypass) { + u64 tmp = dac_clkin_Hz; - pll_mult = DIV_ROUND_CLOSEST(st->dac_rate_khz, dac_clkin_Hz / 1000); + do_div(tmp, 1000); + + pll_mult = DIV_ROUND_CLOSEST_ULL(st->dac_rate_khz, tmp); + + ret = ad917x_set_dac_clk(ad917x_h, dac_clkin_Hz * pll_mult, + 1, dac_clkin_Hz); + } else { + ret = ad917x_set_dac_clk(ad917x_h, dac_clkin_Hz, 0, + dac_clkin_Hz); + } - ret = ad917x_set_dac_clk(ad917x_h, (u64)dac_clkin_Hz * pll_mult, - 1, dac_clkin_Hz); if (ret != 0) { dev_err(dev, "ad917x_set_dac_clk failed (%d)\n", ret); return ret; @@ -165,7 +177,7 @@ static int ad9172_setup(struct ad9172_state *st) msleep(100); /* Wait 100 ms for PLL to lock */ ret = ad917x_get_dac_clk_status(ad917x_h, - &pll_lock_status, &dll_lock_stat); + &pll_lock_status, &dll_lock_stat); if (ret != 0) { dev_err(dev, "ad917x_get_dac_clk_status failed (%d)\n", ret); return ret; @@ -830,6 +842,8 @@ static int ad9172_parse_dt(struct spi_device *spi, struct ad9172_state *st) st->jesd_subclass = 0; of_property_read_u32(np, "adi,jesd-subclass", &st->jesd_subclass); + st->pll_bypass = of_property_read_bool(np, "adi,direct-clocking-enable"); + st->dac_interpolation = 1; of_property_read_u32(np, "adi,dac-interpolation", &st->dac_interpolation); From 39624cb95ef534b5707f865275f8f843cb5caa30 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 11 Jan 2022 15:17:21 +0100 Subject: [PATCH 082/407] iio: frequency: ad9172: Create channel list from synthesis parameters This patch enables support to automatically populate the channel list from the HDL core synthesis parameters. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/ad9172.c | 9 +-- drivers/iio/frequency/cf_axi_dds.c | 126 ++++++++++------------------- drivers/iio/frequency/cf_axi_dds.h | 4 +- 3 files changed, 44 insertions(+), 95 deletions(-) diff --git a/drivers/iio/frequency/ad9172.c b/drivers/iio/frequency/ad9172.c index 664745f6cc9b8d..643d5b5d63726a 100644 --- a/drivers/iio/frequency/ad9172.c +++ b/drivers/iio/frequency/ad9172.c @@ -920,7 +920,7 @@ static int ad9172_probe(struct spi_device *spi) conv->write_raw = ad9172_write_raw; conv->read_raw = ad9172_read_raw; conv->spi = spi; - conv->id = ID_AD9172_M2; + conv->id = ID_AUTO_SYNTH_PARAM; ret = ad9172_get_clks(conv); if (ret < 0) { @@ -946,28 +946,21 @@ static int ad9172_probe(struct spi_device *spi) if (st->interpolation == 1) { conv->attrs = NULL; - conv->id = ID_AD9172_M2; } else { switch (st->appJesdConfig.jesd_M) { case 2: - conv->id = ID_AD9172_M2; - if (st->jesd_dual_link_mode) conv->attrs = &ad9172_attribute_group_dual_m2; else conv->attrs = &ad9172_attribute_group_m2; break; case 4: - conv->id = ID_AD9172_M4; - if (st->jesd_dual_link_mode) conv->attrs = &ad9172_attribute_group_dual_m4; else conv->attrs = &ad9172_attribute_group_m4; break; case 6: - conv->id = ID_AD9172_M6; - if (st->jesd_dual_link_mode) conv->attrs = &ad9172_attribute_group_dual_m6; else diff --git a/drivers/iio/frequency/cf_axi_dds.c b/drivers/iio/frequency/cf_axi_dds.c index 45a7f7f9b1d961..79a18fae70e8b6 100644 --- a/drivers/iio/frequency/cf_axi_dds.c +++ b/drivers/iio/frequency/cf_axi_dds.c @@ -1250,70 +1250,6 @@ static struct cf_axi_dds_chip_info cf_axi_dds_chip_info_tbl[] = { .num_dds_channels = 4, .num_buf_channels = 2, }, - [ID_AD9172_M2] = { - .name = "AD9172", - .channel = { - CF_AXI_DDS_CHAN_BUF_MOD(0, IIO_MOD_I, 0), - CF_AXI_DDS_CHAN_BUF_MOD(0, IIO_MOD_Q, 1), - CF_AXI_DDS_CHAN(0, 0, "TX1_I_F1"), - CF_AXI_DDS_CHAN(1, 0, "TX1_I_F2"), - CF_AXI_DDS_CHAN(2, 0, "TX1_Q_F1"), - CF_AXI_DDS_CHAN(3, 0, "TX1_Q_F2"), - }, - .num_channels = 6, - .num_dp_disable_channels = 2, - .num_dds_channels = 4, - .num_buf_channels = 2, - }, - [ID_AD9172_M4] = { - .name = "AD9172", - .channel = { - CF_AXI_DDS_CHAN_BUF_MOD(0, IIO_MOD_I, 0), - CF_AXI_DDS_CHAN_BUF_MOD(0, IIO_MOD_Q, 1), - CF_AXI_DDS_CHAN_BUF_MOD(1, IIO_MOD_I, 2), - CF_AXI_DDS_CHAN_BUF_MOD(1, IIO_MOD_Q, 3), - CF_AXI_DDS_CHAN(0, 0, "TX1_I_F1"), - CF_AXI_DDS_CHAN(1, 0, "TX1_I_F2"), - CF_AXI_DDS_CHAN(2, 0, "TX1_Q_F1"), - CF_AXI_DDS_CHAN(3, 0, "TX1_Q_F2"), - CF_AXI_DDS_CHAN(4, 0, "TX2_I_F1"), - CF_AXI_DDS_CHAN(5, 0, "TX2_I_F2"), - CF_AXI_DDS_CHAN(6, 0, "TX2_Q_F1"), - CF_AXI_DDS_CHAN(7, 0, "TX2_Q_F2"), - - }, - .num_channels = 12, - .num_dp_disable_channels = 4, - .num_dds_channels = 8, - .num_buf_channels = 4, - }, - [ID_AD9172_M6] = { - .name = "AD9172", - .channel = { - CF_AXI_DDS_CHAN_BUF_MOD(0, IIO_MOD_I, 0), - CF_AXI_DDS_CHAN_BUF_MOD(0, IIO_MOD_Q, 1), - CF_AXI_DDS_CHAN_BUF_MOD(1, IIO_MOD_I, 2), - CF_AXI_DDS_CHAN_BUF_MOD(1, IIO_MOD_Q, 3), - CF_AXI_DDS_CHAN_BUF_MOD(2, IIO_MOD_I, 4), - CF_AXI_DDS_CHAN_BUF_MOD(2, IIO_MOD_Q, 5), - CF_AXI_DDS_CHAN(0, 0, "1A"), - CF_AXI_DDS_CHAN(1, 0, "1B"), - CF_AXI_DDS_CHAN(2, 0, "2A"), - CF_AXI_DDS_CHAN(3, 0, "2B"), - CF_AXI_DDS_CHAN(4, 0, "3A"), - CF_AXI_DDS_CHAN(5, 0, "3B"), - CF_AXI_DDS_CHAN(6, 0, "4A"), - CF_AXI_DDS_CHAN(7, 0, "4B"), - CF_AXI_DDS_CHAN(8, 0, "5A"), - CF_AXI_DDS_CHAN(9, 0, "5B"), - CF_AXI_DDS_CHAN(10, 0, "6A"), - CF_AXI_DDS_CHAN(11, 0, "6B"), - }, - .num_channels = 18, - .num_dp_disable_channels = 6, - .num_dds_channels = 12, - .num_buf_channels = 6, - }, }; static struct cf_axi_dds_chip_info cf_axi_dds_chip_info_ad9361 = { @@ -1780,8 +1716,21 @@ static const struct jesd204_dev_data jesd204_cf_axi_dds_init = { }, }; +struct axidds_core_info { + unsigned int version; + bool standalone; + bool rate_format_skip_en; + bool complex_modified; + bool issue_sync_en; + struct cf_axi_dds_chip_info *chip_info; + unsigned int data_format; + unsigned int rate; + long info_mask_separate; + const char *name; +}; + static int cf_axi_dds_setup_chip_info_tbl(struct cf_axi_dds_state *st, - const char *name, bool complex) + const struct axidds_core_info *info) { u32 i, c, reg, m, n, np; @@ -1801,9 +1750,10 @@ static int cf_axi_dds_setup_chip_info_tbl(struct cf_axi_dds_state *st, st->chip_info_generated.channel[c].type = IIO_VOLTAGE; st->chip_info_generated.channel[c].output = 1; st->chip_info_generated.channel[c].indexed = 1; - st->chip_info_generated.channel[c].modified = complex ? 1 : 0; + st->chip_info_generated.channel[c].modified = + info->complex_modified ? 1 : 0; st->chip_info_generated.channel[c].channel = - complex ? i / 2 : i; + info->complex_modified ? i / 2 : i; st->chip_info_generated.channel[c].channel2 = (i & 1) ? IIO_MOD_Q : IIO_MOD_I; st->chip_info_generated.channel[c].scan_index = i; @@ -1819,6 +1769,9 @@ static int cf_axi_dds_setup_chip_info_tbl(struct cf_axi_dds_state *st, st->chip_info_generated.channel[c].ext_info = axidds_ext_info; + st->chip_info_generated.channel[c].info_mask_separate |= + info->info_mask_separate; + st->chip_info_generated.channel[c].scan_type.realbits = n; st->chip_info_generated.channel[c].scan_type.storagebits = np; st->chip_info_generated.channel[c].scan_type.shift = np - n; @@ -1856,23 +1809,11 @@ static int cf_axi_dds_setup_chip_info_tbl(struct cf_axi_dds_state *st, st->chip_info_generated.num_dp_disable_channels = m; st->chip_info_generated.num_dds_channels = i; st->chip_info_generated.num_buf_channels = m; - st->chip_info_generated.name = name; + st->chip_info_generated.name = info->name; return 0; } -struct axidds_core_info { - unsigned int version; - bool standalone; - bool rate_format_skip_en; - bool complex_modified; - bool issue_sync_en; - struct cf_axi_dds_chip_info *chip_info; - unsigned int data_format; - unsigned int rate; - const char *name; -}; - static const struct axidds_core_info ad9122_6_00_a_info = { .version = ADI_AXI_PCORE_VER(9, 0, 'a'), .rate = 1, @@ -1958,6 +1899,13 @@ static const struct axidds_core_info ad9081_1_00_a_info = { .complex_modified = true, }; +static const struct axidds_core_info ad9172_1_00_a_info = { + .version = ADI_AXI_PCORE_VER(9, 1, 'b'), + .name = "AD917x", + .complex_modified = true, + .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE), +}; + static const struct axidds_core_info adrv9002_9_01_b_info = { .version = ADI_AXI_PCORE_VER(9, 1, 'b'), .standalone = true, @@ -2008,7 +1956,7 @@ static const struct of_device_id cf_axi_dds_of_match[] = { .data = &ad9963_1_00_a_info, }, { .compatible = "adi,axi-ad9172-1.0", - .data = &ad9162_1_00_a_info, + .data = &ad9172_1_00_a_info, }, { .compatible = "adi,axi-ad9081-tx-1.0", .data = &ad9081_1_00_a_info, @@ -2140,8 +2088,7 @@ static int cf_axi_dds_probe(struct platform_device *pdev) if (info->chip_info) { st->chip_info = info->chip_info; } else { - ret = cf_axi_dds_setup_chip_info_tbl(st, info->name, - info->complex_modified); + ret = cf_axi_dds_setup_chip_info_tbl(st, info); if (ret) { dev_err(&pdev->dev, "Invalid number of converters identified"); @@ -2168,7 +2115,18 @@ static int cf_axi_dds_probe(struct platform_device *pdev) st->dac_clk = conv->get_data_clk(conv); - st->chip_info = &cf_axi_dds_chip_info_tbl[conv->id]; + if (conv->id == ID_AUTO_SYNTH_PARAM) { + ret = cf_axi_dds_setup_chip_info_tbl(st, info); + if (ret) { + dev_err(&pdev->dev, + "Invalid number of converters identified"); + return ret; + } + + st->chip_info = &st->chip_info_generated; + } else { + st->chip_info = &cf_axi_dds_chip_info_tbl[conv->id]; + } } /* diff --git a/drivers/iio/frequency/cf_axi_dds.h b/drivers/iio/frequency/cf_axi_dds.h index c0407bdf02f040..e144ec58545c9e 100644 --- a/drivers/iio/frequency/cf_axi_dds.h +++ b/drivers/iio/frequency/cf_axi_dds.h @@ -199,9 +199,7 @@ enum { ID_AD9154, ID_AD9162, ID_AD9162_COMPLEX, - ID_AD9172_M2, - ID_AD9172_M4, - ID_AD9172_M6, + ID_AUTO_SYNTH_PARAM = ~0, }; enum fifo_ctrl { From 76c02648d0360d4bfdab26943d87119f79c6d9c0 Mon Sep 17 00:00:00 2001 From: Laszlo Nagy Date: Wed, 5 Jan 2022 12:39:38 +0000 Subject: [PATCH 083/407] iio: jesd204: axi_adxcvr: BUFSTATUS support The RX/TXBUFSTATUS ports of the XCVRs provide status on the internal buffer or asynchronous gearbox from each channel indicating either underflow or overflow events. These unwanted events are the consequence of clocking miss-configuration or failure of the CDR circuitry in case of RX channels. This condition happens mostly on RX channels in case the transmit side of the link is not enabled in the moment when the XCVR is pulled out of reset and its CDR circuitry does not have a reliable source to lock on. These events are captured/latched by the UTIL_ADXCVR and are exposed to AXI_ADXCVR to STATUS register (0x14) fields [6:5] . In order to clear the latched status, bit 1 of RESETN register (0x1) must be set then cleared. In case after the initial reset sequence overflow/underflow is detected retry resetting the XCVR couple of times, if the errors are still detected report them and error out. Signed-off-by: Laszlo Nagy Signed-off-by: Michael Hennerich --- drivers/iio/jesd204/axi_adxcvr.c | 61 ++++++++++++++++++++++++++++---- drivers/iio/jesd204/axi_adxcvr.h | 1 + 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/drivers/iio/jesd204/axi_adxcvr.c b/drivers/iio/jesd204/axi_adxcvr.c index 085b08fc6feb66..dfb2e8fbc4edb9 100644 --- a/drivers/iio/jesd204/axi_adxcvr.c +++ b/drivers/iio/jesd204/axi_adxcvr.c @@ -403,7 +403,7 @@ static int adxcvr_status_error(struct device *dev) do { mdelay(1); status = adxcvr_read(st, ADXCVR_REG_STATUS); - } while ((timeout--) && (status == 0)); + } while ((timeout--) && !(status & BIT(0))); if (!(status & BIT(0))) { if (!st->qpll_enable && !st->cpll_enable) { @@ -454,24 +454,73 @@ static void adxcvr_work_func(struct work_struct *work) __func__, div40_rate, ret); } -static int adxcvr_clk_enable(struct clk_hw *hw) +static int adxcvr_reset(struct adxcvr_state *st) { - struct adxcvr_state *st = - container_of(hw, struct adxcvr_state, lane_clk_hw); int ret, retry = 1; - dev_dbg(st->dev, "%s: %s", __func__, st->tx_enable ? "TX" : "RX"); - do { adxcvr_write(st, ADXCVR_REG_RESETN, 0); udelay(2); adxcvr_write(st, ADXCVR_REG_RESETN, ADXCVR_RESETN); + dev_dbg(st->dev, "%s: %s %s Reset\n", + __func__, + adxcvr_sys_clock_sel_names[st->sys_clk_sel], + st->tx_enable ? "TX" : "RX"); ret = adxcvr_status_error(st->dev); } while (ret < 0 && retry--); return ret; } +static int adxcvr_clk_enable(struct clk_hw *hw) +{ + struct adxcvr_state *st = + container_of(hw, struct adxcvr_state, lane_clk_hw); + int ret, retry = 10; + unsigned int status; + int bufstatus_err; + + dev_dbg(st->dev, "%s: %s\n", __func__, st->tx_enable ? "TX" : "RX"); + + ret = adxcvr_reset(st); + if (ret < 0) + return ret; + + if (st->xcvr.version >= ADI_AXI_PCORE_VER(17, 5, 'a')) { + do { + adxcvr_write(st, ADXCVR_REG_RESETN, ADXCVR_BUFSTATUS_RST | ADXCVR_RESETN); + adxcvr_write(st, ADXCVR_REG_RESETN, ADXCVR_RESETN); + mdelay(1); + status = adxcvr_read(st, ADXCVR_REG_STATUS); + bufstatus_err = ((status & BIT(5)) || (status & BIT(6))); + if (bufstatus_err) { + ret = adxcvr_reset(st); + if (ret < 0) + return ret; + } + } while (bufstatus_err && retry--); + + if (status & BIT(5)) + dev_err(st->dev, "%s: %s %s %s error, status: 0x%x\n", + __func__, + adxcvr_sys_clock_sel_names[st->sys_clk_sel], + st->tx_enable ? "TX" : "RX", + "buffer underflow", status); + + if (status & BIT(6)) + dev_err(st->dev, "%s: %s %s %s error, status: 0x%x\n", + __func__, + adxcvr_sys_clock_sel_names[st->sys_clk_sel], + st->tx_enable ? "TX" : "RX", + "buffer overflow", status); + + if (bufstatus_err) + return -EIO; + } + + return ret; +} + static void adxcvr_clk_disable(struct clk_hw *hw) { struct adxcvr_state *st = diff --git a/drivers/iio/jesd204/axi_adxcvr.h b/drivers/iio/jesd204/axi_adxcvr.h index c260d3107d6164..9252b0d23a1e9c 100644 --- a/drivers/iio/jesd204/axi_adxcvr.h +++ b/drivers/iio/jesd204/axi_adxcvr.h @@ -21,6 +21,7 @@ #define ADXCVR_REG_RESETN 0x0010 #define ADXCVR_RESETN (1 << 0) +#define ADXCVR_BUFSTATUS_RST (1 << 1) #define ADXCVR_REG_STATUS 0x0014 #define ADXCVR_STATUS (1 << 0) From 9bad1d35b461b3ad7bfd813e76dbd6ef3f100d36 Mon Sep 17 00:00:00 2001 From: Laszlo Nagy Date: Tue, 11 Jan 2022 10:21:41 +0000 Subject: [PATCH 084/407] iio: jesd204: axi_jesd204_rx: Move lane clock enable Lane clock enable triggers the physical layer reset de-assertion. This must happen only when the transmit side of the link is out of reset and sends valid characters that the receive side CDR circuitry can lock on. Assumption is that this happens in the clock enable phase or earlier of the transmit side of the link. Signed-off-by: Laszlo Nagy Signed-off-by: Michael Hennerich --- drivers/iio/jesd204/axi_jesd204_rx.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/iio/jesd204/axi_jesd204_rx.c b/drivers/iio/jesd204/axi_jesd204_rx.c index 3ba2f1ddcc6856..3b16b4a81a5fa9 100644 --- a/drivers/iio/jesd204/axi_jesd204_rx.c +++ b/drivers/iio/jesd204/axi_jesd204_rx.c @@ -912,14 +912,13 @@ static int axi_jesd204_rx_jesd204_clks_enable(struct jesd204_dev *jdev, struct axi_jesd204_rx *jesd = dev_get_drvdata(dev); int ret; - dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, lnk->link_id, jesd204_state_op_reason_str(reason)); + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, + lnk->link_id, jesd204_state_op_reason_str(reason)); switch (reason) { case JESD204_STATE_OP_REASON_INIT: break; case JESD204_STATE_OP_REASON_UNINIT: - if (__clk_is_enabled(jesd->lane_clk)) /* REVIST */ - clk_disable_unprepare(jesd->lane_clk); if (__clk_is_enabled(jesd->device_clk)) clk_disable_unprepare(jesd->device_clk); if (!IS_ERR(jesd->link_clk)) { @@ -947,13 +946,6 @@ static int axi_jesd204_rx_jesd204_clks_enable(struct jesd204_dev *jdev, } } - ret = clk_prepare_enable(jesd->lane_clk); - if (ret) { - dev_err(dev, "%s: Link%u enable lane clock failed (%d)\n", - __func__, lnk->link_id, ret); - return ret; - } - return JESD204_STATE_CHANGE_DONE; } @@ -963,8 +955,10 @@ static int axi_jesd204_rx_jesd204_link_enable(struct jesd204_dev *jdev, { struct device *dev = jesd204_dev_to_device(jdev); struct axi_jesd204_rx *jesd = dev_get_drvdata(dev); + int ret; - dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, lnk->link_id, jesd204_state_op_reason_str(reason)); + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, + lnk->link_id, jesd204_state_op_reason_str(reason)); switch (reason) { case JESD204_STATE_OP_REASON_INIT: @@ -974,12 +968,24 @@ static int axi_jesd204_rx_jesd204_link_enable(struct jesd204_dev *jdev, cancel_delayed_work_sync(&jesd->watchdog_work); else disable_irq(jesd->irq); + writel_relaxed(0x1, jesd->base + JESD204_RX_REG_LINK_DISABLE); + + if (__clk_is_enabled(jesd->lane_clk)) + clk_disable_unprepare(jesd->lane_clk); + return JESD204_STATE_CHANGE_DONE; default: return JESD204_STATE_CHANGE_DONE; } + ret = clk_prepare_enable(jesd->lane_clk); + if (ret) { + dev_err(dev, "%s: Link%u enable lane clock failed (%d)\n", + __func__, lnk->link_id, ret); + return ret; + } + writel_relaxed(0x3, jesd->base + JESD204_RX_REG_SYSREF_STATUS); writel_relaxed(0x0, jesd->base + JESD204_RX_REG_LINK_DISABLE); From 9a902a41643845442eeadb6eb71920501d706f50 Mon Sep 17 00:00:00 2001 From: Laszlo Nagy Date: Tue, 11 Jan 2022 10:27:53 +0000 Subject: [PATCH 085/407] iio: adc: adrv9009: Move framer enable Enable framers in the clock enable phase. This will ensure the CDR circuity of the receive side of the link can lock to it correctly in the later stage of the JESD FSM. Signed-off-by: Laszlo Nagy Signed-off-by: Michael Hennerich --- drivers/iio/adc/adrv9009.c | 45 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/iio/adc/adrv9009.c b/drivers/iio/adc/adrv9009.c index 366aa31cd05cb5..ae1c28717097c8 100644 --- a/drivers/iio/adc/adrv9009.c +++ b/drivers/iio/adc/adrv9009.c @@ -5625,6 +5625,30 @@ static int adrv9009_jesd204_clks_enable(struct jesd204_dev *jdev, "%s:%d (ret %d)", __func__, __LINE__, ret); ret = -EFAULT; } + + ret = TALISE_enableFramerLink(phy->talDevice, + priv->link[lnk->link_id].source_id, 1); + if (ret != TALACT_NO_ACTION) { + dev_err(&phy->spi->dev, + "%s:%d (ret %d)", __func__, __LINE__, ret); + return -EFAULT; + } + + dev_dbg(&phy->spi->dev, + "%s:%d Link %d Framer enabled", __func__, __LINE__, + priv->link[lnk->link_id].source_id); + + /*************************************************/ + /**** Enable SYSREF to Talise JESD204B Framer ***/ + /*************************************************/ + /*** < User: Make sure SYSREF is stopped/disabled > ***/ + ret = TALISE_enableSysrefToFramer(phy->talDevice, + priv->link[lnk->link_id].source_id, 1); + if (ret != TALACT_NO_ACTION) { + dev_err(&phy->spi->dev, + "%s:%d (ret %d)", __func__, __LINE__, ret); + return -EFAULT; + } } else { ret = TALISE_enableSysrefToDeframer(phy->talDevice, priv->link[lnk->link_id].source_id, 0); @@ -5664,26 +5688,7 @@ static int adrv9009_jesd204_link_enable(struct jesd204_dev *jdev, if (!lnk->num_converters) return JESD204_STATE_CHANGE_DONE; - if (priv->link[lnk->link_id].is_framer) { - ret = TALISE_enableFramerLink(phy->talDevice, - priv->link[lnk->link_id].source_id, 1); - if (ret != TALACT_NO_ACTION) { - dev_err(&phy->spi->dev, - "%s:%d (ret %d)", __func__, __LINE__, ret); - return -EFAULT; - } - /*************************************************/ - /**** Enable SYSREF to Talise JESD204B Framer ***/ - /*************************************************/ - /*** < User: Make sure SYSREF is stopped/disabled > ***/ - ret = TALISE_enableSysrefToFramer(phy->talDevice, - priv->link[lnk->link_id].source_id, 1); - if (ret != TALACT_NO_ACTION) { - dev_err(&phy->spi->dev, - "%s:%d (ret %d)", __func__, __LINE__, ret); - return -EFAULT; - } - } else { + if (!priv->link[lnk->link_id].is_framer) { ret = TALISE_enableDeframerLink(phy->talDevice, priv->link[lnk->link_id].source_id, 1); if (ret != TALACT_NO_ACTION) { From 806bfce26f2cbd575d081428ffd47761b401b645 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Sun, 5 Dec 2021 13:40:44 +0200 Subject: [PATCH 086/407] dt-bindings: iio: add AD74413R The AD74412R and AD74413R are quad-channel, software configurable, input/output solutions for building and process control applications. They contain functionality for analog output, analog input, digital input, resistance temperature detector, and thermocouple measurements integrated into a single chip solution with an SPI interface. The devices feature a 16-bit ADC and four configurable 13-bit DACs to provide four configurable input/output channels and a suite of diagnostic functions. The AD74413R differentiates itself from the AD74412R by being HART-compatible. Signed-off-by: Cosmin Tanislav Reviewed-by: Rob Herring Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20211205114045.173612-3-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/addac/adi,ad74413r.yaml | 158 ++++++++++++++++++ include/dt-bindings/iio/addac/adi,ad74413r.h | 21 +++ 2 files changed, 179 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml create mode 100644 include/dt-bindings/iio/addac/adi,ad74413r.h diff --git a/Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml b/Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml new file mode 100644 index 00000000000000..baa65a521bad5b --- /dev/null +++ b/Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml @@ -0,0 +1,158 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/addac/adi,ad74413r.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD74412R/AD74413R device + +maintainers: + - Cosmin Tanislav + +description: | + The AD74412R and AD74413R are quad-channel software configurable input/output + solutions for building and process control applications. They contain + functionality for analog output, analog input, digital input, resistance + temperature detector, and thermocouple measurements integrated + into a single chip solution with an SPI interface. + The devices feature a 16-bit ADC and four configurable 13-bit DACs to provide + four configurable input/output channels and a suite of diagnostic functions. + The AD74413R differentiates itself from the AD74412R by being HART-compatible. + https://www.analog.com/en/products/ad74412r.html + https://www.analog.com/en/products/ad74413r.html + +properties: + compatible: + enum: + - adi,ad74412r + - adi,ad74413r + + reg: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + spi-max-frequency: + maximum: 1000000 + + spi-cpol: true + + interrupts: + maxItems: 1 + + refin-supply: true + + shunt-resistor-micro-ohms: + description: + Shunt (sense) resistor value in micro-Ohms. + default: 100000000 + +required: + - compatible + - reg + - spi-max-frequency + - spi-cpol + - refin-supply + +additionalProperties: false + +patternProperties: + "^channel@[0-3]$": + type: object + description: Represents the external channels which are connected to the device. + + properties: + reg: + description: | + The channel number. It can have up to 4 channels numbered from 0 to 3. + minimum: 0 + maximum: 3 + + adi,ch-func: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Channel function. + HART functions are not supported on AD74412R. + 0 - CH_FUNC_HIGH_IMPEDANCE + 1 - CH_FUNC_VOLTAGE_OUTPUT + 2 - CH_FUNC_CURRENT_OUTPUT + 3 - CH_FUNC_VOLTAGE_INPUT + 4 - CH_FUNC_CURRENT_INPUT_EXT_POWER + 5 - CH_FUNC_CURRENT_INPUT_LOOP_POWER + 6 - CH_FUNC_RESISTANCE_INPUT + 7 - CH_FUNC_DIGITAL_INPUT_LOGIC + 8 - CH_FUNC_DIGITAL_INPUT_LOOP_POWER + 9 - CH_FUNC_CURRENT_INPUT_EXT_POWER_HART + 10 - CH_FUNC_CURRENT_INPUT_LOOP_POWER_HART + minimum: 0 + maximum: 10 + default: 0 + + adi,gpo-comparator: + type: boolean + description: | + Whether to configure GPO as a comparator or not. + When not configured as a comparator, the GPO will be treated as an + output-only GPIO. + + required: + - reg + +examples: + - | + #include + #include + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + cs-gpios = <&gpio 17 GPIO_ACTIVE_LOW>; + status = "okay"; + + ad74413r@0 { + compatible = "adi,ad74413r"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cpol; + + #address-cells = <1>; + #size-cells = <0>; + + interrupt-parent = <&gpio>; + interrupts = <26 IRQ_TYPE_EDGE_FALLING>; + + refin-supply = <&ad74413r_refin>; + + channel@0 { + reg = <0>; + + adi,ch-func = ; + }; + + channel@1 { + reg = <1>; + + adi,ch-func = ; + }; + + channel@2 { + reg = <2>; + + adi,ch-func = ; + adi,gpo-comparator; + }; + + channel@3 { + reg = <3>; + + adi,ch-func = ; + }; + }; + }; +... diff --git a/include/dt-bindings/iio/addac/adi,ad74413r.h b/include/dt-bindings/iio/addac/adi,ad74413r.h new file mode 100644 index 00000000000000..204f92bbd79f26 --- /dev/null +++ b/include/dt-bindings/iio/addac/adi,ad74413r.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _DT_BINDINGS_ADI_AD74413R_H +#define _DT_BINDINGS_ADI_AD74413R_H + +#define CH_FUNC_HIGH_IMPEDANCE 0x0 +#define CH_FUNC_VOLTAGE_OUTPUT 0x1 +#define CH_FUNC_CURRENT_OUTPUT 0x2 +#define CH_FUNC_VOLTAGE_INPUT 0x3 +#define CH_FUNC_CURRENT_INPUT_EXT_POWER 0x4 +#define CH_FUNC_CURRENT_INPUT_LOOP_POWER 0x5 +#define CH_FUNC_RESISTANCE_INPUT 0x6 +#define CH_FUNC_DIGITAL_INPUT_LOGIC 0x7 +#define CH_FUNC_DIGITAL_INPUT_LOOP_POWER 0x8 +#define CH_FUNC_CURRENT_INPUT_EXT_POWER_HART 0x9 +#define CH_FUNC_CURRENT_INPUT_LOOP_POWER_HART 0xA + +#define CH_FUNC_MIN CH_FUNC_HIGH_IMPEDANCE +#define CH_FUNC_MAX CH_FUNC_CURRENT_INPUT_LOOP_POWER_HART + +#endif /* _DT_BINDINGS_ADI_AD74413R_H */ From e645671b9b0e7866f9fd21c320ba873334db7902 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Sun, 5 Dec 2021 13:40:45 +0200 Subject: [PATCH 087/407] iio: addac: add AD74413R driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AD74412R and AD74413R are quad-channel, software configurable, input/output solutions for building and process control applications. They contain functionality for analog output, analog input, digital input, resistance temperature detector, and thermocouple measurements integrated into a single chip solution with an SPI interface. The devices feature a 16-bit ADC and four configurable 13-bit DACs to provide four configurable input/output channels and a suite of diagnostic functions. The AD74413R differentiates itself from the AD74412R by being HART-compatible. When configured with channel 0 as voltage output, channel 1 as current output, channel 2 as voltage input and channel 3 as current input, the following structure is created under the corresponding IIO device. . ├── in_current0_offset ├── in_current0_raw ├── in_current0_sampling_frequency ├── in_current0_sampling_frequency_available ├── in_current0_scale ├── in_voltage1_offset ├── in_voltage1_raw ├── in_voltage1_sampling_frequency ├── in_voltage1_sampling_frequency_available ├── in_voltage1_scale ├── in_voltage2_offset ├── in_voltage2_raw ├── in_voltage2_sampling_frequency ├── in_voltage2_sampling_frequency_available ├── in_voltage2_scale ├── in_current3_offset ├── in_current3_raw ├── in_current3_sampling_frequency ├── in_current3_sampling_frequency_available ├── in_current3_scale ├── out_voltage0_raw ├── out_voltage0_scale ├── out_current1_raw ├── out_current1_scale ├── name ├── buffer │   ├── data_available │   ├── enable │   ├── length │   └── watermark └── scan_elements    ├── in_current0_en    ├── in_current0_index    ├── in_current0_type    ├── in_voltage1_en    ├── in_voltage1_index    ├── in_voltage1_type    ├── in_voltage2_en    ├── in_voltage2_index    ├── in_voltage2_type    ├── in_current3_en    ├── in_current3_index    └── in_current3_type Signed-off-by: Cosmin Tanislav Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20211205114045.173612-4-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 9 + drivers/iio/addac/Kconfig | 12 + drivers/iio/addac/Makefile | 1 + drivers/iio/addac/ad74413r.c | 1478 ++++++++++++++++++++++++++++++++++ 4 files changed, 1500 insertions(+) create mode 100644 drivers/iio/addac/ad74413r.c diff --git a/MAINTAINERS b/MAINTAINERS index ce2259b84b5334..39da035ef71614 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1066,6 +1066,15 @@ W: http://ez.analog.com/community/linux-device-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml F: drivers/iio/adc/ad7780.c +ANALOG DEVICES INC AD74413R DRIVER +M: Cosmin Tanislav +L: linux-iio@vger.kernel.org +S: Supported +W: http://ez.analog.com/community/linux-device-drivers +F: Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml +F: drivers/iio/addac/ad74413r.c +F: include/dt-bindings/iio/addac/adi,ad74413r.h + ANALOG DEVICES INC AD9389B DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org diff --git a/drivers/iio/addac/Kconfig b/drivers/iio/addac/Kconfig index 4e0875f0707469..c456a390d68a26 100644 --- a/drivers/iio/addac/Kconfig +++ b/drivers/iio/addac/Kconfig @@ -5,6 +5,18 @@ menu "Analog to digital and digital to analog converters" +config AD74413R + tristate "Analog Devices AD74412R/AD74413R driver" + depends on GPIOLIB && SPI + select REGMAP_SPI + select CRC8 + help + Say yes here to build support for Analog Devices AD74412R/AD74413R + quad-channel software configurable input/output solution. + + To compile this driver as a module, choose M here: the + module will be called ad74413r. + config ONE_BIT_ADC_DAC tristate "Analog Devices ONE_BIT_ADC_DAC driver" help diff --git a/drivers/iio/addac/Makefile b/drivers/iio/addac/Makefile index 81487e5f66a46d..0a33f0706b553b 100644 --- a/drivers/iio/addac/Makefile +++ b/drivers/iio/addac/Makefile @@ -4,4 +4,5 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AD74413R) += ad74413r.o obj-$(CONFIG_ONE_BIT_ADC_DAC) += one-bit-adc-dac.o diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c new file mode 100644 index 00000000000000..a2b1f6625fee59 --- /dev/null +++ b/drivers/iio/addac/ad74413r.c @@ -0,0 +1,1478 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Analog Devices, Inc. + * Author: Cosmin Tanislav + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define AD74413R_CRC_POLYNOMIAL 0x7 +DECLARE_CRC8_TABLE(ad74413r_crc8_table); + +#define AD74413R_CHANNEL_MAX 4 + +#define AD74413R_FRAME_SIZE 4 + +struct ad74413r_chip_info { + const char *name; + bool hart_support; +}; + +struct ad74413r_channel_config { + u32 func; + bool gpo_comparator; + bool initialized; +}; + +struct ad74413r_channels { + struct iio_chan_spec *channels; + unsigned int num_channels; +}; + +struct ad74413r_state { + struct ad74413r_channel_config channel_configs[AD74413R_CHANNEL_MAX]; + unsigned int gpo_gpio_offsets[AD74413R_CHANNEL_MAX]; + unsigned int comp_gpio_offsets[AD74413R_CHANNEL_MAX]; + struct gpio_chip gpo_gpiochip; + struct gpio_chip comp_gpiochip; + struct completion adc_data_completion; + unsigned int num_gpo_gpios; + unsigned int num_comparator_gpios; + u32 sense_resistor_ohms; + + /* + * Synchronize consecutive operations when doing a one-shot + * conversion and when updating the ADC samples SPI message. + */ + struct mutex lock; + + const struct ad74413r_chip_info *chip_info; + struct spi_device *spi; + struct regulator *refin_reg; + struct regmap *regmap; + struct device *dev; + struct iio_trigger *trig; + + size_t adc_active_channels; + struct spi_message adc_samples_msg; + struct spi_transfer adc_samples_xfer[AD74413R_CHANNEL_MAX + 1]; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + struct { + u8 rx_buf[AD74413R_FRAME_SIZE * AD74413R_CHANNEL_MAX]; + s64 timestamp; + } adc_samples_buf ____cacheline_aligned; + + u8 adc_samples_tx_buf[AD74413R_FRAME_SIZE * AD74413R_CHANNEL_MAX]; + u8 reg_tx_buf[AD74413R_FRAME_SIZE]; + u8 reg_rx_buf[AD74413R_FRAME_SIZE]; +}; + +#define AD74413R_REG_NOP 0x00 + +#define AD74413R_REG_CH_FUNC_SETUP_X(x) (0x01 + (x)) +#define AD74413R_CH_FUNC_SETUP_MASK GENMASK(3, 0) + +#define AD74413R_REG_ADC_CONFIG_X(x) (0x05 + (x)) +#define AD74413R_ADC_CONFIG_RANGE_MASK GENMASK(7, 5) +#define AD74413R_ADC_CONFIG_REJECTION_MASK GENMASK(4, 3) +#define AD74413R_ADC_RANGE_10V 0b000 +#define AD74413R_ADC_RANGE_2P5V_EXT_POW 0b001 +#define AD74413R_ADC_RANGE_2P5V_INT_POW 0b010 +#define AD74413R_ADC_RANGE_5V_BI_DIR 0b011 +#define AD74413R_ADC_REJECTION_50_60 0b00 +#define AD74413R_ADC_REJECTION_NONE 0b01 +#define AD74413R_ADC_REJECTION_50_60_HART 0b10 +#define AD74413R_ADC_REJECTION_HART 0b11 + +#define AD74413R_REG_DIN_CONFIG_X(x) (0x09 + (x)) +#define AD74413R_DIN_DEBOUNCE_MASK GENMASK(4, 0) +#define AD74413R_DIN_DEBOUNCE_LEN BIT(5) + +#define AD74413R_REG_DAC_CODE_X(x) (0x16 + (x)) +#define AD74413R_DAC_CODE_MAX GENMASK(12, 0) +#define AD74413R_DAC_VOLTAGE_MAX 11000 + +#define AD74413R_REG_GPO_PAR_DATA 0x0d +#define AD74413R_REG_GPO_CONFIG_X(x) (0x0e + (x)) +#define AD74413R_GPO_CONFIG_DATA_MASK BIT(3) +#define AD74413R_GPO_CONFIG_SELECT_MASK GENMASK(2, 0) +#define AD74413R_GPO_CONFIG_100K_PULL_DOWN 0b000 +#define AD74413R_GPO_CONFIG_LOGIC 0b001 +#define AD74413R_GPO_CONFIG_LOGIC_PARALLEL 0b010 +#define AD74413R_GPO_CONFIG_COMPARATOR 0b011 +#define AD74413R_GPO_CONFIG_HIGH_IMPEDANCE 0b100 + +#define AD74413R_REG_ADC_CONV_CTRL 0x23 +#define AD74413R_CONV_SEQ_MASK GENMASK(9, 8) +#define AD74413R_CONV_SEQ_ON 0b00 +#define AD74413R_CONV_SEQ_SINGLE 0b01 +#define AD74413R_CONV_SEQ_CONTINUOUS 0b10 +#define AD74413R_CONV_SEQ_OFF 0b11 +#define AD74413R_CH_EN_MASK(x) BIT(x) + +#define AD74413R_REG_DIN_COMP_OUT 0x25 +#define AD74413R_DIN_COMP_OUT_SHIFT_X(x) x + +#define AD74413R_REG_ADC_RESULT_X(x) (0x26 + (x)) +#define AD74413R_ADC_RESULT_MAX GENMASK(15, 0) + +#define AD74413R_REG_READ_SELECT 0x41 + +#define AD74413R_REG_CMD_KEY 0x44 +#define AD74413R_CMD_KEY_LDAC 0x953a +#define AD74413R_CMD_KEY_RESET1 0x15fa +#define AD74413R_CMD_KEY_RESET2 0xaf51 + +static const int ad74413r_adc_sampling_rates[] = { + 20, 4800, +}; + +static const int ad74413r_adc_sampling_rates_hart[] = { + 10, 20, 1200, 4800, +}; + +static int ad74413r_crc(u8 *buf) +{ + return crc8(ad74413r_crc8_table, buf, 3, 0); +} + +static void ad74413r_format_reg_write(u8 reg, u16 val, u8 *buf) +{ + buf[0] = reg; + put_unaligned_be16(val, &buf[1]); + buf[3] = ad74413r_crc(buf); +} + +static int ad74413r_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct ad74413r_state *st = context; + + ad74413r_format_reg_write(reg, val, st->reg_tx_buf); + + return spi_write(st->spi, st->reg_tx_buf, AD74413R_FRAME_SIZE); +} + +static int ad74413r_crc_check(struct ad74413r_state *st, u8 *buf) +{ + u8 expected_crc = ad74413r_crc(buf); + + if (buf[3] != expected_crc) { + dev_err(st->dev, "Bad CRC %02x for %02x%02x%02x\n", + buf[3], buf[0], buf[1], buf[2]); + return -EINVAL; + } + + return 0; +} + +static int ad74413r_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct ad74413r_state *st = context; + struct spi_transfer reg_read_xfer[] = { + { + .tx_buf = st->reg_tx_buf, + .len = AD74413R_FRAME_SIZE, + .cs_change = 1, + }, + { + .rx_buf = st->reg_rx_buf, + .len = AD74413R_FRAME_SIZE, + }, + }; + int ret; + + ad74413r_format_reg_write(AD74413R_REG_READ_SELECT, reg, + st->reg_tx_buf); + + ret = spi_sync_transfer(st->spi, reg_read_xfer, + ARRAY_SIZE(reg_read_xfer)); + if (ret) + return ret; + + ret = ad74413r_crc_check(st, st->reg_rx_buf); + if (ret) + return ret; + + *val = get_unaligned_be16(&st->reg_rx_buf[1]); + + return 0; +} + +static const struct regmap_config ad74413r_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .reg_read = ad74413r_reg_read, + .reg_write = ad74413r_reg_write, +}; + +static int ad74413r_set_gpo_config(struct ad74413r_state *st, + unsigned int offset, u8 mode) +{ + return regmap_update_bits(st->regmap, AD74413R_REG_GPO_CONFIG_X(offset), + AD74413R_GPO_CONFIG_SELECT_MASK, mode); +} + +static const unsigned int ad74413r_debounce_map[AD74413R_DIN_DEBOUNCE_LEN] = { + 0, 13, 18, 24, 32, 42, 56, 75, + 100, 130, 180, 240, 320, 420, 560, 750, + 1000, 1300, 1800, 2400, 3200, 4200, 5600, 7500, + 10000, 13000, 18000, 24000, 32000, 42000, 56000, 75000, +}; + +static int ad74413r_set_comp_debounce(struct ad74413r_state *st, + unsigned int offset, + unsigned int debounce) +{ + unsigned int val = AD74413R_DIN_DEBOUNCE_LEN - 1; + unsigned int i; + + for (i = 0; i < AD74413R_DIN_DEBOUNCE_LEN; i++) + if (debounce <= ad74413r_debounce_map[i]) { + val = i; + break; + } + + return regmap_update_bits(st->regmap, + AD74413R_REG_DIN_CONFIG_X(offset), + AD74413R_DIN_DEBOUNCE_MASK, + val); +} + +static void ad74413r_gpio_set(struct gpio_chip *chip, + unsigned int offset, int val) +{ + struct ad74413r_state *st = gpiochip_get_data(chip); + unsigned int real_offset = st->gpo_gpio_offsets[offset]; + int ret; + + ret = ad74413r_set_gpo_config(st, real_offset, + AD74413R_GPO_CONFIG_LOGIC); + if (ret) + return; + + regmap_update_bits(st->regmap, AD74413R_REG_GPO_CONFIG_X(real_offset), + AD74413R_GPO_CONFIG_DATA_MASK, + val ? AD74413R_GPO_CONFIG_DATA_MASK : 0); +} + +static void ad74413r_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, + unsigned long *bits) +{ + struct ad74413r_state *st = gpiochip_get_data(chip); + unsigned long real_mask = 0; + unsigned long real_bits = 0; + unsigned int offset = 0; + int ret; + + for_each_set_bit_from(offset, mask, AD74413R_CHANNEL_MAX) { + unsigned int real_offset = st->gpo_gpio_offsets[offset]; + + ret = ad74413r_set_gpo_config(st, real_offset, + AD74413R_GPO_CONFIG_LOGIC_PARALLEL); + if (ret) + return; + + real_mask |= BIT(real_offset); + if (*bits & offset) + real_bits |= BIT(real_offset); + } + + regmap_update_bits(st->regmap, AD74413R_REG_GPO_PAR_DATA, + real_mask, real_bits); +} + +static int ad74413r_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct ad74413r_state *st = gpiochip_get_data(chip); + unsigned int real_offset = st->comp_gpio_offsets[offset]; + unsigned int status; + int ret; + + ret = regmap_read(st->regmap, AD74413R_REG_DIN_COMP_OUT, &status); + if (ret) + return ret; + + status &= AD74413R_DIN_COMP_OUT_SHIFT_X(real_offset); + + return status ? 1 : 0; +} + +static int ad74413r_gpio_get_multiple(struct gpio_chip *chip, + unsigned long *mask, + unsigned long *bits) +{ + struct ad74413r_state *st = gpiochip_get_data(chip); + unsigned int offset = 0; + unsigned int val; + int ret; + + ret = regmap_read(st->regmap, AD74413R_REG_DIN_COMP_OUT, &val); + if (ret) + return ret; + + for_each_set_bit_from(offset, mask, AD74413R_CHANNEL_MAX) { + unsigned int real_offset = st->comp_gpio_offsets[offset]; + + if (val & BIT(real_offset)) + *bits |= offset; + } + + return ret; +} + +static int ad74413r_gpio_get_gpo_direction(struct gpio_chip *chip, + unsigned int offset) +{ + return GPIO_LINE_DIRECTION_OUT; +} + +static int ad74413r_gpio_get_comp_direction(struct gpio_chip *chip, + unsigned int offset) +{ + return GPIO_LINE_DIRECTION_IN; +} + +static int ad74413r_gpio_set_gpo_config(struct gpio_chip *chip, + unsigned int offset, + unsigned long config) +{ + struct ad74413r_state *st = gpiochip_get_data(chip); + unsigned int real_offset = st->gpo_gpio_offsets[offset]; + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_BIAS_PULL_DOWN: + return ad74413r_set_gpo_config(st, real_offset, + AD74413R_GPO_CONFIG_100K_PULL_DOWN); + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + return ad74413r_set_gpo_config(st, real_offset, + AD74413R_GPO_CONFIG_HIGH_IMPEDANCE); + default: + return -ENOTSUPP; + } +} + +static int ad74413r_gpio_set_comp_config(struct gpio_chip *chip, + unsigned int offset, + unsigned long config) +{ + struct ad74413r_state *st = gpiochip_get_data(chip); + unsigned int real_offset = st->comp_gpio_offsets[offset]; + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_INPUT_DEBOUNCE: + return ad74413r_set_comp_debounce(st, real_offset, + pinconf_to_config_argument(config)); + default: + return -ENOTSUPP; + } +} + +static int ad74413r_reset(struct ad74413r_state *st) +{ + int ret; + + ret = regmap_write(st->regmap, AD74413R_REG_CMD_KEY, + AD74413R_CMD_KEY_RESET1); + if (ret) + return ret; + + return regmap_write(st->regmap, AD74413R_REG_CMD_KEY, + AD74413R_CMD_KEY_RESET2); +} + +static int ad74413r_set_channel_dac_code(struct ad74413r_state *st, + unsigned int channel, int dac_code) +{ + struct reg_sequence reg_seq[2] = { + { AD74413R_REG_DAC_CODE_X(channel), dac_code }, + { AD74413R_REG_CMD_KEY, AD74413R_CMD_KEY_LDAC }, + }; + + return regmap_multi_reg_write(st->regmap, reg_seq, 2); +} + +static int ad74413r_set_channel_function(struct ad74413r_state *st, + unsigned int channel, u8 func) +{ + return regmap_update_bits(st->regmap, + AD74413R_REG_CH_FUNC_SETUP_X(channel), + AD74413R_CH_FUNC_SETUP_MASK, func); +} + +static int ad74413r_set_adc_conv_seq(struct ad74413r_state *st, + unsigned int status) +{ + int ret; + + /* + * These bits do not clear when a conversion completes. + * To enable a subsequent conversion, repeat the write. + */ + ret = regmap_write_bits(st->regmap, AD74413R_REG_ADC_CONV_CTRL, + AD74413R_CONV_SEQ_MASK, + FIELD_PREP(AD74413R_CONV_SEQ_MASK, status)); + if (ret) + return ret; + + /* + * Wait 100us before starting conversions. + */ + usleep_range(100, 120); + + return 0; +} + +static int ad74413r_set_adc_channel_enable(struct ad74413r_state *st, + unsigned int channel, + bool status) +{ + return regmap_update_bits(st->regmap, AD74413R_REG_ADC_CONV_CTRL, + AD74413R_CH_EN_MASK(channel), + status ? AD74413R_CH_EN_MASK(channel) : 0); +} + +static int ad74413r_get_adc_range(struct ad74413r_state *st, + unsigned int channel, + unsigned int *val) +{ + int ret; + + ret = regmap_read(st->regmap, AD74413R_REG_ADC_CONFIG_X(channel), val); + if (ret) + return ret; + + *val = FIELD_GET(AD74413R_ADC_CONFIG_RANGE_MASK, *val); + + return 0; +} + +static int ad74413r_get_adc_rejection(struct ad74413r_state *st, + unsigned int channel, + unsigned int *val) +{ + int ret; + + ret = regmap_read(st->regmap, AD74413R_REG_ADC_CONFIG_X(channel), val); + if (ret) + return ret; + + *val = FIELD_GET(AD74413R_ADC_CONFIG_REJECTION_MASK, *val); + + return 0; +} + +static int ad74413r_set_adc_rejection(struct ad74413r_state *st, + unsigned int channel, + unsigned int val) +{ + return regmap_update_bits(st->regmap, + AD74413R_REG_ADC_CONFIG_X(channel), + AD74413R_ADC_CONFIG_REJECTION_MASK, + FIELD_PREP(AD74413R_ADC_CONFIG_REJECTION_MASK, + val)); +} + +static int ad74413r_rejection_to_rate(struct ad74413r_state *st, + unsigned int rej, int *val) +{ + switch (rej) { + case AD74413R_ADC_REJECTION_50_60: + *val = 20; + return 0; + case AD74413R_ADC_REJECTION_NONE: + *val = 4800; + return 0; + case AD74413R_ADC_REJECTION_50_60_HART: + *val = 10; + return 0; + case AD74413R_ADC_REJECTION_HART: + *val = 1200; + return 0; + default: + dev_err(st->dev, "ADC rejection invalid\n"); + return -EINVAL; + } +} + +static int ad74413r_rate_to_rejection(struct ad74413r_state *st, + int rate, unsigned int *val) +{ + switch (rate) { + case 20: + *val = AD74413R_ADC_REJECTION_50_60; + return 0; + case 4800: + *val = AD74413R_ADC_REJECTION_NONE; + return 0; + case 10: + *val = AD74413R_ADC_REJECTION_50_60_HART; + return 0; + case 1200: + *val = AD74413R_ADC_REJECTION_HART; + return 0; + default: + dev_err(st->dev, "ADC rate invalid\n"); + return -EINVAL; + } +} + +static int ad74413r_range_to_voltage_range(struct ad74413r_state *st, + unsigned int range, int *val) +{ + switch (range) { + case AD74413R_ADC_RANGE_10V: + *val = 10000; + return 0; + case AD74413R_ADC_RANGE_2P5V_EXT_POW: + case AD74413R_ADC_RANGE_2P5V_INT_POW: + *val = 2500; + return 0; + case AD74413R_ADC_RANGE_5V_BI_DIR: + *val = 5000; + return 0; + default: + dev_err(st->dev, "ADC range invalid\n"); + return -EINVAL; + } +} + +static int ad74413r_range_to_voltage_offset(struct ad74413r_state *st, + unsigned int range, int *val) +{ + switch (range) { + case AD74413R_ADC_RANGE_10V: + case AD74413R_ADC_RANGE_2P5V_EXT_POW: + *val = 0; + return 0; + case AD74413R_ADC_RANGE_2P5V_INT_POW: + case AD74413R_ADC_RANGE_5V_BI_DIR: + *val = -2500; + return 0; + default: + dev_err(st->dev, "ADC range invalid\n"); + return -EINVAL; + } +} + +static int ad74413r_range_to_voltage_offset_raw(struct ad74413r_state *st, + unsigned int range, int *val) +{ + switch (range) { + case AD74413R_ADC_RANGE_10V: + case AD74413R_ADC_RANGE_2P5V_EXT_POW: + *val = 0; + return 0; + case AD74413R_ADC_RANGE_2P5V_INT_POW: + *val = -((int)AD74413R_ADC_RESULT_MAX); + return 0; + case AD74413R_ADC_RANGE_5V_BI_DIR: + *val = -((int)AD74413R_ADC_RESULT_MAX / 2); + return 0; + default: + dev_err(st->dev, "ADC range invalid\n"); + return -EINVAL; + } +} + +static int ad74413r_get_output_voltage_scale(struct ad74413r_state *st, + int *val, int *val2) +{ + *val = AD74413R_DAC_VOLTAGE_MAX; + *val2 = AD74413R_DAC_CODE_MAX; + + return IIO_VAL_FRACTIONAL; +} + +static int ad74413r_get_output_current_scale(struct ad74413r_state *st, + int *val, int *val2) +{ + *val = regulator_get_voltage(st->refin_reg); + *val2 = st->sense_resistor_ohms * AD74413R_DAC_CODE_MAX * 1000; + + return IIO_VAL_FRACTIONAL; +} + +static int ad74413r_get_input_voltage_scale(struct ad74413r_state *st, + unsigned int channel, + int *val, int *val2) +{ + unsigned int range; + int ret; + + ret = ad74413r_get_adc_range(st, channel, &range); + if (ret) + return ret; + + ret = ad74413r_range_to_voltage_range(st, range, val); + if (ret) + return ret; + + *val2 = AD74413R_ADC_RESULT_MAX; + + return IIO_VAL_FRACTIONAL; +} + +static int ad74413r_get_input_voltage_offset(struct ad74413r_state *st, + unsigned int channel, int *val) +{ + unsigned int range; + int ret; + + ret = ad74413r_get_adc_range(st, channel, &range); + if (ret) + return ret; + + ret = ad74413r_range_to_voltage_offset_raw(st, range, val); + if (ret) + return ret; + + return IIO_VAL_INT; +} + +static int ad74413r_get_input_current_scale(struct ad74413r_state *st, + unsigned int channel, int *val, + int *val2) +{ + unsigned int range; + int ret; + + ret = ad74413r_get_adc_range(st, channel, &range); + if (ret) + return ret; + + ret = ad74413r_range_to_voltage_range(st, range, val); + if (ret) + return ret; + + *val2 = AD74413R_ADC_RESULT_MAX * st->sense_resistor_ohms; + + return IIO_VAL_FRACTIONAL; +} + +static int ad74413_get_input_current_offset(struct ad74413r_state *st, + unsigned int channel, int *val) +{ + unsigned int range; + int voltage_range; + int voltage_offset; + int ret; + + ret = ad74413r_get_adc_range(st, channel, &range); + if (ret) + return ret; + + ret = ad74413r_range_to_voltage_range(st, range, &voltage_range); + if (ret) + return ret; + + ret = ad74413r_range_to_voltage_offset(st, range, &voltage_offset); + if (ret) + return ret; + + *val = voltage_offset * AD74413R_ADC_RESULT_MAX / voltage_range; + + return IIO_VAL_INT; +} + +static int ad74413r_get_adc_rate(struct ad74413r_state *st, + unsigned int channel, int *val) +{ + unsigned int rejection; + int ret; + + ret = ad74413r_get_adc_rejection(st, channel, &rejection); + if (ret) + return ret; + + ret = ad74413r_rejection_to_rate(st, rejection, val); + if (ret) + return ret; + + return IIO_VAL_INT; +} + +static int ad74413r_set_adc_rate(struct ad74413r_state *st, + unsigned int channel, int val) +{ + unsigned int rejection; + int ret; + + ret = ad74413r_rate_to_rejection(st, val, &rejection); + if (ret) + return ret; + + return ad74413r_set_adc_rejection(st, channel, rejection); +} + +static irqreturn_t ad74413r_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad74413r_state *st = iio_priv(indio_dev); + u8 *rx_buf = st->adc_samples_buf.rx_buf; + unsigned int i; + int ret; + + ret = spi_sync(st->spi, &st->adc_samples_msg); + if (ret) + goto out; + + for (i = 0; i < st->adc_active_channels; i++) + ad74413r_crc_check(st, &rx_buf[i * AD74413R_FRAME_SIZE]); + + iio_push_to_buffers_with_timestamp(indio_dev, &st->adc_samples_buf, + iio_get_time_ns(indio_dev)); + +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static irqreturn_t ad74413r_adc_data_interrupt(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct ad74413r_state *st = iio_priv(indio_dev); + + if (iio_buffer_enabled(indio_dev)) + iio_trigger_poll(st->trig); + else + complete(&st->adc_data_completion); + + return IRQ_HANDLED; +} + +static int _ad74413r_get_single_adc_result(struct ad74413r_state *st, + unsigned int channel, int *val) +{ + unsigned int uval; + int ret; + + reinit_completion(&st->adc_data_completion); + + ret = ad74413r_set_adc_channel_enable(st, channel, true); + if (ret) + return ret; + + ret = ad74413r_set_adc_conv_seq(st, AD74413R_CONV_SEQ_SINGLE); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&st->adc_data_completion, + msecs_to_jiffies(1000)); + if (!ret) { + ret = -ETIMEDOUT; + return ret; + } + + ret = regmap_read(st->regmap, AD74413R_REG_ADC_RESULT_X(channel), + &uval); + if (ret) + return ret; + + ret = ad74413r_set_adc_conv_seq(st, AD74413R_CONV_SEQ_OFF); + if (ret) + return ret; + + ret = ad74413r_set_adc_channel_enable(st, channel, false); + if (ret) + return ret; + + *val = uval; + + return IIO_VAL_INT; +} + +static int ad74413r_get_single_adc_result(struct iio_dev *indio_dev, + unsigned int channel, int *val) +{ + struct ad74413r_state *st = iio_priv(indio_dev); + int ret; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + mutex_lock(&st->lock); + ret = _ad74413r_get_single_adc_result(st, channel, val); + mutex_unlock(&st->lock); + + iio_device_release_direct_mode(indio_dev); + + return ret; +} + +static void ad74413r_adc_to_resistance_result(int adc_result, int *val) +{ + if (adc_result == AD74413R_ADC_RESULT_MAX) + adc_result = AD74413R_ADC_RESULT_MAX - 1; + + *val = DIV_ROUND_CLOSEST(adc_result * 2100, + AD74413R_ADC_RESULT_MAX - adc_result); +} + +static int ad74413r_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *active_scan_mask) +{ + struct ad74413r_state *st = iio_priv(indio_dev); + struct spi_transfer *xfer = st->adc_samples_xfer; + u8 *rx_buf = &st->adc_samples_buf.rx_buf[-1 * AD74413R_FRAME_SIZE]; + u8 *tx_buf = st->adc_samples_tx_buf; + unsigned int channel; + int ret = -EINVAL; + + mutex_lock(&st->lock); + + spi_message_init(&st->adc_samples_msg); + st->adc_active_channels = 0; + + for_each_clear_bit(channel, active_scan_mask, AD74413R_CHANNEL_MAX) { + ret = ad74413r_set_adc_channel_enable(st, channel, false); + if (ret) + goto out; + } + + if (*active_scan_mask == 0) + goto out; + + /* + * The read select register is used to select which register's value + * will be sent by the slave on the next SPI frame. + * + * Create an SPI message that, on each step, writes to the read select + * register to select the ADC result of the next enabled channel, and + * reads the ADC result of the previous enabled channel. + * + * Example: + * W: [WCH1] [WCH2] [WCH2] [WCH3] [ ] + * R: [ ] [RCH1] [RCH2] [RCH3] [RCH4] + */ + + for_each_set_bit(channel, active_scan_mask, AD74413R_CHANNEL_MAX) { + ret = ad74413r_set_adc_channel_enable(st, channel, true); + if (ret) + goto out; + + st->adc_active_channels++; + + if (xfer == st->adc_samples_xfer) + xfer->rx_buf = NULL; + else + xfer->rx_buf = rx_buf; + + xfer->tx_buf = tx_buf; + xfer->len = AD74413R_FRAME_SIZE; + xfer->cs_change = 1; + + ad74413r_format_reg_write(AD74413R_REG_READ_SELECT, + AD74413R_REG_ADC_RESULT_X(channel), + tx_buf); + + spi_message_add_tail(xfer, &st->adc_samples_msg); + + xfer++; + tx_buf += AD74413R_FRAME_SIZE; + rx_buf += AD74413R_FRAME_SIZE; + } + + xfer->rx_buf = rx_buf; + xfer->tx_buf = NULL; + xfer->len = AD74413R_FRAME_SIZE; + xfer->cs_change = 0; + + spi_message_add_tail(xfer, &st->adc_samples_msg); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static int ad74413r_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad74413r_state *st = iio_priv(indio_dev); + + return ad74413r_set_adc_conv_seq(st, AD74413R_CONV_SEQ_CONTINUOUS); +} + +static int ad74413r_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad74413r_state *st = iio_priv(indio_dev); + + return ad74413r_set_adc_conv_seq(st, AD74413R_CONV_SEQ_OFF); +} + +static int ad74413r_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct ad74413r_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + if (chan->output) + return ad74413r_get_output_voltage_scale(st, + val, val2); + else + return ad74413r_get_input_voltage_scale(st, + chan->channel, val, val2); + case IIO_CURRENT: + if (chan->output) + return ad74413r_get_output_current_scale(st, + val, val2); + else + return ad74413r_get_input_current_scale(st, + chan->channel, val, val2); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_VOLTAGE: + return ad74413r_get_input_voltage_offset(st, + chan->channel, val); + case IIO_CURRENT: + return ad74413_get_input_current_offset(st, + chan->channel, val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_RAW: + if (chan->output) + return -EINVAL; + + return ad74413r_get_single_adc_result(indio_dev, chan->channel, + val); + case IIO_CHAN_INFO_PROCESSED: { + int ret; + + ret = ad74413r_get_single_adc_result(indio_dev, chan->channel, + val); + if (ret) + return ret; + + ad74413r_adc_to_resistance_result(*val, val); + + return ret; + } + case IIO_CHAN_INFO_SAMP_FREQ: + return ad74413r_get_adc_rate(st, chan->channel, val); + default: + return -EINVAL; + } +} + +static int ad74413r_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct ad74413r_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + if (!chan->output) + return -EINVAL; + + if (val < 0 || val > AD74413R_DAC_CODE_MAX) { + dev_err(st->dev, "Invalid DAC code\n"); + return -EINVAL; + } + + return ad74413r_set_channel_dac_code(st, chan->channel, val); + case IIO_CHAN_INFO_SAMP_FREQ: + return ad74413r_set_adc_rate(st, chan->channel, val); + default: + return -EINVAL; + } +} + +static int ad74413r_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + struct ad74413r_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (st->chip_info->hart_support) { + *vals = ad74413r_adc_sampling_rates_hart; + *length = ARRAY_SIZE(ad74413r_adc_sampling_rates_hart); + } else { + *vals = ad74413r_adc_sampling_rates; + *length = ARRAY_SIZE(ad74413r_adc_sampling_rates); + } + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static const struct iio_buffer_setup_ops ad74413r_buffer_ops = { + .postenable = &ad74413r_buffer_postenable, + .predisable = &ad74413r_buffer_predisable, +}; + +static const struct iio_trigger_ops ad74413r_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, +}; + +static const struct iio_info ad74413r_info = { + .read_raw = &ad74413r_read_raw, + .write_raw = &ad74413r_write_raw, + .read_avail = &ad74413r_read_avail, + .update_scan_mode = &ad74413r_update_scan_mode, +}; + +#define AD74413R_DAC_CHANNEL(_type, extra_mask_separate) \ + { \ + .type = (_type), \ + .indexed = 1, \ + .output = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ + | (extra_mask_separate), \ + } + +#define AD74413R_ADC_CHANNEL(_type, extra_mask_separate) \ + { \ + .type = (_type), \ + .indexed = 1, \ + .output = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ + | BIT(IIO_CHAN_INFO_SAMP_FREQ) \ + | (extra_mask_separate), \ + .info_mask_separate_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 32, \ + .shift = 8, \ + .endianness = IIO_BE, \ + }, \ + } + +#define AD74413R_ADC_VOLTAGE_CHANNEL \ + AD74413R_ADC_CHANNEL(IIO_VOLTAGE, BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_OFFSET)) + +#define AD74413R_ADC_CURRENT_CHANNEL \ + AD74413R_ADC_CHANNEL(IIO_CURRENT, BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_OFFSET)) + +static struct iio_chan_spec ad74413r_voltage_output_channels[] = { + AD74413R_DAC_CHANNEL(IIO_VOLTAGE, BIT(IIO_CHAN_INFO_SCALE)), + AD74413R_ADC_CURRENT_CHANNEL, +}; + +static struct iio_chan_spec ad74413r_current_output_channels[] = { + AD74413R_DAC_CHANNEL(IIO_CURRENT, BIT(IIO_CHAN_INFO_SCALE)), + AD74413R_ADC_VOLTAGE_CHANNEL, +}; + +static struct iio_chan_spec ad74413r_voltage_input_channels[] = { + AD74413R_ADC_VOLTAGE_CHANNEL, +}; + +static struct iio_chan_spec ad74413r_current_input_channels[] = { + AD74413R_ADC_CURRENT_CHANNEL, +}; + +static struct iio_chan_spec ad74413r_resistance_input_channels[] = { + AD74413R_ADC_CHANNEL(IIO_RESISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)), +}; + +static struct iio_chan_spec ad74413r_digital_input_channels[] = { + AD74413R_ADC_VOLTAGE_CHANNEL, +}; + +#define _AD74413R_CHANNELS(_channels) \ + { \ + .channels = _channels, \ + .num_channels = ARRAY_SIZE(_channels), \ + } + +#define AD74413R_CHANNELS(name) \ + _AD74413R_CHANNELS(ad74413r_ ## name ## _channels) + +static const struct ad74413r_channels ad74413r_channels_map[] = { + [CH_FUNC_HIGH_IMPEDANCE] = AD74413R_CHANNELS(voltage_input), + [CH_FUNC_VOLTAGE_OUTPUT] = AD74413R_CHANNELS(voltage_output), + [CH_FUNC_CURRENT_OUTPUT] = AD74413R_CHANNELS(current_output), + [CH_FUNC_VOLTAGE_INPUT] = AD74413R_CHANNELS(voltage_input), + [CH_FUNC_CURRENT_INPUT_EXT_POWER] = AD74413R_CHANNELS(current_input), + [CH_FUNC_CURRENT_INPUT_LOOP_POWER] = AD74413R_CHANNELS(current_input), + [CH_FUNC_RESISTANCE_INPUT] = AD74413R_CHANNELS(resistance_input), + [CH_FUNC_DIGITAL_INPUT_LOGIC] = AD74413R_CHANNELS(digital_input), + [CH_FUNC_DIGITAL_INPUT_LOOP_POWER] = AD74413R_CHANNELS(digital_input), + [CH_FUNC_CURRENT_INPUT_EXT_POWER_HART] = AD74413R_CHANNELS(current_input), + [CH_FUNC_CURRENT_INPUT_LOOP_POWER_HART] = AD74413R_CHANNELS(current_input), +}; + +static int ad74413r_parse_channel_config(struct iio_dev *indio_dev, + struct fwnode_handle *channel_node) +{ + struct ad74413r_state *st = iio_priv(indio_dev); + struct ad74413r_channel_config *config; + u32 index; + int ret; + + ret = fwnode_property_read_u32(channel_node, "reg", &index); + if (ret) { + dev_err(st->dev, "Failed to read channel reg: %d\n", ret); + return ret; + } + + if (index >= AD74413R_CHANNEL_MAX) { + dev_err(st->dev, "Channel index %u is too large\n", index); + return -EINVAL; + } + + config = &st->channel_configs[index]; + if (config->initialized) { + dev_err(st->dev, "Channel %u already initialized\n", index); + return -EINVAL; + } + + config->func = CH_FUNC_HIGH_IMPEDANCE; + fwnode_property_read_u32(channel_node, "adi,ch-func", &config->func); + + if (config->func < CH_FUNC_MIN || config->func > CH_FUNC_MAX) { + dev_err(st->dev, "Invalid channel function %u\n", config->func); + return -EINVAL; + } + + if (!st->chip_info->hart_support && + (config->func == CH_FUNC_CURRENT_INPUT_EXT_POWER_HART || + config->func == CH_FUNC_CURRENT_INPUT_LOOP_POWER_HART)) { + dev_err(st->dev, "Unsupported HART function %u\n", config->func); + return -EINVAL; + } + + if (config->func == CH_FUNC_DIGITAL_INPUT_LOGIC || + config->func == CH_FUNC_DIGITAL_INPUT_LOOP_POWER) + st->num_comparator_gpios++; + + config->gpo_comparator = fwnode_property_read_bool(channel_node, + "adi,gpo-comparator"); + + if (!config->gpo_comparator) + st->num_gpo_gpios++; + + indio_dev->num_channels += ad74413r_channels_map[config->func].num_channels; + + config->initialized = true; + + return 0; +} + +static int ad74413r_parse_channel_configs(struct iio_dev *indio_dev) +{ + struct ad74413r_state *st = iio_priv(indio_dev); + struct fwnode_handle *channel_node = NULL; + int ret; + + fwnode_for_each_available_child_node(dev_fwnode(st->dev), channel_node) { + ret = ad74413r_parse_channel_config(indio_dev, channel_node); + if (ret) + goto put_channel_node; + } + + return 0; + +put_channel_node: + fwnode_handle_put(channel_node); + + return ret; +} + +static int ad74413r_setup_channels(struct iio_dev *indio_dev) +{ + struct ad74413r_state *st = iio_priv(indio_dev); + struct ad74413r_channel_config *config; + struct iio_chan_spec *channels, *chans; + unsigned int i, num_chans, chan_i; + int ret; + + channels = devm_kcalloc(st->dev, sizeof(*channels), + indio_dev->num_channels, GFP_KERNEL); + if (!channels) + return -ENOMEM; + + indio_dev->channels = channels; + + for (i = 0; i < AD74413R_CHANNEL_MAX; i++) { + config = &st->channel_configs[i]; + chans = ad74413r_channels_map[config->func].channels; + num_chans = ad74413r_channels_map[config->func].num_channels; + + memcpy(channels, chans, num_chans * sizeof(*chans)); + + for (chan_i = 0; chan_i < num_chans; chan_i++) { + struct iio_chan_spec *chan = &channels[chan_i]; + + chan->channel = i; + if (chan->output) + chan->scan_index = -1; + else + chan->scan_index = i; + } + + ret = ad74413r_set_channel_function(st, i, config->func); + if (ret) + return ret; + + channels += num_chans; + } + + return 0; +} + +static int ad74413r_setup_gpios(struct ad74413r_state *st) +{ + struct ad74413r_channel_config *config; + unsigned int comp_gpio_i = 0; + unsigned int gpo_gpio_i = 0; + unsigned int i; + u8 gpo_config; + int ret; + + for (i = 0; i < AD74413R_CHANNEL_MAX; i++) { + config = &st->channel_configs[i]; + + if (config->gpo_comparator) { + gpo_config = AD74413R_GPO_CONFIG_COMPARATOR; + } else { + gpo_config = AD74413R_GPO_CONFIG_LOGIC; + st->gpo_gpio_offsets[gpo_gpio_i++] = i; + } + + if (config->func == CH_FUNC_DIGITAL_INPUT_LOGIC || + config->func == CH_FUNC_DIGITAL_INPUT_LOOP_POWER) + st->comp_gpio_offsets[comp_gpio_i++] = i; + + ret = ad74413r_set_gpo_config(st, i, gpo_config); + if (ret) + return ret; + } + + return 0; +} + +static void ad74413r_regulator_disable(void *regulator) +{ + regulator_disable(regulator); +} + +static int ad74413r_probe(struct spi_device *spi) +{ + struct ad74413r_state *st; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + st->spi = spi; + st->dev = &spi->dev; + st->chip_info = device_get_match_data(&spi->dev); + mutex_init(&st->lock); + init_completion(&st->adc_data_completion); + + st->regmap = devm_regmap_init(st->dev, NULL, st, + &ad74413r_regmap_config); + if (IS_ERR(st->regmap)) + return PTR_ERR(st->regmap); + + st->refin_reg = devm_regulator_get(st->dev, "refin"); + if (IS_ERR(st->refin_reg)) + return dev_err_probe(st->dev, PTR_ERR(st->refin_reg), + "Failed to get refin regulator\n"); + + ret = regulator_enable(st->refin_reg); + if (ret) + return ret; + + ret = devm_add_action_or_reset(st->dev, ad74413r_regulator_disable, + st->refin_reg); + if (ret) + return ret; + + st->sense_resistor_ohms = 100000000; + device_property_read_u32(st->dev, "shunt-resistor-micro-ohms", + &st->sense_resistor_ohms); + st->sense_resistor_ohms /= 1000000; + + /* iio_device_id(indio_dev) -> indio_dev->id to compile against 5.10 */ + st->trig = devm_iio_trigger_alloc(st->dev, "%s-dev%d", + st->chip_info->name, indio_dev->id); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad74413r_trigger_ops; + /* dev.parent is already assigned by devm_iio_trigger_alloc on 5.12+ */ + st->trig->dev.parent = st->dev; + iio_trigger_set_drvdata(st->trig, st); + + ret = devm_iio_trigger_register(st->dev, st->trig); + if (ret) + return ret; + + indio_dev->name = st->chip_info->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &ad74413r_info; + indio_dev->trig = iio_trigger_get(st->trig); + + ret = ad74413r_reset(st); + if (ret) + return ret; + + ret = ad74413r_parse_channel_configs(indio_dev); + if (ret) + return ret; + + ret = ad74413r_setup_channels(indio_dev); + if (ret) + return ret; + + ret = ad74413r_setup_gpios(st); + if (ret) + return ret; + + if (st->num_gpo_gpios) { + st->gpo_gpiochip.owner = THIS_MODULE; + st->gpo_gpiochip.label = st->chip_info->name; + st->gpo_gpiochip.base = -1; + st->gpo_gpiochip.ngpio = st->num_gpo_gpios; + st->gpo_gpiochip.parent = st->dev; + st->gpo_gpiochip.can_sleep = true; + st->gpo_gpiochip.set = ad74413r_gpio_set; + st->gpo_gpiochip.set_multiple = ad74413r_gpio_set_multiple; + st->gpo_gpiochip.set_config = ad74413r_gpio_set_gpo_config; + st->gpo_gpiochip.get_direction = + ad74413r_gpio_get_gpo_direction; + + ret = devm_gpiochip_add_data(st->dev, &st->gpo_gpiochip, st); + if (ret) + return ret; + } + + if (st->num_comparator_gpios) { + st->comp_gpiochip.owner = THIS_MODULE; + st->comp_gpiochip.label = st->chip_info->name; + st->comp_gpiochip.base = -1; + st->comp_gpiochip.ngpio = st->num_comparator_gpios; + st->comp_gpiochip.parent = st->dev; + st->comp_gpiochip.can_sleep = true; + st->comp_gpiochip.get = ad74413r_gpio_get; + st->comp_gpiochip.get_multiple = ad74413r_gpio_get_multiple; + st->comp_gpiochip.set_config = ad74413r_gpio_set_comp_config; + st->comp_gpiochip.get_direction = + ad74413r_gpio_get_comp_direction; + + ret = devm_gpiochip_add_data(st->dev, &st->comp_gpiochip, st); + if (ret) + return ret; + } + + ret = ad74413r_set_adc_conv_seq(st, AD74413R_CONV_SEQ_OFF); + if (ret) + return ret; + + ret = devm_request_irq(st->dev, spi->irq, ad74413r_adc_data_interrupt, + 0, st->chip_info->name, indio_dev); + if (ret) + return dev_err_probe(st->dev, ret, "Failed to request irq\n"); + + ret = devm_iio_triggered_buffer_setup(st->dev, indio_dev, + &iio_pollfunc_store_time, + &ad74413r_trigger_handler, + &ad74413r_buffer_ops); + if (ret) + return ret; + + return devm_iio_device_register(st->dev, indio_dev); +} + +static int ad74413r_unregister_driver(struct spi_driver *spi) +{ + spi_unregister_driver(spi); + + return 0; +} + +static int __init ad74413r_register_driver(struct spi_driver *spi) +{ + crc8_populate_msb(ad74413r_crc8_table, AD74413R_CRC_POLYNOMIAL); + + return spi_register_driver(spi); +} + +static const struct ad74413r_chip_info ad74412r_chip_info_data = { + .hart_support = false, + .name = "ad74412r", +}; + +static const struct ad74413r_chip_info ad74413r_chip_info_data = { + .hart_support = true, + .name = "ad74413r", +}; + +static const struct of_device_id ad74413r_dt_id[] = { + { + .compatible = "adi,ad74412r", + .data = &ad74412r_chip_info_data, + }, + { + .compatible = "adi,ad74413r", + .data = &ad74413r_chip_info_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ad74413r_dt_id); + +static struct spi_driver ad74413r_driver = { + .driver = { + .name = "ad74413r", + .of_match_table = ad74413r_dt_id, + }, + .probe = ad74413r_probe, +}; + +module_driver(ad74413r_driver, + ad74413r_register_driver, + ad74413r_unregister_driver); + +MODULE_AUTHOR("Cosmin Tanislav "); +MODULE_DESCRIPTION("Analog Devices AD74413R ADDAC"); +MODULE_LICENSE("GPL v2"); From 3fe6ad713a50822c8cfcdbace939948d93adacd9 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Thu, 14 Oct 2021 19:13:20 +0300 Subject: [PATCH 088/407] iio: Kconfig.adi: select AD74413R Select AD74413R driver. Signed-off-by: Cosmin Tanislav --- drivers/iio/Kconfig.adi | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/Kconfig.adi b/drivers/iio/Kconfig.adi index 9357d65d55b081..7aa1082c4400bb 100644 --- a/drivers/iio/Kconfig.adi +++ b/drivers/iio/Kconfig.adi @@ -173,3 +173,4 @@ config IIO_ALL_ADI_DRIVERS select ONE_BIT_ADC_DAC select ADUX1020 select IIO_GEN_MUX + select AD74413R From 7a4e388df9555201bb5c6da6707ce81387b42d71 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 13 Jan 2022 14:36:43 +0100 Subject: [PATCH 089/407] iio: frequency: ad9172: Add support for jesd204-fsm This patch adds support for the: JESD204 (FSM) Interface Linux Kernel Framework. Some refactoring is done, to avoid duplicated code. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/ad9172.c | 299 +++++++++++++++++++++++++++------ 1 file changed, 251 insertions(+), 48 deletions(-) diff --git a/drivers/iio/frequency/ad9172.c b/drivers/iio/frequency/ad9172.c index 643d5b5d63726a..bb23221397fdca 100644 --- a/drivers/iio/frequency/ad9172.c +++ b/drivers/iio/frequency/ad9172.c @@ -2,7 +2,7 @@ /* * AD9172 SPI DAC driver for AXI DDS PCORE/COREFPGA Module * - * Copyright 2018-2019 Analog Devices Inc. + * Copyright 2018-2022 Analog Devices Inc. */ #include @@ -21,6 +21,10 @@ #include #include +#define JESD204_OF_PREFIX "adi," +#include +#include + #include "cf_axi_dds.h" #include "ad917x/AD917x.h" @@ -48,6 +52,8 @@ struct ad9172_state { struct cf_axi_converter conv; enum chip_id id; struct regmap *map; + struct jesd204_dev *jdev; + struct jesd204_link jesd204_link; ad917x_handle_t dac_h; jesd_param_t appJesdConfig; u32 dac_rate_khz; @@ -58,6 +64,8 @@ struct ad9172_state { u32 jesd_dual_link_mode; u32 jesd_subclass; u32 clock_output_config; + u32 scrambling; + u32 sysref_mode; bool pll_bypass; signal_type_t syncoutb_type; signal_coupling_t sysref_coupling; @@ -66,10 +74,14 @@ struct ad9172_state { u8 logic_lanes[8]; }; +struct ad9172_jesd204_priv { + struct ad9172_state *st; +}; + static const char * const clk_names[] = { - [CLK_DATA] = "jesd_dac_clk", - [CLK_DAC] = "dac_clk", - [CLK_REF] = "dac_sysref" + [CLK_DATA] = "jesd_dac_clk", /* Not required with jesd204-fsm */ + [CLK_DAC] = "dac_clk", /* Always needed */ + [CLK_REF] = "dac_sysref" /* Not required with jesd204-fsm */ }; static int ad9172_read(struct spi_device *spi, u32 reg) @@ -100,6 +112,75 @@ static unsigned long long ad9172_get_data_clk(struct cf_axi_converter *conv) return div_u64(dac_rate_Hz, st->interpolation); } +static int ad9172_link_status_get(struct ad9172_state *st, unsigned long lane_rate_kHz) +{ + struct regmap *map = st->map; + struct device *dev = regmap_get_device(map); + ad917x_jesd_link_stat_t link_status; + int ret, i; + + for (i = JESD_LINK_0; i <= JESD_LINK_1; i++) { + ret = ad917x_jesd_get_link_status(&st->dac_h, i, &link_status); + if (ret != 0) { + dev_err(dev, + "DAC:MODE:JESD: ERROR : Get Link%d status failed \r\n", i); + return -EIO; + } + + dev_info(dev, "Link%d code_grp_sync: %x\n", i, link_status.code_grp_sync_stat); + dev_info(dev, "Link%d frame_sync_stat: %x\n", i, link_status.frame_sync_stat); + dev_info(dev, "Link%d good_checksum_stat: %x\n", + i, link_status.good_checksum_stat); + dev_info(dev, "Link%d init_lane_sync_stat: %x\n", + i, link_status.init_lane_sync_stat); + dev_info(dev, "Link%d %d lanes @ %lu kBps\n", + i, st->appJesdConfig.jesd_L, lane_rate_kHz); + + if (hweight8(link_status.code_grp_sync_stat) != st->appJesdConfig.jesd_L || + link_status.code_grp_sync_stat != link_status.frame_sync_stat || + link_status.code_grp_sync_stat != link_status.init_lane_sync_stat) + return -EFAULT; + + if (!st->jesd_dual_link_mode) + break; + } + + return 0; +} + +static int ad9172_finalize_setup(struct ad9172_state *st) +{ + ad917x_handle_t *ad917x_h = &st->dac_h; + int ret; + u8 dac_mask, chan_mask; + + if (st->jesd_dual_link_mode || st->interpolation == 1) + dac_mask = AD917X_DAC0 | AD917X_DAC1; + else + dac_mask = AD917X_DAC0; + + if (st->interpolation > 1) { + chan_mask = GENMASK(st->appJesdConfig.jesd_M / 2, 0); + ret = ad917x_set_page_idx(ad917x_h, AD917X_DAC_NONE, chan_mask); + if (ret) + return ret; + + ret = ad917x_set_channel_gain(ad917x_h, 2048); /* GAIN = 1 */ + if (ret) + return ret; + + st->nco_main_enable = dac_mask; + + ad917x_nco_enable(ad917x_h, st->nco_main_enable, 0); + } + + ret = ad917x_set_page_idx(ad917x_h, dac_mask, AD917X_CH_NONE); + if (ret != 0) + return -EIO; + + return regmap_write(st->map, 0x596, 0x1c); +} + static int ad9172_setup(struct ad9172_state *st) { struct regmap *map = st->map; @@ -110,10 +191,8 @@ static int ad9172_setup(struct ad9172_state *st) int ret, i; u64 dac_rate_Hz, dac_clkin_Hz; unsigned long lane_rate_kHz; - ad917x_jesd_link_stat_t link_status; ad917x_handle_t *ad917x_h = &st->dac_h; unsigned long pll_mult; - u8 dac_mask, chan_mask; st->interpolation = st->dac_interpolation * st->channel_interpolation; @@ -211,7 +290,7 @@ static int ad9172_setup(struct ad9172_state *st) return ret; } - ret = ad917x_jesd_set_scrambler_enable(ad917x_h, 1); + ret = ad917x_jesd_set_scrambler_enable(ad917x_h, st->scrambling); if (ret != 0) { dev_err(dev, "ad917x_jesd_set_scrambler_enable failed (%d)\n", ret); @@ -250,6 +329,10 @@ static int ad9172_setup(struct ad9172_state *st) ((pll_lock_status & 0x1) == 0x1) ? "Locked" : "Unlocked", pll_lock_status); + /* No need to continue here when jesd204-fsm enabled */ + if (st->jdev) + return 0; + ad917x_get_dac_clk_freq(ad917x_h, &dac_rate_Hz); lane_rate_kHz = div_u64(dac_rate_Hz * 20 * st->appJesdConfig.jesd_M, @@ -284,48 +367,13 @@ static int ad9172_setup(struct ad9172_state *st) msleep(100); - for (i = JESD_LINK_0; i <= JESD_LINK_1; i++) { - ret = ad917x_jesd_get_link_status(ad917x_h, i, &link_status); - if (ret != 0) { - dev_err(dev, - "DAC:MODE:JESD: ERROR : Get Link%d status failed \r\n", i); - return -EIO; - } - - dev_info(dev, "Link%d code_grp_sync: %x\n", i, link_status.code_grp_sync_stat); - dev_info(dev, "Link%d frame_sync_stat: %x\n", i, link_status.frame_sync_stat); - dev_info(dev, "Link%d good_checksum_stat: %x\n", - i, link_status.good_checksum_stat); - dev_info(dev, "Link%d init_lane_sync_stat: %x\n", - i, link_status.init_lane_sync_stat); - dev_info(dev, "Link%d %d lanes @ %lu kBps\n", - i, st->appJesdConfig.jesd_L, lane_rate_kHz); - - if (!st->jesd_dual_link_mode) - break; - } - - if (st->jesd_dual_link_mode || st->interpolation == 1) - dac_mask = AD917X_DAC0 | AD917X_DAC1; - else - dac_mask = AD917X_DAC0; - - if (st->interpolation > 1) { - chan_mask = GENMASK(st->appJesdConfig.jesd_M / 2, 0); - ret = ad917x_set_page_idx(ad917x_h, AD917X_DAC_NONE, chan_mask); - - ret = ad917x_set_channel_gain(ad917x_h, 2048); /* GAIN = 1 */ - - st->nco_main_enable = dac_mask; - - ad917x_nco_enable(ad917x_h, st->nco_main_enable, 0); + ret = ad9172_link_status_get(st, lane_rate_kHz); + if (ret != 0) { + dev_err(dev, "DAC:MODE:JESD: ERROR : Link status failed\n"); + return ret; } - ret = ad917x_set_page_idx(ad917x_h, dac_mask, AD917X_CH_NONE); - if (ret != 0) - return -EIO; - - return regmap_write(st->map, 0x596, 0x1c); + return ad9172_finalize_setup(st); } static int ad9172_get_clks(struct cf_axi_converter *conv) @@ -844,6 +892,9 @@ static int ad9172_parse_dt(struct spi_device *spi, struct ad9172_state *st) st->pll_bypass = of_property_read_bool(np, "adi,direct-clocking-enable"); + st->scrambling = 1; + of_property_read_u32(np, "", &st->scrambling); + st->dac_interpolation = 1; of_property_read_u32(np, "adi,dac-interpolation", &st->dac_interpolation); @@ -866,6 +917,9 @@ static int ad9172_parse_dt(struct spi_device *spi, struct ad9172_state *st) else st->sysref_coupling = COUPLING_AC; + if (of_property_read_u32(np, "adi,sysref-mode", &st->sysref_mode)) + st->sysref_mode = SYSREF_CONT; + /*Logic lane configuration*/ ret = of_property_read_u8_array(np,"adi,logic-lanes-mapping", st->logic_lanes, sizeof(st->logic_lanes)); @@ -876,6 +930,143 @@ static int ad9172_parse_dt(struct spi_device *spi, struct ad9172_state *st) return 0; } +static int ad9172_jesd204_link_init(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason, + struct jesd204_link *lnk) +{ + struct device *dev = jesd204_dev_to_device(jdev); + struct ad9172_jesd204_priv *priv = jesd204_dev_priv(jdev); + struct ad9172_state *st = priv->st; + u64 rate; + int ret; + + if (reason != JESD204_STATE_OP_REASON_INIT) + return JESD204_STATE_CHANGE_DONE; + + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, + __LINE__, lnk->link_id, jesd204_state_op_reason_str(reason)); + + lnk->num_converters = st->appJesdConfig.jesd_M; + lnk->num_lanes = st->appJesdConfig.jesd_L; + lnk->octets_per_frame = st->appJesdConfig.jesd_F; + lnk->frames_per_multiframe = st->appJesdConfig.jesd_K; + lnk->device_id = st->appJesdConfig.jesd_DID; + lnk->bank_id = st->appJesdConfig.jesd_BID; + lnk->scrambling = st->scrambling; + lnk->bits_per_sample = st->appJesdConfig.jesd_NP; + lnk->converter_resolution = st->appJesdConfig.jesd_N; + lnk->ctrl_bits_per_sample = st->appJesdConfig.jesd_CS; + lnk->jesd_version = JESD204_VERSION_B; + lnk->subclass = st->jesd_subclass ? + JESD204_SUBCLASS_1 : JESD204_SUBCLASS_0; + lnk->high_density = st->appJesdConfig.jesd_HD; + lnk->samples_per_conv_frame = st->appJesdConfig.jesd_S; + + ret = ad917x_get_dac_clk_freq(&st->dac_h, &rate); + if (ret) + return ret; + + lnk->sample_rate = rate; + lnk->sample_rate_div = st->interpolation; + lnk->jesd_encoder = JESD204_ENCODER_8B10B; + lnk->is_transmit = true; + + if (st->sysref_mode == SYSREF_CONT) + lnk->sysref.mode = JESD204_SYSREF_CONTINUOUS; + else if (st->sysref_mode == SYSREF_ONESHOT) + lnk->sysref.mode = JESD204_SYSREF_ONESHOT; + + return JESD204_STATE_CHANGE_DONE; +} + +static int ad9172_jesd204_link_enable(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason, + struct jesd204_link *lnk) +{ + struct device *dev = jesd204_dev_to_device(jdev); + struct ad9172_jesd204_priv *priv = jesd204_dev_priv(jdev); + struct ad9172_state *st = priv->st; + int ret; + + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, + __LINE__, lnk->link_id, jesd204_state_op_reason_str(reason)); + + ad917x_jesd_set_sysref_enable(&st->dac_h, !!st->jesd_subclass); + + /*Enable Link*/ + ret = ad917x_jesd_enable_link(&st->dac_h, JESD_LINK_ALL, + reason == JESD204_STATE_OP_REASON_INIT); + if (ret != 0) { + dev_err(dev, "Failed to enabled JESD204 link (%d)\n", ret); + return -EFAULT; + } + + return JESD204_STATE_CHANGE_DONE; +} + +static int ad9172_jesd204_link_running(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason, + struct jesd204_link *lnk) +{ + struct device *dev = jesd204_dev_to_device(jdev); + struct ad9172_jesd204_priv *priv = jesd204_dev_priv(jdev); + struct ad9172_state *st = priv->st; + unsigned long lane_rate_khz; + int ret; + + if (reason != JESD204_STATE_OP_REASON_INIT) + return JESD204_STATE_CHANGE_DONE; + + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, + __LINE__, lnk->link_id, jesd204_state_op_reason_str(reason)); + + ret = jesd204_link_get_rate_khz(lnk, &lane_rate_khz); + if (ret) { + dev_err(dev, "Failed JESD204 link get rate (%d)\n", ret); + return ret; + } + + ret = ad9172_link_status_get(st, lane_rate_khz); + if (ret) { + dev_err(dev, "Failed JESD204 link status (%d)\n", ret); + return ret; + } + + return JESD204_STATE_CHANGE_DONE; +} + +static int ad9172_jesd204_post_running_stage(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason) +{ + struct ad9172_jesd204_priv *priv = jesd204_dev_priv(jdev); + struct ad9172_state *st = priv->st; + + return ad9172_finalize_setup(st); +} + +static const struct jesd204_dev_data jesd204_ad9172_init = { + .state_ops = { + [JESD204_OP_LINK_INIT] = { + .per_link = ad9172_jesd204_link_init, + }, + [JESD204_OP_LINK_ENABLE] = { + .per_link = ad9172_jesd204_link_enable, + .post_state_sysref = true, + }, + [JESD204_OP_LINK_RUNNING] = { + .per_link = ad9172_jesd204_link_running, + }, + [JESD204_OP_OPT_POST_RUNNING_STAGE] = { + .per_device = ad9172_jesd204_post_running_stage, + .mode = JESD204_STATE_OP_MODE_PER_DEVICE, + }, + }, + + .max_num_links = 1, + .num_retries = 2, + .sizeof_priv = sizeof(struct ad9172_jesd204_priv), +}; + static int ad9172_probe(struct spi_device *spi) { const struct spi_device_id *dev_id = spi_get_device_id(spi); @@ -913,6 +1104,17 @@ static int ad9172_probe(struct spi_device *spi) if (ret < 0) return ret; + st->jdev = devm_jesd204_dev_register(&spi->dev, &jesd204_ad9172_init); + if (IS_ERR(st->jdev)) + return PTR_ERR(st->jdev); + + if (st->jdev) { + struct ad9172_jesd204_priv *priv; + + priv = jesd204_dev_priv(st->jdev); + priv->st = st; + } + conv->write = ad9172_write; conv->read = ad9172_read; conv->setup = ad9172_prepare; @@ -974,7 +1176,8 @@ static int ad9172_probe(struct spi_device *spi) spi_set_drvdata(spi, conv); dev_info(&spi->dev, "Probed.\n"); - return 0; + + return jesd204_fsm_start(st->jdev, JESD204_LINKS_ALL); out: return ret; } From f7dbea887207963e18bd2e459833603a9d4b1355 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 14 Jan 2022 08:44:25 +0100 Subject: [PATCH 090/407] iio: frequency: ad9172: Fix typo in info strings This driver handles the AD917x family, the AD916x family is supported with a different driver. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/ad9172.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/frequency/ad9172.c b/drivers/iio/frequency/ad9172.c index bb23221397fdca..d4b6031d98d38d 100644 --- a/drivers/iio/frequency/ad9172.c +++ b/drivers/iio/frequency/ad9172.c @@ -221,12 +221,12 @@ static int ad9172_setup(struct ad9172_state *st) if (ret != 0) return ret; - dev_info(dev, "AD916x DAC Chip ID: %d\n", dac_chip_id.chip_type); - dev_info(dev, "AD916x DAC Product ID: %x\n", dac_chip_id.prod_id); - dev_info(dev, "AD916x DAC Product Grade: %d\n", dac_chip_id.prod_grade); - dev_info(dev, "AD916x DAC Product Revision: %d\n", + dev_info(dev, "ad917x DAC Chip ID: %d\n", dac_chip_id.chip_type); + dev_info(dev, "ad917x DAC Product ID: %x\n", dac_chip_id.prod_id); + dev_info(dev, "ad917x DAC Product Grade: %d\n", dac_chip_id.prod_grade); + dev_info(dev, "ad917x DAC Product Revision: %d\n", dac_chip_id.dev_revision); - dev_info(dev, "AD916x Revision: %d.%d.%d\n", + dev_info(dev, "ad917x Revision: %d.%d.%d\n", revision[0], revision[1], revision[2]); dac_clkin_Hz = clk_get_rate_scaled(st->conv.clk[CLK_DAC], From 55a35e2bac6f0bfef70430731dae4746268609fe Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 13 Jan 2022 15:45:41 +0100 Subject: [PATCH 091/407] dts: zynq-zc706-adv7511-ad9172-fmc-ebz.dts: Add FMC FRU EEPROM This adds the support for the FMC FRU eeprom. Signed-off-by: Michael Hennerich --- .../boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts index f204b735f96118..50209c20387a7b 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts @@ -15,6 +15,19 @@ #include "zynq-zc706-adv7511.dtsi" #include +&i2c_mux { + i2c@5 { /* HPC IIC */ + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + + eeprom@50 { + compatible = "at24,24c02"; + reg = <0x50>; + }; + }; +}; + &fpga_axi { tx_dma: tx-dmac@7c420000 { #dma-cells = <1>; From ca2df7c78518c71805e52db969c185bb628d37a0 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 13 Jan 2022 16:40:59 +0100 Subject: [PATCH 092/407] dts: zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts: Move to jesd204-fsm This patch enables the jesd204-fsm and removes some nodes and attributes which are no longer needed. Signed-off-by: Michael Hennerich --- .../boot/dts/xilinx/adi-ad9172-fmc-ebz.dtsi | 24 +++++++++++++++---- ...nqmp-zcu102-rev10-ad9172-fmc-ebz-mode4.dts | 16 ++----------- .../zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts | 23 ++++++++++++------ 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/adi-ad9172-fmc-ebz.dtsi b/arch/arm64/boot/dts/xilinx/adi-ad9172-fmc-ebz.dtsi index 174f5d06684bc9..1ddc27f6990578 100644 --- a/arch/arm64/boot/dts/xilinx/adi-ad9172-fmc-ebz.dtsi +++ b/arch/arm64/boot/dts/xilinx/adi-ad9172-fmc-ebz.dtsi @@ -2,7 +2,7 @@ /* * dts file for AD9172-FMC-EBZ on Xilinx ZynqMP ZCU102 Rev 1.0 * - * Copyright (C) 2018-2019 Analog Devices Inc. + * Copyright (C) 2018-2022 Analog Devices Inc. */ &fmc_spi { @@ -37,6 +37,12 @@ "hmc7044_out9", "hmc7044_out10", "hmc7044_out11", "hmc7044_out12", "hmc7044_out13"; + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-sysref-provider; + adi,jesd204-max-sysref-frequency-hz = <2000000>; /* 2 MHz */ + hmc7044_c2: channel@2 { reg = <2>; adi,extended-name = "DAC_CLK"; @@ -48,6 +54,7 @@ adi,extended-name = "DAC_SYSREF"; adi,divider = <512>; // 5760000 adi,driver-mode = <1>; // LVPECL + adi,jesd204-sysref-chan; }; hmc7044_c12: channel@12 { reg = <12>; @@ -60,6 +67,7 @@ adi,extended-name = "FPGA_SYSREF"; adi,divider = <512>; // 5760000 adi,driver-mode = <2>; // LVDS + adi,jesd204-sysref-chan; }; }; @@ -69,18 +77,26 @@ compatible = "adi,ad9172"; reg = <1>; spi-max-frequency = <1000000>; - clocks = <&axi_ad9172_jesd>, <&hmc7044 2>, <&hmc7044 3>; - clock-names = "jesd_dac_clk", "dac_clk", "dac_sysref"; + clocks = <&hmc7044 2>; + clock-names = "dac_clk"; adi,dac-rate-khz = <2949120>; adi,jesd-link-mode = <10>; - adi,jesd-subclass = <0>; + adi,jesd-subclass = <1>; adi,dac-interpolation = <1>; adi,channel-interpolation = <1>; adi,clock-output-divider = <1>; adi,syncoutb-signal-type-lvds-enable; + adi,scrambling = <1>; + adi,sysref-mode = <2>; /* SYSREF_CONTINUOUS */ + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <0>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9172_core 0 0>; }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz-mode4.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz-mode4.dts index bce1876dbc645b..08d20a54503afa 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz-mode4.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz-mode4.dts @@ -9,36 +9,24 @@ * * JESD Link Mode 4 Example: M4, L4, S1, F2, NP'16, Interpolation: 4*8 * - * Copyright (C) 2018-2020 Analog Devices Inc. + * Copyright (C) 2018-2022 Analog Devices Inc. */ #include "zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts" #include -&axi_ad9172_jesd { - adi,octets-per-frame = <2>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <4>; - -}; &dac0_ad9172 { - //adi,dac-rate-khz = <5898240>; /* 11.8 GSPS */ adi,dac-rate-khz = <11796480>; /* 11.8 GSPS */ adi,jesd-link-mode = <4>; - adi,jesd-subclass = <0>; + adi,jesd-subclass = <1>; adi,dac-interpolation = <8>; adi,channel-interpolation = <4>; - //adi,channel-interpolation = <2>; adi,clock-output-divider = <4>; adi,syncoutb-signal-type-lvds-enable; - }; &axi_ad9172_adxcvr { - adi,out-clk-select = ; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts index 6df407788e1263..8ab422e184ab31 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts @@ -7,7 +7,7 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2018-2020 Analog Devices Inc. + * Copyright (C) 2018-2022 Analog Devices Inc. */ #include "zynqmp-zcu102-rev1.0.dts" @@ -72,6 +72,11 @@ dma-names = "tx"; spibus-connected = <&dac0_ad9172>; adi,axi-pl-fifo-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9172_jesd 0 0>; }; axi_ad9172_jesd: axi-jesd204-tx@84a90000 { @@ -83,14 +88,13 @@ clocks = <&zynqmp_clk 71>, <&axi_ad9172_adxcvr 1>, <&axi_ad9172_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <2>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9172_adxcvr 0 0>; }; axi_ad9172_adxcvr: axi-adxcvr-tx@84a60000 { @@ -106,6 +110,11 @@ #clock-cells = <1>; clock-output-names = "dac_gt_clk", "tx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&hmc7044 0 0>; }; axi_sysid_0: axi-sysid-0@85000000 { From ab701abe31b8217a32a3e65cd903546d51201c0d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 13 Jan 2022 15:07:17 +0100 Subject: [PATCH 093/407] dts: zynq-zc706-adv7511-ad9172-fmc-ebz.dts: Move to jesd204-fsm This patch enables the jesd204-fsm and removes some nodes and attributes which are no longer needed. Signed-off-by: Michael Hennerich --- arch/arm/boot/dts/adi-ad9172-fmc-ebz.dtsi | 25 ++++++++++++++++--- .../dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts | 24 ++++++++++++------ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/adi-ad9172-fmc-ebz.dtsi b/arch/arm/boot/dts/adi-ad9172-fmc-ebz.dtsi index 309d9a89eed196..6f79830e717037 100644 --- a/arch/arm/boot/dts/adi-ad9172-fmc-ebz.dtsi +++ b/arch/arm/boot/dts/adi-ad9172-fmc-ebz.dtsi @@ -2,7 +2,7 @@ /* * dts file for AD9172-FMC-EBZ on Xilinx ZynqMP ZCU102 Rev 1.0 * - * Copyright (C) 2018-2019 Analog Devices Inc. + * Copyright (C) 2018-2022 Analog Devices Inc. */ &fmc_spi { @@ -37,6 +37,12 @@ "hmc7044_out9", "hmc7044_out10", "hmc7044_out11", "hmc7044_out12", "hmc7044_out13"; + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-sysref-provider; + adi,jesd204-max-sysref-frequency-hz = <2000000>; /* 2 MHz */ + hmc7044_c2: channel@2 { reg = <2>; adi,extended-name = "DAC_CLK"; @@ -48,6 +54,7 @@ adi,extended-name = "DAC_SYSREF"; adi,divider = <512>; // 5760000 adi,driver-mode = <1>; // LVPECL + adi,jesd204-sysref-chan; }; hmc7044_c12: channel@12 { reg = <12>; @@ -60,6 +67,7 @@ adi,extended-name = "FPGA_SYSREF"; adi,divider = <512>; // 5760000 adi,driver-mode = <2>; // LVDS + adi,jesd204-sysref-chan; }; }; @@ -69,17 +77,26 @@ compatible = "adi,ad9172"; reg = <1>; spi-max-frequency = <1000000>; - clocks = <&axi_ad9172_jesd>, <&hmc7044 2>, <&hmc7044 3>; - clock-names = "jesd_dac_clk", "dac_clk", "dac_sysref"; + clocks = <&hmc7044 2>; + clock-names = "dac_clk"; adi,dac-rate-khz = <11796480>; adi,jesd-link-mode = <4>; - adi,jesd-subclass = <0>; + adi,jesd-subclass = <1>; adi,dac-interpolation = <8>; adi,channel-interpolation = <4>; adi,clock-output-divider = <4>; adi,syncoutb-signal-type-lvds-enable; + adi,scrambling = <1>; + adi,sysref-mode = <2>; /* SYSREF_CONTINUOUS */ + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <0>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9172_core 0 0>; }; }; diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts index 50209c20387a7b..ecd5b02a878451 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts @@ -7,7 +7,7 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2018-2020 Analog Devices Inc. + * Copyright (C) 2018-2022 Analog Devices Inc. */ /dts-v1/; @@ -58,6 +58,11 @@ dma-names = "tx"; spibus-connected = <&dac0_ad9172>; adi,axi-pl-fifo-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9172_jesd 0 0>; }; axi_ad9172_jesd: axi-jesd204-tx@44A90000 { @@ -69,14 +74,13 @@ clocks = <&clkc 16>, <&axi_ad9172_adxcvr 1>, <&axi_ad9172_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <2>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <4>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9172_adxcvr 0 0>; }; axi_ad9172_adxcvr: axi-adxcvr-tx@44A60000 { @@ -92,10 +96,14 @@ #clock-cells = <1>; clock-output-names = "dac_gt_clk", "tx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&hmc7044 0 0>; }; }; - &spi0 { status = "okay"; }; From 20d1b978c370acfeeaa7f12224c175e4cb866590 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 14 Jan 2022 08:35:29 +0100 Subject: [PATCH 094/407] dts: zynqmp-zcu102-rev10-ad9172-fmc-ebz: axi-dmac remove channel node This patch removes the adi,channels node since it is no longer required. This information instead is read from the HDL core synthesis parameters. Signed-off-by: Michael Hennerich --- .../xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts index 8ab422e184ab31..ee2eeda0bfc487 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9172-fmc-ebz.dts @@ -49,20 +49,6 @@ reg = <0x9c420000 0x10000>; interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; clocks = <&zynqmp_clk 71>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <128>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <256>; - adi,destination-bus-type = <1>; - adi,cyclic; - }; - }; }; axi_ad9172_core: axi-ad9172-hpc@84a04000 { From a2a6fc514c77054af488d221fc21d0028d144961 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 14 Jan 2022 08:37:31 +0100 Subject: [PATCH 095/407] dts: zynq-zc706-adv7511-ad9172-fmc-ebz: axi-dmac remove channel node This patch removes the adi,channels node since it is no longer required. This information instead is read from the HDL core synthesis parameters. Signed-off-by: Michael Hennerich --- .../boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts index ecd5b02a878451..94408681835f32 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9172-fmc-ebz.dts @@ -35,20 +35,6 @@ reg = <0x7c420000 0x10000>; interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clkc 16>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <128>; - adi,destination-bus-type = <1>; - adi,cyclic; - }; - }; }; axi_ad9172_core: axi-ad9172-hpc@44A04000 { From 980f5a9bec1321901157effc391100be03298881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 13 Jan 2022 17:25:35 +0100 Subject: [PATCH 096/407] ci: add more things to ignore on checkpatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this commit, the following checkpatch warnings are ignored: * UNDOCUMENTED_DT_STRING: We have a significant amount of "active" drivers and dts with no bindings. Often this adds noise to CI. Ideally, we would add all the missing bindings so that we could stop ignoring this. * CAMELCASE: All the "external" APIs generate a lot of warnings because of this. And this is something that we can't really change. I'm also fairly sure that everyone is mostly used to not do CAMELCASE in the kernel so ignoring this should not be a big problem. Signed-off-by: Nuno Sá --- ci/travis/run-build.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index 5d315f616a4f5a..d8c94b03e58869 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -239,7 +239,9 @@ build_checkpatch() { --ignore LONG_LINE \ --ignore LONG_LINE_STRING \ --ignore LONG_LINE_COMMENT \ - --ignore PARENTHESIS_ALIGNMENT + --ignore PARENTHESIS_ALIGNMENT \ + --ignore CAMELCASE \ + --ignore UNDOCUMENTED_DT_STRING } build_dtb_build_test() { From 66d1740bc0c6b795e3873c057e2e1327b229519b Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Tue, 18 Jan 2022 00:18:11 +0200 Subject: [PATCH 097/407] arm64: dts: xilinx: Move gpio-poweroff from kernel to ATF Since drivers/firmware/psci/psci.c registers a pm_power_off, GPIO poweroff signals should be enabled by the PSCI firmware. Signed-off-by: Dragos Bogdan --- arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts b/arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts index b168aa028616f6..24150cceb4da5a 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-pluto-ng.dts @@ -585,11 +585,6 @@ gpio-key,wakeup; }; }; - - gpio-poweroff { - compatible = "gpio-poweroff"; - gpios = <&gpio 19 GPIO_ACTIVE_LOW>; - }; }; #define fmc_spi spi0 From 37db34448ba7b5f3666fc561b7dbdd6c9062b426 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 19 Jan 2022 13:48:21 +0200 Subject: [PATCH 098/407] arch:arm64:dts: add fmc eeprom device Add eeprom device inside the fmcbridge dts. Signed-off-by: Antoniu Miclaus --- ...zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-fmcbridge.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-fmcbridge.dts b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-fmcbridge.dts index b4b3118e3d6e81..0254aaa5f0bb56 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-fmcbridge.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-fmcbridge.dts @@ -126,3 +126,10 @@ spi-max-frequency = <500000>; }; }; + +&i2c_fmc { + eeprom@52 { + compatible = "at24,24c02"; + reg = <0x52>; + }; +}; From 72ae62031ebc9d527aee3acb2735c4e2b7c4fc3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 17 Jan 2022 14:43:00 +0100 Subject: [PATCH 099/407] iio: adrv9002: remove unneeded 'else if' and 'else' clauses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the changes in this commit are for code patterns as: ``` if (...) { ... return|goto|continue... } else { ... } ``` In the above code snippet the 'else' clause is redundant as there's no way both code blocks will run even without the 'else'. So it can be turned into: ``` if (...) { ... return|goto|continue... } //else code goes here... ... ``` Some other minor changes are relative to conditions that do not apply anymore. Signed-off-by: Nuno Sá --- drivers/iio/adc/navassa/adrv9002.c | 145 +++++++++++++++++++---------- 1 file changed, 95 insertions(+), 50 deletions(-) diff --git a/drivers/iio/adc/navassa/adrv9002.c b/drivers/iio/adc/navassa/adrv9002.c index 12e742fa6b5cf6..13ef4c242f579f 100644 --- a/drivers/iio/adc/navassa/adrv9002.c +++ b/drivers/iio/adc/navassa/adrv9002.c @@ -555,8 +555,10 @@ static ssize_t adrv9002_attr_show(struct device *dev, struct device_attribute *a dev_err(&phy->spi->dev, "Frequency hopping not enabled\n"); mutex_unlock(&phy->lock); return -ENOTSUPP; - } else if (iio_attr->address && - mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) { + } + + if (iio_attr->address && + mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) { dev_err(&phy->spi->dev, "HOP2 not supported! FH mode not in dual hop.\n"); mutex_unlock(&phy->lock); return -ENOTSUPP; @@ -589,8 +591,10 @@ static ssize_t adrv9002_attr_store(struct device *dev, struct device_attribute * dev_err(&phy->spi->dev, "Frequency hopping not enabled\n"); mutex_unlock(&phy->lock); return -ENOTSUPP; - } else if (iio_attr->address == ADRV9002_HOP_2_TABLE_SEL || - iio_attr->address == ADRV9002_HOP_2_TRIGGER) { + } + + if (iio_attr->address == ADRV9002_HOP_2_TABLE_SEL || + iio_attr->address == ADRV9002_HOP_2_TRIGGER) { if (phy->fh.mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) { dev_err(&phy->spi->dev, "HOP2 not supported! FH mode not in dual hop.\n"); mutex_unlock(&phy->lock); @@ -816,7 +820,9 @@ static int adrv9002_set_ensm_mode(struct iio_dev *indio_dev, if (!chann->enabled) { mutex_unlock(&phy->lock); return -ENODEV; - } else if (adrv9002_orx_enabled(phy, chann)) { + } + + if (adrv9002_orx_enabled(phy, chann)) { mutex_unlock(&phy->lock); return -EPERM; } @@ -1051,7 +1057,9 @@ static int adrv9002_set_port_en_mode(struct iio_dev *indio_dev, if (!chann->enabled) { mutex_unlock(&phy->lock); return -ENODEV; - } else if (adrv9002_orx_enabled(phy, chann)) { + } + + if (adrv9002_orx_enabled(phy, chann)) { /* * Don't allow changing port enable mode if ORx is enabled, because it * might trigger an ensm state transition which can potentially break ORx @@ -2030,7 +2038,9 @@ static int adrv9002_phy_write_raw(struct iio_dev *indio_dev, if (!rx->orx_gpio) { mutex_unlock(&phy->lock); return -ENOTSUPP; - } else if (val && !adrv9002_orx_can_enable(phy, chann)) { + } + + if (val && !adrv9002_orx_can_enable(phy, chann)) { mutex_unlock(&phy->lock); return -EPERM; } @@ -2447,19 +2457,27 @@ static int adrv9002_validate_profile(struct adrv9002_rf_phy *phy) i + 1, rx_cfg[i].profile.rxOutputRate_Hz, phy->rx_channels[0].channel.rate); return -EINVAL; - } else if (phy->rx2tx2 && i && !phy->rx_channels[0].channel.enabled) { + } + + if (phy->rx2tx2 && i && !phy->rx_channels[0].channel.enabled) { dev_err(&phy->spi->dev, "In rx2tx2, RX%d cannot be enabled while RX1 is disabled", i + 1); return -EINVAL; - } else if (phy->ssi_type != rx_cfg[i].profile.rxSsiConfig.ssiType) { + } + + if (phy->ssi_type != rx_cfg[i].profile.rxSsiConfig.ssiType) { dev_err(&phy->spi->dev, "SSI interface mismatch. PHY=%d, RX%d=%d\n", phy->ssi_type, i + 1, rx_cfg[i].profile.rxSsiConfig.ssiType); return -EINVAL; - } else if (rx_cfg[i].profile.rxSsiConfig.strobeType == ADI_ADRV9001_SSI_LONG_STROBE) { + } + + if (rx_cfg[i].profile.rxSsiConfig.strobeType == ADI_ADRV9001_SSI_LONG_STROBE) { dev_err(&phy->spi->dev, "SSI interface Long Strobe not supported\n"); return -EINVAL; - } else if (phy->ssi_type == ADI_ADRV9001_SSI_TYPE_LVDS && - !rx_cfg[i].profile.rxSsiConfig.ddrEn) { + } + + if (phy->ssi_type == ADI_ADRV9001_SSI_TYPE_LVDS && + !rx_cfg[i].profile.rxSsiConfig.ddrEn) { dev_err(&phy->spi->dev, "RX%d: Single Data Rate port not supported for LVDS\n", i + 1); return -EINVAL; @@ -2480,15 +2498,21 @@ static int adrv9002_validate_profile(struct adrv9002_rf_phy *phy) dev_err(&phy->spi->dev, "SSI interface mismatch. PHY=%d, TX%d=%d\n", phy->ssi_type, i + 1, tx_cfg[i].txSsiConfig.ssiType); return -EINVAL; - } else if (tx_cfg[i].txSsiConfig.strobeType == ADI_ADRV9001_SSI_LONG_STROBE) { + } + + if (tx_cfg[i].txSsiConfig.strobeType == ADI_ADRV9001_SSI_LONG_STROBE) { dev_err(&phy->spi->dev, "SSI interface Long Strobe not supported\n"); return -EINVAL; - } else if (phy->ssi_type == ADI_ADRV9001_SSI_TYPE_LVDS && - !tx_cfg[i].txSsiConfig.ddrEn) { + } + + if (phy->ssi_type == ADI_ADRV9001_SSI_TYPE_LVDS && + !tx_cfg[i].txSsiConfig.ddrEn) { dev_err(&phy->spi->dev, "TX%d: Single Data Rate port not supported for LVDS\n", i + 1); return -EINVAL; - } else if (phy->rx2tx2) { + } + + if (phy->rx2tx2) { if (!phy->tx_only && !phy->rx_channels[0].channel.enabled) { /* * pretty much means that in this case either all channels are @@ -2498,12 +2522,16 @@ static int adrv9002_validate_profile(struct adrv9002_rf_phy *phy) dev_err(&phy->spi->dev, "In rx2tx2, TX%d cannot be enabled while RX1 is disabled", i + 1); return -EINVAL; - } else if (i && !phy->tx_channels[0].channel.enabled) { + } + + if (i && !phy->tx_channels[0].channel.enabled) { dev_err(&phy->spi->dev, "In rx2tx2, TX%d cannot be enabled while TX1 is disabled", i + 1); return -EINVAL; - } else if (!phy->tx_only && - tx_cfg[i].txInputRate_Hz != phy->rx_channels[0].channel.rate) { + } + + if (!phy->tx_only && + tx_cfg[i].txInputRate_Hz != phy->rx_channels[0].channel.rate) { /* * pretty much means that in this case, all ports must have * the same rate. We match against RX1 since RX2 can be disabled @@ -2513,8 +2541,10 @@ static int adrv9002_validate_profile(struct adrv9002_rf_phy *phy) i + 1, tx_cfg[i].txInputRate_Hz, phy->rx_channels[0].channel.rate); return -EINVAL; - } else if (phy->tx_only && i && - tx_cfg[i].txInputRate_Hz != phy->tx_channels[0].channel.rate) { + } + + if (phy->tx_only && i && + tx_cfg[i].txInputRate_Hz != phy->tx_channels[0].channel.rate) { dev_err(&phy->spi->dev, "In rx2tx2, TX%d rate=%u must be equal to TX1, rate=%ld\n", i + 1, tx_cfg[i].txInputRate_Hz, phy->tx_channels[0].channel.rate); @@ -3003,9 +3033,9 @@ static int adrv9002_intf_tuning(struct adrv9002_rf_phy *phy) for (i = 0; i < ARRAY_SIZE(phy->channels); i++) { struct adrv9002_chan *c = phy->channels[i]; - if (!c->enabled) { + if (!c->enabled) continue; - } else if (phy->rx2tx2 && c->idx) { + if (phy->rx2tx2 && c->idx) { /* * In rx2tx2 we should treat both channels as the same. Hence, we will run * the test simultaneosly for both and configure the same delays. @@ -3357,7 +3387,9 @@ static int adrv9002_fh_parse_gpio_gain_control(struct adrv9002_rf_phy *phy, dev_err(&phy->spi->dev, "No reg property defined for gain pin setup channel\n"); goto of_child_put; - } else if (chann > ADRV9002_CHANN_2) { + } + + if (chann > ADRV9002_CHANN_2) { dev_err(&phy->spi->dev, "Invalid value for gain pin setup channel: %d\n", chann); ret = -EINVAL; @@ -3429,9 +3461,10 @@ static int adrv9002_parse_fh_dt(struct adrv9002_rf_phy *phy, const struct device ret = OF_ADRV9002_FH("adi,fh-min-tx-atten-mdb", 0, 0, ADRV9001_TX_MAX_ATTENUATION_MDB, phy->fh.minTxAtten_mdB, false); - if (ret) { + if (ret) goto of_put; - } else if (phy->fh.minTxAtten_mdB % ADRV9001_TX_ATTENUATION_RESOLUTION_MDB) { + + if (phy->fh.minTxAtten_mdB % ADRV9001_TX_ATTENUATION_RESOLUTION_MDB) { dev_err(&phy->spi->dev, "adi,fh-min-tx-atten-mdb must have %d resolution\n", ADRV9001_TX_ATTENUATION_RESOLUTION_MDB); ret = -EINVAL; @@ -3441,9 +3474,10 @@ static int adrv9002_parse_fh_dt(struct adrv9002_rf_phy *phy, const struct device ret = OF_ADRV9002_FH("adi,fh-max-tx-atten-mdb", ADRV9001_TX_MAX_ATTENUATION_MDB, phy->fh.minTxAtten_mdB, ADRV9001_TX_MAX_ATTENUATION_MDB, phy->fh.maxTxAtten_mdB, false); - if (ret) { + if (ret) goto of_put; - } else if (phy->fh.maxTxAtten_mdB % ADRV9001_TX_ATTENUATION_RESOLUTION_MDB) { + + if (phy->fh.maxTxAtten_mdB % ADRV9001_TX_ATTENUATION_RESOLUTION_MDB) { dev_err(&phy->spi->dev, "adi,fh-max-tx-atten-mdb must have %d resolution\n", ADRV9001_TX_ATTENUATION_RESOLUTION_MDB); ret = -EINVAL; @@ -3942,10 +3976,10 @@ static int adrv9002_parse_rx_dt(struct adrv9002_rf_phy *phy, of_fwnode_handle(node), GPIOD_OUT_LOW, NULL); if (IS_ERR(rx->orx_gpio)) { - if (PTR_ERR(rx->orx_gpio) == -ENOENT) - rx->orx_gpio = NULL; - else + if (PTR_ERR(rx->orx_gpio) != -ENOENT) return PTR_ERR(rx->orx_gpio); + + rx->orx_gpio = NULL; } return 0; @@ -3970,7 +4004,9 @@ static int adrv9002_parse_dt(struct adrv9002_rf_phy *phy) dev_err(&phy->spi->dev, "No reg property defined for channel\n"); goto of_child_put; - } else if (chann > 1) { + } + + if (chann > 1) { dev_err(&phy->spi->dev, "Invalid value for channel: %d\n", chann); ret = -EINVAL; @@ -4027,8 +4063,10 @@ static int adrv9002_parse_dt(struct adrv9002_rf_phy *phy) dev_err(&phy->spi->dev, "No reg property defined for gpio\n"); goto of_child_put; - } else if (gpio < ADI_ADRV9001_GPIO_DIGITAL_00 || - gpio > ADI_ADRV9001_GPIO_ANALOG_11) { + } + + if (gpio < ADI_ADRV9001_GPIO_DIGITAL_00 || + gpio > ADI_ADRV9001_GPIO_ANALOG_11) { dev_err(&phy->spi->dev, "Invalid gpio number: %d\n", gpio); ret = -EINVAL; @@ -4043,12 +4081,15 @@ static int adrv9002_parse_dt(struct adrv9002_rf_phy *phy) "No adi,signal property defined for gpio%d\n", gpio); goto of_child_put; - } else if (signal >= ADI_ADRV9001_GPIO_NUM_SIGNALS) { + } + + if (signal >= ADI_ADRV9001_GPIO_NUM_SIGNALS) { dev_err(&phy->spi->dev, "Invalid gpio signal: %d\n", signal); ret = -EINVAL; goto of_child_put; } + phy->adrv9002_gpios[idx].signal = signal; ret = of_property_read_u32(child, "adi,polarity", &polarity); @@ -4076,8 +4117,6 @@ static int adrv9002_parse_dt(struct adrv9002_rf_phy *phy) goto of_child_put; } phy->adrv9002_gpios[idx].gpio.master = master; - } else { - ret = 0; } idx++; @@ -4165,18 +4204,18 @@ static ssize_t adrv9002_stream_bin_write(struct file *filp, struct kobject *kobj struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj)); struct adrv9002_rf_phy *phy = iio_priv(indio_dev); - if (off + count <= bin_attr->size) { - mutex_lock(&phy->lock); - if (!off) - phy->stream_size = 0; - memcpy(phy->stream_buf + off, buf, count); - phy->stream_size += count; - mutex_unlock(&phy->lock); - } else { + if (off + count > bin_attr->size) { dev_err(&phy->spi->dev, "Invalid stream image size:%lld!\n", count + off); return -EINVAL; } + mutex_lock(&phy->lock); + if (!off) + phy->stream_size = 0; + memcpy(phy->stream_buf + off, buf, count); + phy->stream_size += count; + mutex_unlock(&phy->lock); + return count; } @@ -4289,7 +4328,9 @@ static ssize_t adrv9002_fh_bin_table_write(struct adrv9002_rf_phy *phy, char *bu dev_err(&phy->spi->dev, "Frequency hopping not enabled\n"); mutex_unlock(&phy->lock); return -ENOTSUPP; - } else if (hop && phy->fh.mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) { + } + + if (hop && phy->fh.mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) { dev_err(&phy->spi->dev, "HOP2 not supported! FH mode not in dual hop.\n"); mutex_unlock(&phy->lock); return -ENOTSUPP; @@ -4316,7 +4357,7 @@ static ssize_t adrv9002_fh_bin_table_write(struct adrv9002_rf_phy *phy, char *bu /* skip comment lines or blank lines */ if (line[0] == '#' || !line[0]) continue; - else if (strstr(line, "table>")) + if (strstr(line, "table>")) continue; ret = sscanf(line, "%llu,%u,%u,%u,%u,%u,%u", &lo, &rx10_if, &rx20_if, &rx1_gain, @@ -4326,12 +4367,16 @@ static ssize_t adrv9002_fh_bin_table_write(struct adrv9002_rf_phy *phy, char *bu hop, table, line); mutex_unlock(&phy->lock); return -EINVAL; - } else if (entry > max_sz) { + } + + if (entry > max_sz) { dev_err(&phy->spi->dev, "Hop:%d table:%d too big:%d\n", hop, table, entry); mutex_unlock(&phy->lock); return -EINVAL; - } else if (lo < ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ || - lo > ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ) { + } + + if (lo < ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ || + lo > ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ) { dev_err(&phy->spi->dev, "Invalid value for lo:%llu, in table entry:%d\n", lo, entry); mutex_unlock(&phy->lock); From 389bb83bc04bcd13e43a1e8d33452ddcf9ef1994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 17 Jan 2022 16:41:35 +0100 Subject: [PATCH 100/407] iio: adrv9002: coding style cleanups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the checkpatch warnings when running with '--strict'. The only left warnings were relates to macro variables reuse which is not an issue in the reported places. Signed-off-by: Nuno Sá --- drivers/iio/adc/navassa/adrv9002.c | 68 +++++++++++----------- drivers/iio/adc/navassa/adrv9002.h | 8 +-- drivers/iio/adc/navassa/adrv9002_debugfs.c | 14 +++-- 3 files changed, 46 insertions(+), 44 deletions(-) diff --git a/drivers/iio/adc/navassa/adrv9002.c b/drivers/iio/adc/navassa/adrv9002.c index 13ef4c242f579f..41f7834525138d 100644 --- a/drivers/iio/adc/navassa/adrv9002.c +++ b/drivers/iio/adc/navassa/adrv9002.c @@ -70,7 +70,8 @@ #define ADRV9002_TX_EN(nr) BIT(((nr) * 2 + 1) & 0x3) #define ADRV9002_RX_MAX_GAIN_mdB \ - ((ADI_ADRV9001_RX_GAIN_INDEX_MAX - ADI_ADRV9001_RX_GAIN_INDEX_MIN) * ADRV9002_RX_GAIN_STEP_mDB) + ((ADI_ADRV9001_RX_GAIN_INDEX_MAX - ADI_ADRV9001_RX_GAIN_INDEX_MIN) * \ + ADRV9002_RX_GAIN_STEP_mDB) #define ADRV9002_RX_GAIN_STEP_mDB 500 #define ADRV9002_RX_MIN_GAIN_IDX ADI_ADRV9001_RX_GAIN_INDEX_MIN #define ADRV9002_RX_MAX_GAIN_IDX ADI_ADRV9001_RX_GAIN_INDEX_MAX @@ -90,7 +91,7 @@ (ADRV9002_RX_MAX_GAIN_mdB - ADRV9002_ORX_MAX_GAIN_DROP_mdB); \ }) -#define ADRV9002_STREAM_BINARY_SZ ADI_ADRV9001_STREAM_BINARY_IMAGE_FILE_SIZE_BYTES +#define ADRV9002_STREAM_BINARY_SZ ADI_ADRV9001_STREAM_BINARY_IMAGE_FILE_SIZE_BYTES #define ADRV9002_HP_CLK_PLL_DAHZ 884736000 /* Frequency hopping */ @@ -213,7 +214,7 @@ static int adrv9002_ssi_configure(struct adrv9002_rf_phy *phy) if (!chann->enabled) continue; - adrv9002_sync_gpio_toogle(phy); + adrv9002_sync_gpio_toggle(phy); adrv9002_get_ssi_interface(phy, chann->idx, chann->port == ADI_TX, &n_lanes, &cmos_ddr); @@ -268,7 +269,7 @@ static char *adrv9002_clk_set_dev_name(struct adrv9002_rf_phy *phy, return NULL; if (*name == '-') - len = strlcpy(dest, dev_name(&phy->spi->dev), + len = strscpy(dest, dev_name(&phy->spi->dev), ADRV9002_MAX_CLK_NAME); else *dest = '\0'; @@ -1437,7 +1438,7 @@ static int adrv9002_set_atten_control_mode(struct iio_dev *indio_dev, } static int adrv9002_get_atten_control_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) + const struct iio_chan_spec *chan) { struct adrv9002_rf_phy *phy = iio_priv(indio_dev); const int chann = ADRV_ADDRESS_CHAN(chan->address); @@ -2101,7 +2102,6 @@ static int adrv9002_phy_write_raw(struct iio_dev *indio_dev, .address = ADRV_ADDRESS(port, chan), \ } - #define ADRV9002_IIO_AUX_CONV_CHAN(idx, out, chan) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -2600,6 +2600,7 @@ static int adrv9002_power_mgmt_config(struct adrv9002_rf_phy *phy) static int adrv9002_digital_init(struct adrv9002_rf_phy *phy) { + int spi_mode = ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252; int ret; u8 tx_mask = 0; int c; @@ -2628,17 +2629,16 @@ static int adrv9002_digital_init(struct adrv9002_rf_phy *phy) */ if (phy->stream_size == ADI_ADRV9001_STREAM_BINARY_IMAGE_FILE_SIZE_BYTES) ret = adi_adrv9001_Stream_Image_Write(phy->adrv9001, 0, phy->stream_buf, - phy->stream_size, - ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252); + phy->stream_size, spi_mode); else ret = adi_adrv9001_Utilities_StreamImage_Load(phy->adrv9001, "Navassa_Stream.bin", - ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252); + spi_mode); if (ret) return adrv9002_dev_err(phy); /* program arm firmware */ ret = adi_adrv9001_Utilities_ArmImage_Load(phy->adrv9001, "Navassa_EvaluationFw.bin", - ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252); + spi_mode); if (ret) return adrv9002_dev_err(phy); @@ -2718,15 +2718,18 @@ static int adrv9002_radio_init(struct adrv9002_rf_phy *phy) }; struct adi_adrv9001_Carrier carrier = {0}; - ret = adi_adrv9001_Radio_PllLoopFilter_Set(phy->adrv9001, ADI_ADRV9001_PLL_LO1, &pll_loop_filter); + ret = adi_adrv9001_Radio_PllLoopFilter_Set(phy->adrv9001, ADI_ADRV9001_PLL_LO1, + &pll_loop_filter); if (ret) return adrv9002_dev_err(phy); - ret = adi_adrv9001_Radio_PllLoopFilter_Set(phy->adrv9001, ADI_ADRV9001_PLL_LO2, &pll_loop_filter); + ret = adi_adrv9001_Radio_PllLoopFilter_Set(phy->adrv9001, ADI_ADRV9001_PLL_LO2, + &pll_loop_filter); if (ret) return adrv9002_dev_err(phy); - ret = adi_adrv9001_Radio_PllLoopFilter_Set(phy->adrv9001, ADI_ADRV9001_PLL_AUX, &pll_loop_filter); + ret = adi_adrv9001_Radio_PllLoopFilter_Set(phy->adrv9001, ADI_ADRV9001_PLL_AUX, + &pll_loop_filter); if (ret) return adrv9002_dev_err(phy); @@ -2899,17 +2902,17 @@ int adrv9002_check_tx_test_pattern(struct adrv9002_rf_phy *phy, const int chann) ADI_ADRV9001_SSI_TESTMODE_DATA_PRBS7; struct adi_adrv9001_TxSsiTestModeCfg cfg = {0}; struct adi_adrv9001_TxSsiTestModeStatus status = {0}; + adi_adrv9001_SsiDataFormat_e data_fmt = ADI_ADRV9001_SSI_FORMAT_16_BIT_I_Q_DATA; cfg.testData = test_data; - ret = adi_adrv9001_Ssi_Tx_TestMode_Status_Inspect(phy->adrv9001, chan->number, phy->ssi_type, - ADI_ADRV9001_SSI_FORMAT_16_BIT_I_Q_DATA, - &cfg, &status); + ret = adi_adrv9001_Ssi_Tx_TestMode_Status_Inspect(phy->adrv9001, chan->number, + phy->ssi_type, data_fmt, &cfg, &status); if (ret) return adrv9002_dev_err(phy); - dev_dbg(&phy->spi->dev, "[c%d]: d_e:%u, f_f:%u f_e:%u, s_e:%u", chan->number, status.dataError, - status.fifoFull, status.fifoEmpty, status.strobeAlignError); + dev_dbg(&phy->spi->dev, "[c%d]: d_e:%u, f_f:%u f_e:%u, s_e:%u", chan->number, + status.dataError, status.fifoFull, status.fifoEmpty, status.strobeAlignError); /* only looking for data errors for now */ if (status.dataError) @@ -2924,9 +2927,8 @@ int adrv9002_check_tx_test_pattern(struct adrv9002_rf_phy *phy, const int chann) return 0; memset(&status, 0, sizeof(status)); - ret = adi_adrv9001_Ssi_Tx_TestMode_Status_Inspect(phy->adrv9001, chan->number, phy->ssi_type, - ADI_ADRV9001_SSI_FORMAT_16_BIT_I_Q_DATA, - &cfg, &status); + ret = adi_adrv9001_Ssi_Tx_TestMode_Status_Inspect(phy->adrv9001, chan->number, + phy->ssi_type, data_fmt, &cfg, &status); if (ret) return adrv9002_dev_err(phy); @@ -2944,12 +2946,14 @@ int adrv9002_intf_test_cfg(struct adrv9002_rf_phy *phy, const int chann, const b { int ret; struct adrv9002_chan *chan; + adi_adrv9001_SsiDataFormat_e data_fmt = ADI_ADRV9001_SSI_FORMAT_16_BIT_I_Q_DATA; dev_dbg(&phy->spi->dev, "cfg test stop:%u, ssi:%d, c:%d, tx:%d\n", stop, phy->ssi_type, chann, tx); if (tx) { struct adi_adrv9001_TxSsiTestModeCfg cfg = {0}; + chan = &phy->tx_channels[chann].channel; if (stop) @@ -2967,9 +2971,8 @@ int adrv9002_intf_test_cfg(struct adrv9002_rf_phy *phy, const int chann, const b /* CMOS */ cfg.testData = ADI_ADRV9001_SSI_TESTMODE_DATA_RAMP_NIBBLE; - ret = adi_adrv9001_Ssi_Tx_TestMode_Configure(phy->adrv9001, chan->number, phy->ssi_type, - ADI_ADRV9001_SSI_FORMAT_16_BIT_I_Q_DATA, - &cfg); + ret = adi_adrv9001_Ssi_Tx_TestMode_Configure(phy->adrv9001, chan->number, + phy->ssi_type, data_fmt, &cfg); if (ret) return adrv9002_dev_err(phy); @@ -2981,14 +2984,14 @@ int adrv9002_intf_test_cfg(struct adrv9002_rf_phy *phy, const int chann, const b if (!chan->enabled) return 0; - ret = adi_adrv9001_Ssi_Tx_TestMode_Configure(phy->adrv9001, chan->number, phy->ssi_type, - ADI_ADRV9001_SSI_FORMAT_16_BIT_I_Q_DATA, - &cfg); + ret = adi_adrv9001_Ssi_Tx_TestMode_Configure(phy->adrv9001, chan->number, + phy->ssi_type, data_fmt, &cfg); if (ret) return adrv9002_dev_err(phy); } else { struct adi_adrv9001_RxSsiTestModeCfg cfg = {0}; + chan = &phy->rx_channels[chann].channel; if (stop) @@ -2999,9 +3002,8 @@ int adrv9002_intf_test_cfg(struct adrv9002_rf_phy *phy, const int chann, const b /* CMOS */ cfg.testData = ADI_ADRV9001_SSI_TESTMODE_DATA_RAMP_NIBBLE; - ret = adi_adrv9001_Ssi_Rx_TestMode_Configure(phy->adrv9001, chan->number, phy->ssi_type, - ADI_ADRV9001_SSI_FORMAT_16_BIT_I_Q_DATA, - &cfg); + ret = adi_adrv9001_Ssi_Rx_TestMode_Configure(phy->adrv9001, chan->number, + phy->ssi_type, data_fmt, &cfg); if (ret) return adrv9002_dev_err(phy); @@ -3013,9 +3015,8 @@ int adrv9002_intf_test_cfg(struct adrv9002_rf_phy *phy, const int chann, const b if (!chan->enabled) return 0; - ret = adi_adrv9001_Ssi_Rx_TestMode_Configure(phy->adrv9001, chan->number, phy->ssi_type, - ADI_ADRV9001_SSI_FORMAT_16_BIT_I_Q_DATA, - &cfg); + ret = adi_adrv9001_Ssi_Rx_TestMode_Configure(phy->adrv9001, chan->number, + phy->ssi_type, data_fmt, &cfg); if (ret) return adrv9002_dev_err(phy); } @@ -4089,7 +4090,6 @@ static int adrv9002_parse_dt(struct adrv9002_rf_phy *phy) ret = -EINVAL; goto of_child_put; } - phy->adrv9002_gpios[idx].signal = signal; ret = of_property_read_u32(child, "adi,polarity", &polarity); diff --git a/drivers/iio/adc/navassa/adrv9002.h b/drivers/iio/adc/navassa/adrv9002.h index 0ee27facc7429f..ca637e8572ae51 100644 --- a/drivers/iio/adc/navassa/adrv9002.h +++ b/drivers/iio/adc/navassa/adrv9002.h @@ -143,7 +143,7 @@ struct adrv9002_chan { u32 power; int nco_freq; u8 idx; - u8 enabled;; + u8 enabled; }; struct adrv9002_rx_chan { @@ -199,7 +199,7 @@ struct adrv9002_rf_phy { struct adrv9002_rx_chan rx_channels[ADRV9002_CHANN_MAX]; struct adrv9002_tx_chan tx_channels[ADRV9002_CHANN_MAX]; struct adrv9002_chan *channels[ADRV9002_CHANN_MAX * 2]; - struct adrv9002_gpio *adrv9002_gpios; + struct adrv9002_gpio *adrv9002_gpios; struct adi_adrv9001_Device adrv9001_device; struct adi_adrv9001_Device *adrv9001; struct adrv9002_hal_cfg hal; @@ -253,10 +253,10 @@ int adrv9002_intf_change_delay(struct adrv9002_rf_phy *phy, const int channel, u u32 adrv9002_axi_dds_rate_get(struct adrv9002_rf_phy *phy, const int chan); void adrv9002_axi_hdl_loopback(struct adrv9002_rf_phy *phy, int channel, bool enable); -static inline void adrv9002_sync_gpio_toogle(const struct adrv9002_rf_phy *phy) +static inline void adrv9002_sync_gpio_toggle(const struct adrv9002_rf_phy *phy) { if (phy->rx2tx2) { - /* toogle ssi sync gpio */ + /* toggle ssi sync gpio */ gpiod_set_value_cansleep(phy->ssi_sync, 1); usleep_range(5000, 5005); gpiod_set_value_cansleep(phy->ssi_sync, 0); diff --git a/drivers/iio/adc/navassa/adrv9002_debugfs.c b/drivers/iio/adc/navassa/adrv9002_debugfs.c index cb8f09dccf3b13..5694f24bde3f55 100644 --- a/drivers/iio/adc/navassa/adrv9002_debugfs.c +++ b/drivers/iio/adc/navassa/adrv9002_debugfs.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0 /* * ADRV9002 debugfs interface * @@ -241,6 +241,7 @@ void adrv9002_debugfs_agc_config_create(struct adrv9002_rx_chan *rx, struct dent const char *attr = adrv9002_agc_get_attr(rx->channel.number, member); \ debugfs_create_bool(attr, 0600, d, &rx->agc.member); \ } + adrv9002_agc_add_file_u8(peakWaitTime); adrv9002_agc_add_file_u8(maxGainIndex); adrv9002_agc_add_file_u8(minGainIndex); @@ -366,23 +367,23 @@ static int adrv9002_pll_status_show(struct seq_file *s, void *ignored) ADI_ADRV9001_PLL_LO1, &lo1); ret = adi_adrv9001_Radio_PllStatus_Get(phy->adrv9001, - ADI_ADRV9001_PLL_LO2, &lo2); + ADI_ADRV9001_PLL_LO2, &lo2); if (ret) goto error; ret = adi_adrv9001_Radio_PllStatus_Get(phy->adrv9001, - ADI_ADRV9001_PLL_AUX, &aux); + ADI_ADRV9001_PLL_AUX, &aux); if (ret) goto error; ret = adi_adrv9001_Radio_PllStatus_Get(phy->adrv9001, - ADI_ADRV9001_PLL_CLK, &clk); + ADI_ADRV9001_PLL_CLK, &clk); if (ret) goto error; ret = adi_adrv9001_Radio_PllStatus_Get(phy->adrv9001, - ADI_ADRV9001_PLL_CLK_LP, - &clk_lp); + ADI_ADRV9001_PLL_CLK_LP, + &clk_lp); if (ret) goto error; mutex_unlock(&phy->lock); @@ -889,6 +890,7 @@ static const struct file_operations adrv9002_api_version_get_fops = { .read = adrv9002_api_version_get, .llseek = default_llseek, }; + static const char * const dgpio_str[] = { "Unassigned", "dgpio0", "dgpio1", "dgpio2", "dgpio3", "dgpio4", "dgpio5", "dgpio6", "dgpio7", "dgpio8", "dgpio9", "dgpio10", "dgpio11", "dgpio12", "dgpio13", From 7a01ca5dd071c606069482888c9b640867700c4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 17 Jan 2022 16:44:02 +0100 Subject: [PATCH 101/407] iio: adrv9002: fix debugfs attribute name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a typo in 'tx%d_ssi_strobe_delay_delay' Fixes: 17a27f3675b35 ("iio: Add ADRV9002 support") Signed-off-by: Nuno Sá --- drivers/iio/adc/navassa/adrv9002_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/navassa/adrv9002_debugfs.c b/drivers/iio/adc/navassa/adrv9002_debugfs.c index 5694f24bde3f55..1ad3b126e352e9 100644 --- a/drivers/iio/adc/navassa/adrv9002_debugfs.c +++ b/drivers/iio/adc/navassa/adrv9002_debugfs.c @@ -1341,7 +1341,7 @@ void adrv9002_debugfs_create(struct adrv9002_rf_phy *phy, struct dentry *d) debugfs_create_u8(attr, 0600, d, &phy->ssi_delays.txClkDelay[chan]); sprintf(attr, "tx%d_ssi_refclk_delay", chan); debugfs_create_u8(attr, 0600, d, &phy->ssi_delays.txRefClkDelay[chan]); - sprintf(attr, "tx%d_ssi_strobe_delay_delay", chan); + sprintf(attr, "tx%d_ssi_strobe_delay", chan); debugfs_create_u8(attr, 0600, d, &phy->ssi_delays.txStrobeDelay[chan]); sprintf(attr, "tx%d_ssi_i_data_delay", chan); debugfs_create_u8(attr, 0600, d, &phy->ssi_delays.txIDataDelay[chan]); From b50e3929c10b5c8f4847cb38a6f104fedb541527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 20 Jan 2022 14:00:29 +0100 Subject: [PATCH 102/407] ci: add custom checkout for checkpatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes a long standing issue with the checkpatch job. The problem is that whenever a not so old commit is referenced in a new commit (eg: on Fixes tag), checkpatch will report that the commit is not known even though the commit exists. The problem is that a shallow clone with depth=50 (to speed up `git fetch`) is being done in the job and hence checkpatch won't know about the commit because we don't have the whole history. This all means that we need to fetch the whole git history. To do that while minimizing fetch times, we'll do a partial clone. What this means is that only the tree and blobs respective to HEAD will be fetched instead of all trees and blobs for all existing commits. This considerably speeds up the fetch time when compared to a full fetch (more than 50% is some tests). As treeless clones are not supported in azure, we need to tell it to not do any checkout and manually handle things before calling run-build.sh. Signed-off-by: Nuno Sá --- azure-pipelines.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fc3afa450c4f29..9cadf4030f7d79 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -36,11 +36,17 @@ jobs: variables: BUILD_TYPE: checkpatch TARGET_BRANCH: $[ variables['System.PullRequest.TargetBranch'] ] + COMMIT: $[ variables['Build.SourceVersion'] ] + REPO_URL: $[ variables['Build.Repository.Uri'] ] steps: - - checkout: self - fetchDepth: 50 - clean: true - - script: ./ci/travis/run-build.sh + - checkout: none + - script: | + set -ex + git init + git remote add origin ${REPO_URL} + git fetch --filter=tree:0 --no-tags origin ${COMMIT} + git checkout --progress --force ${COMMIT} + ./ci/travis/run-build.sh displayName: 'Checkpatch Script' - job: check_is_new_adi_driver_dual_licensed From 23fa8525321e51fe61005c420973a110fe51c058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 20 Jan 2022 13:40:25 +0100 Subject: [PATCH 103/407] ci: remove unneeded dependencies from checkpatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The installed dependencies are meant for running dt bindings check rather than checkpatch. So, remove them. Signed-off-by: Nuno Sá --- ci/travis/run-build.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index d8c94b03e58869..aeb06df661b911 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -215,13 +215,6 @@ build_allmodconfig() { } build_checkpatch() { - # TODO: Re-visit periodically: - # https://github.com/torvalds/linux/blob/master/Documentation/devicetree/writing-schema.rst - # This seems to change every now-n-then - apt_install python3-ply python-git-doc libyaml-dev python3-pip python3-setuptools - pip3 install wheel - pip3 install git+https://github.com/devicetree-org/dt-schema.git@master - local ref_branch="$(get_ref_branch)" echo_green "Running checkpatch for commit range '$ref_branch..'" From 16e9edecb873787323ae2dba3039f87c20bc4d5b Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 14 Jan 2022 17:38:53 +0100 Subject: [PATCH 104/407] drivers: jesd204 :jesd204-core: copy_link_params() handle sysref param jesd204_copy_link_params() also copy the SYSREF settings form source to destination. Signed-off-by: Michael Hennerich --- drivers/jesd204/jesd204-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/jesd204/jesd204-core.c b/drivers/jesd204/jesd204-core.c index 85f20aab128e05..306c66f3b750f6 100644 --- a/drivers/jesd204/jesd204-core.c +++ b/drivers/jesd204/jesd204-core.c @@ -275,6 +275,10 @@ void jesd204_copy_link_params(struct jesd204_link *dst, dst->dac_adj_resolution_steps = src->dac_adj_resolution_steps; dst->dac_adj_direction = src->dac_adj_direction; dst->dac_phase_adj = src->dac_phase_adj; + dst->sysref.mode = dst->sysref.mode; + dst->sysref.capture_falling_edge = dst->sysref.capture_falling_edge; + dst->sysref.valid_falling_edge = dst->sysref.valid_falling_edge; + dst->sysref.lmfc_offset = dst->sysref.lmfc_offset; } EXPORT_SYMBOL_GPL(jesd204_copy_link_params); From fbdcaa819349d89e7180087276f736ba5bb9d35f Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 20 Jan 2022 14:12:41 +0100 Subject: [PATCH 105/407] iio: frequency: cf_axi_dds: setup_chip_info_tbl() real DDS chan support This patch adds support for real (non-complex) DDS channel naming. This can later be used to eliminate some of the static device<->channel assignments. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/cf_axi_dds.c | 33 ++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/iio/frequency/cf_axi_dds.c b/drivers/iio/frequency/cf_axi_dds.c index 79a18fae70e8b6..2b35f713a559b0 100644 --- a/drivers/iio/frequency/cf_axi_dds.c +++ b/drivers/iio/frequency/cf_axi_dds.c @@ -44,7 +44,7 @@ static const unsigned int interpolation_factors_available[] = {1, 8}; -static const char * const dds_extend_names[] = { +static const char * const dds_extend_names_complex[] = { "TX1_I_F1", "TX1_I_F2", "TX1_Q_F1", "TX1_Q_F2", "TX2_I_F1", "TX2_I_F2", "TX2_Q_F1", "TX2_Q_F2", "TX3_I_F1", "TX3_I_F2", "TX3_Q_F1", "TX3_Q_F2", @@ -79,6 +79,25 @@ static const char * const dds_extend_names[] = { "TX32_I_F1", "TX32_I_F2", "TX32_Q_F1", "TX32_Q_F2", }; +static const char * const dds_extend_names[] = { + "1A", "1B", "2A", "2B", + "3A", "3B", "4A", "4B", + "5A", "5B", "6A", "6B", + "7A", "7B", "8A", "8B", + "9A", "9B", "10A", "10B", + "11A", "11B", "12A", "12B", + "13A", "13B", "14A", "14B", + "15A", "15B", "16A", "16B", + "17A", "17B", "18A", "18B", + "19A", "19B", "20A", "20B", + "21A", "21B", "22A", "22B", + "23A", "23B", "24A", "24B", + "25A", "25B", "26A", "26B", + "27A", "27B", "28A", "28B", + "29A", "29B", "30A", "30B", + "31A", "31B", "32A", "32B", +}; + struct cf_axi_dds_state { struct device *dev_spi; struct axi_data_offload_state *data_offload; @@ -1799,9 +1818,15 @@ static int cf_axi_dds_setup_chip_info_tbl(struct cf_axi_dds_state *st, st->chip_info_generated.channel[c].ext_info = cf_axi_dds_ext_info; - if (i < ARRAY_SIZE(dds_extend_names)) - st->chip_info_generated.channel[ - c].extend_name = dds_extend_names[i]; + if (info->complex_modified) { + if (i < ARRAY_SIZE(dds_extend_names_complex)) + st->chip_info_generated.channel[c].extend_name = + dds_extend_names_complex[i]; + } else { + if (i < ARRAY_SIZE(dds_extend_names)) + st->chip_info_generated.channel[c].extend_name = + dds_extend_names[i]; + } } } From 38521f67847ccf1b32b833f76e7a2941689427fd Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 20 Jan 2022 14:23:56 +0100 Subject: [PATCH 106/407] iio: frequency: cf_axi_dds: Support for chan spec via axidds_core_info This adds support for providing an additional channel list via struct axidds_core_info. This is in particular useful when auto-generating the channel list from the HDL core synthesis parameter. This additional list then allows to specify channels that can't be known by this driver, such as channels of type IIO_TEMP, etc. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/cf_axi_dds.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/iio/frequency/cf_axi_dds.c b/drivers/iio/frequency/cf_axi_dds.c index 2b35f713a559b0..c85c3962d5261b 100644 --- a/drivers/iio/frequency/cf_axi_dds.c +++ b/drivers/iio/frequency/cf_axi_dds.c @@ -1746,6 +1746,8 @@ struct axidds_core_info { unsigned int rate; long info_mask_separate; const char *name; + struct iio_chan_spec device_channels[AXIDDS_MAX_NUM_CHANNELS]; + unsigned int num_device_channels; }; static int cf_axi_dds_setup_chip_info_tbl(struct cf_axi_dds_state *st, @@ -1830,9 +1832,18 @@ static int cf_axi_dds_setup_chip_info_tbl(struct cf_axi_dds_state *st, } } + st->chip_info_generated.num_dds_channels = i; + + for (i = 0; i < info->num_device_channels; i++, c++) { + if (c > ARRAY_SIZE(st->chip_info_generated.channel)) + return -EINVAL; + memcpy(&st->chip_info_generated.channel[c], + &info->device_channels[i], + sizeof(info->device_channels[0])); + } + st->chip_info_generated.num_channels = c; st->chip_info_generated.num_dp_disable_channels = m; - st->chip_info_generated.num_dds_channels = i; st->chip_info_generated.num_buf_channels = m; st->chip_info_generated.name = info->name; @@ -1875,6 +1886,17 @@ static const struct axidds_core_info ad9144_7_00_a_info = { .version = ADI_AXI_PCORE_VER(9, 0, 'a'), .rate = 1, .issue_sync_en = 1, + .complex_modified = false, + .device_channels = {{ + .type = IIO_TEMP, + .indexed = 1, + .channel = 0, + .scan_index = -1, + .info_mask_separate = + BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + }}, + .num_device_channels = 1, }; static const struct axidds_core_info ad9739a_8_00_b_info = { From 4d972ca8f47d6164d0b579b57247089cf79d8407 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 20 Jan 2022 14:40:08 +0100 Subject: [PATCH 107/407] iio: frequency: ad9528: jesd204-fsm additional link validation This adds some additional checks for the SYSREF frequency. In particular we handle a case where the initial LMFC is greater than the master SYSREF clock source. In this case we solve following equation sysref_src_pll2/k = LMFC/N, where both N and k are variables. k is going to be computed later, so we scale the LMFC by N before moving on. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/ad9528.c | 53 ++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/iio/frequency/ad9528.c b/drivers/iio/frequency/ad9528.c index efa16f93974c42..307d8685bb48d7 100644 --- a/drivers/iio/frequency/ad9528.c +++ b/drivers/iio/frequency/ad9528.c @@ -1235,6 +1235,53 @@ static int ad9528_setup(struct iio_dev *indio_dev) return 0; } +static int ad9528_lmfc_lemc_validate(struct ad9528_state *st, u64 dividend, u32 divisor) +{ + u32 rem, rem_l, rem_u, gcd_val, min; + + if (divisor > dividend) { + unsigned long best_num, best_den; + + rational_best_approximation(dividend, divisor, + 65535, 65535, &best_num, &best_den); + + divisor /= best_den; + } + + gcd_val = gcd(dividend, divisor); + min = DIV_ROUND_CLOSEST(st->sysref_src_pll2, 65535UL); + + if (gcd_val >= min) { + dev_dbg(&st->spi->dev, + "%s: dividend=%llu divisor=%u GCD=%u (st->sysref_src_pll2=%lu, min=%u)", + __func__, dividend, divisor, gcd_val, st->sysref_src_pll2, min); + + st->jdev_lmfc_lemc_gcd = gcd_val; + return 0; + } + + div_u64_rem(st->sysref_src_pll2, divisor, &rem); + + dev_dbg(&st->spi->dev, + "%s: dividend=%llu divisor=%u GCD=%u rem=%u (st->sysref_src_pll2=%lu)", + __func__, dividend, divisor, gcd_val, rem, st->sysref_src_pll2); + + div_u64_rem(dividend, divisor, &rem); + div_u64_rem(dividend, divisor - 1, &rem_l); + div_u64_rem(dividend, divisor + 1, &rem_u); + + if (rem_l > rem && rem_u > rem) { + if (st->jdev_lmfc_lemc_gcd) + st->jdev_lmfc_lemc_gcd = min(st->jdev_lmfc_lemc_gcd, divisor); + else + st->jdev_lmfc_lemc_gcd = divisor; + + return 0; + } + + return -EINVAL; +} + static int ad9528_jesd204_link_supported(struct jesd204_dev *jdev, enum jesd204_state_op_reason reason, struct jesd204_link *lnk) @@ -1260,15 +1307,17 @@ static int ad9528_jesd204_link_supported(struct jesd204_dev *jdev, if (st->jdev_lmfc_lemc_rate) { st->jdev_lmfc_lemc_rate = min(st->jdev_lmfc_lemc_rate, (u32)rate); - st->jdev_lmfc_lemc_gcd = gcd(st->jdev_lmfc_lemc_gcd, rate); + ret = ad9528_lmfc_lemc_validate(st, st->jdev_lmfc_lemc_gcd, rate); } else { st->jdev_lmfc_lemc_rate = rate; - st->jdev_lmfc_lemc_gcd = gcd(st->sysref_src_pll2, rate); + ret = ad9528_lmfc_lemc_validate(st, st->sysref_src_pll2, rate); } dev_dbg(dev, "%s:%d link_num %u LMFC/LEMC %u/%lu gcd %u\n", __func__, __LINE__, lnk->link_id, st->jdev_lmfc_lemc_rate, rate, st->jdev_lmfc_lemc_gcd); + if (ret) + return ret; return JESD204_STATE_CHANGE_DONE; } From c98d87dc6e3d165efcfbba92217e0841ac3381b9 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 20 Jan 2022 15:37:09 +0100 Subject: [PATCH 108/407] iio: frequency: ad9144: Fix die temperature reading Before the die temperature can be read, the AUX ADC must be enabled and an update mist be triggered. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/ad9144.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iio/frequency/ad9144.c b/drivers/iio/frequency/ad9144.c index c64bf707b8a4c6..0eeeddabcddab9 100644 --- a/drivers/iio/frequency/ad9144.c +++ b/drivers/iio/frequency/ad9144.c @@ -150,6 +150,9 @@ static int ad9144_get_temperature_code(struct cf_axi_converter *conv) struct ad9144_state *st = container_of(conv, struct ad9144_state, conv); unsigned val1, val2; + regmap_write(st->map, REG_DIE_TEMP_CTRL0, 1); + regmap_write(st->map, REG_DIE_TEMP_UPDATE, 1); + regmap_read(st->map, REG_DIE_TEMP0, &val1); regmap_read(st->map, REG_DIE_TEMP1, &val2); return ((val2 & 0xFF) << 8) | (val1 & 0xFF); From dd2c96bead6dd0879c905086c0f71f59b7034e23 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 20 Jan 2022 15:40:14 +0100 Subject: [PATCH 109/407] iio: frequency: ad9144: Add support for the jesd204-fsm framework This adds support for the jesd204-fsm framework. The old legacy mode is still supported and should be unaffected by this commit. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/ad9144.c | 332 ++++++++++++++++++++++++--------- 1 file changed, 241 insertions(+), 91 deletions(-) diff --git a/drivers/iio/frequency/ad9144.c b/drivers/iio/frequency/ad9144.c index 0eeeddabcddab9..6ba8533745977e 100644 --- a/drivers/iio/frequency/ad9144.c +++ b/drivers/iio/frequency/ad9144.c @@ -1,9 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * AD9144 SPI DAC driver for AXI DDS PCORE/COREFPGA Module * - * Copyright 2014 Analog Devices Inc. + * Copyright 2014-2022 Analog Devices Inc. * - * Licensed under the GPL-2. */ #include @@ -19,6 +19,10 @@ #include #include +#define JESD204_OF_PREFIX "adi," +#include +#include + #include #include #include "ad9144.h" @@ -37,35 +41,6 @@ enum chip_id { CHIPID_AD9154 = AD9144_CHIPID(0x91, 0x54, 0x9), }; -enum ad9144_sync_mode { - AD9144_SYNC_ONESHOT, - AD9144_SYNC_CONTINUOUS -}; - -struct ad9144_sysref_config { - enum ad9144_sync_mode mode; - bool capture_falling_edge; -}; - -struct ad9144_jesd204_link_config { - uint8_t did; - uint8_t bid; - - uint8_t num_lanes; - uint8_t num_converters; - uint8_t octets_per_frame; - uint8_t frames_per_multiframe; - uint8_t samples_per_frame; - - uint8_t lane_mux[8]; - - bool scrambling; - bool high_density; - uint8_t subclass; - - struct ad9144_sysref_config sysref; -}; - #define AD9144_MOD_TYPE_NONE (0x0 << 2) #define AD9144_MOD_TYPE_FINE (0x1 << 2) #define AD9144_MOD_TYPE_COARSE4 (0x2 << 2) @@ -87,7 +62,13 @@ struct ad9144_platform_data { unsigned int sync_mode; }; +struct ad9144_jesd204_priv { + struct ad9144_state *st; +}; + struct ad9144_state { + struct jesd204_dev *jdev; + struct jesd204_link link_config; struct cf_axi_converter conv; unsigned int interpolation; unsigned int fcenter_shift; @@ -97,7 +78,7 @@ struct ad9144_state { unsigned int num_lanes; unsigned int num_converters; unsigned int octets_per_frame; - + u8 lane_mux[8]; unsigned int pll_frequency; bool pll_enable; }; @@ -264,7 +245,7 @@ static int ad9144_setup_pll(struct ad9144_state *st) } static int ad9144_setup_link(struct ad9144_state *st, - struct ad9144_jesd204_link_config *config) + struct jesd204_link *config) { struct regmap *map = st->map; unsigned int lane_mask; @@ -298,8 +279,8 @@ static int ad9144_setup_link(struct ad9144_state *st, else j = 2*i; - val = config->lane_mux[j]; - val |= config->lane_mux[j+1] << 3; + val = st->lane_mux[j]; + val |= st->lane_mux[j + 1] << 3; regmap_write(map, REG_XBAR(i), val); } @@ -312,8 +293,8 @@ static int ad9144_setup_link(struct ad9144_state *st, regmap_write(map, REG_GENERAL_JRX_CTRL_1, config->subclass); - regmap_write(map, REG_ILS_DID, config->did); - regmap_write(map, REG_ILS_BID, config->bid); + regmap_write(map, REG_ILS_DID, config->device_id); + regmap_write(map, REG_ILS_BID, config->bank_id); val = L; /* L */ if (config->scrambling) @@ -329,7 +310,7 @@ static int ad9144_setup_link(struct ad9144_state *st, val |= config->subclass << 5; /* SUBCLASSV */ regmap_write(map, REG_ILS_NP, val); - val = config->samples_per_frame - 1; /* S */ + val = config->samples_per_conv_frame - 1; /* S */ val |= BIT(5); /* JESDVER */ regmap_write(map, REG_ILS_S, val); @@ -664,8 +645,37 @@ static const struct reg_sequence ad9144_optimal_serdes_settings[] = { { 0x2a0, 0x06 }, }; +static int ad9144_link_status_get(struct ad9144_state *st) +{ + struct regmap *map = st->map; + struct device *dev = regmap_get_device(map); + int ret, i; + unsigned int regs[4]; + + for (i = 0; i < ARRAY_SIZE(regs); i++) { + ret = regmap_read(map, REG_CODEGRPSYNCFLG + i, ®s[i]); + if (ret != 0) { + dev_err(dev, "Get Link0 status failed\n"); + return -EIO; + } + } + + dev_info(dev, "Link0 code grp sync: %x\n", regs[0]); + dev_info(dev, "Link0 frame sync stat: %x\n", regs[1]); + dev_info(dev, "Link0 good checksum stat: %x\n", regs[2]); + dev_info(dev, "Link0 init lane_sync stat: %x\n", regs[3]); + dev_info(dev, "Link0 %d lanes @ %lu kBps\n", st->num_lanes, + ad9144_get_lane_rate(st, ad9144_get_sample_rate(st))); + + if (hweight8(regs[0]) != st->num_lanes || + regs[0] != regs[1] || regs[0] != regs[3]) + ret = -EFAULT; + + return 0; +} + static int ad9144_setup(struct ad9144_state *st, - struct ad9144_jesd204_link_config *link_config) + struct jesd204_link *link_config) { struct regmap *map = st->map; unsigned int sync_mode; @@ -773,7 +783,7 @@ static int ad9144_setup(struct ad9144_state *st, phy_mask = 0xff; for (i = 0; i < link_config->num_lanes; i++) - phy_mask &= ~BIT(link_config->lane_mux[i]); + phy_mask &= ~BIT(st->lane_mux[i]); regmap_write(map, REG_MASTER_PD, 0x00); regmap_write(map, REG_PHY_PD, phy_mask); @@ -794,7 +804,7 @@ static int ad9144_setup(struct ad9144_state *st, regmap_write(map, 0x307, 0x0a); // receive buffer delay } - if (link_config->sysref.mode == AD9144_SYNC_ONESHOT) + if (link_config->sysref.mode == JESD204_SYSREF_ONESHOT) sync_mode = 0x1; else sync_mode = 0x2; @@ -805,6 +815,9 @@ static int ad9144_setup(struct ad9144_state *st, ad9144_setup_samplerate(st); + if (st->jdev) + return 0; + regmap_write(map, 0x300, 0x01); // enable link return 0; @@ -812,12 +825,9 @@ static int ad9144_setup(struct ad9144_state *st, static int ad9144_get_clks(struct cf_axi_converter *conv) { + struct ad9144_state *st = container_of(conv, struct ad9144_state, conv); int ret; - conv->clk[CLK_DATA] = devm_clk_get(&conv->spi->dev, clk_names[CLK_DATA]); - if (IS_ERR(conv->clk[CLK_DATA])) - return PTR_ERR(conv->clk[CLK_DATA]); - conv->clk[CLK_DAC] = devm_clk_get(&conv->spi->dev, clk_names[CLK_DAC]); if (IS_ERR(conv->clk[CLK_DAC])) return PTR_ERR(conv->clk[CLK_DAC]); @@ -826,6 +836,12 @@ static int ad9144_get_clks(struct cf_axi_converter *conv) if (ret < 0) return ret; + if (!st->jdev) { + conv->clk[CLK_DATA] = devm_clk_get(&conv->spi->dev, clk_names[CLK_DATA]); + if (IS_ERR(conv->clk[CLK_DATA])) + return PTR_ERR(conv->clk[CLK_DATA]); + } + conv->clk[CLK_REF] = devm_clk_get(&conv->spi->dev, clk_names[CLK_REF]); if (IS_ERR(conv->clk[CLK_REF])) { if (PTR_ERR(conv->clk[CLK_REF]) == -ENOENT) { @@ -925,6 +941,24 @@ static int ad9144_set_sample_rate(struct cf_axi_converter *conv, else sample_rate = clk_round_rate(conv->clk[CLK_DAC], sample_rate); + if (st->jdev) { + jesd204_fsm_stop(st->jdev, JESD204_LINKS_ALL); + jesd204_fsm_clear_errors(st->jdev, JESD204_LINKS_ALL); + + if (!st->pll_enable) { + ret = clk_set_rate(conv->clk[CLK_DAC], sample_rate); + if (ret < 0) { + dev_err(&conv->spi->dev, + "Failed to set sample rate: %d\n", ret); + return ret; + } + } else { + st->pll_frequency = sample_rate; + } + + return jesd204_fsm_start(st->jdev, JESD204_LINKS_ALL); + } + sysref_rate = DIV_ROUND_CLOSEST(sample_rate, 128); lane_rate_kHz = ad9144_get_lane_rate(st, sample_rate); @@ -1077,9 +1111,10 @@ static struct ad9144_platform_data *ad9144_parse_dt(struct device *dev) of_property_read_u32(np, "adi,jesd-link-mode", &tmp); pdata->jesd_link_mode = (tmp > 13 ? 4 : tmp); - tmp = 1; - of_property_read_u32(np, "adi,jesd-subclass", &tmp); - pdata->jesd_subclass = (tmp > 1 ? 1 : tmp); + tmp = JESD204_SUBCLASS_1; + of_property_read_u32(np, "adi,subclass", &tmp); + pdata->jesd_subclass = (tmp > JESD204_SUBCLASS_1 ? + JESD204_SUBCLASS_1 : tmp); pdata->pll_enable = of_property_read_bool(np, "adi,pll-enable"); @@ -1090,11 +1125,11 @@ static struct ad9144_platform_data *ad9144_parse_dt(struct device *dev) if (pdata->pll_enable && !pdata->pll_frequency) dev_err(dev, "DAC pll enabled but missing 'adi,pll-frequency'\n"); - tmp = AD9144_SYNC_ONESHOT; - of_property_read_u32(np, "adi,sync-mode", &tmp); + tmp = JESD204_SYSREF_ONESHOT; + of_property_read_u32(np, "adi,sysref-mode", &tmp); pdata->sync_mode = tmp; - if (pdata->sync_mode == AD9144_SYNC_CONTINUOUS && !pdata->jesd_subclass) + if (pdata->sync_mode == JESD204_SYSREF_CONTINUOUS && !pdata->jesd_subclass) dev_warn(dev, "Continuous sync mode can only be used in Subclass 1\n"); /* @@ -1138,10 +1173,125 @@ static int ad9144_reset(struct ad9144_state *st, bool spi4wire) return ret; } +static int ad9144_jesd204_link_init(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason, + struct jesd204_link *lnk) +{ + struct device *dev = jesd204_dev_to_device(jdev); + struct ad9144_jesd204_priv *priv = jesd204_dev_priv(jdev); + struct ad9144_state *st = priv->st; + + if (reason != JESD204_STATE_OP_REASON_INIT) + return JESD204_STATE_CHANGE_DONE; + + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, + lnk->link_id, jesd204_state_op_reason_str(reason)); + + jesd204_copy_link_params(lnk, &st->link_config); + + lnk->sample_rate = ad9144_get_sample_rate(st); + lnk->sample_rate_div = st->interpolation; + lnk->jesd_encoder = JESD204_ENCODER_8B10B; + lnk->jesd_version = JESD204_VERSION_B; + lnk->is_transmit = true; + + return JESD204_STATE_CHANGE_DONE; +} + +static int ad9144_jesd204_link_setup(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason, + struct jesd204_link *lnk) +{ + struct device *dev = jesd204_dev_to_device(jdev); + struct ad9144_jesd204_priv *priv = jesd204_dev_priv(jdev); + struct ad9144_state *st = priv->st; + int ret; + + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, + lnk->link_id, jesd204_state_op_reason_str(reason)); + + /*Enable Link*/ + + ret = ad9144_setup(st, lnk); + if (ret != 0) { + dev_err(dev, "Failed to enabled JESD204 link (%d)\n", ret); + return -EFAULT; + } + + return JESD204_STATE_CHANGE_DONE; +} + +static int ad9144_jesd204_link_enable(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason, + struct jesd204_link *lnk) +{ + struct device *dev = jesd204_dev_to_device(jdev); + struct ad9144_jesd204_priv *priv = jesd204_dev_priv(jdev); + struct ad9144_state *st = priv->st; + int ret; + + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, + lnk->link_id, jesd204_state_op_reason_str(reason)); + + /*Enable Link*/ + ret = regmap_write(st->map, 0x300, reason == JESD204_STATE_OP_REASON_INIT); + if (ret != 0) { + dev_err(dev, "Failed to enabled JESD204 link (%d)\n", ret); + return -EFAULT; + } + + return JESD204_STATE_CHANGE_DONE; +} + +static int ad9144_jesd204_link_running(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason, + struct jesd204_link *lnk) +{ + struct device *dev = jesd204_dev_to_device(jdev); + struct ad9144_jesd204_priv *priv = jesd204_dev_priv(jdev); + struct ad9144_state *st = priv->st; + int ret; + + if (reason != JESD204_STATE_OP_REASON_INIT) + return JESD204_STATE_CHANGE_DONE; + + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, + lnk->link_id, jesd204_state_op_reason_str(reason)); + + ret = ad9144_link_status_get(st); + if (ret) { + dev_err(dev, "Failed JESD204 link status (%d)\n", ret); + return ret; + } + + return JESD204_STATE_CHANGE_DONE; +} + +static const struct jesd204_dev_data jesd204_ad9144_init = { + .state_ops = { + [JESD204_OP_LINK_INIT] = { + .per_link = ad9144_jesd204_link_init, + }, + [JESD204_OP_LINK_SETUP] = { + .per_link = ad9144_jesd204_link_setup, + }, + [JESD204_OP_LINK_ENABLE] = { + .per_link = ad9144_jesd204_link_enable, + .post_state_sysref = true, + }, + [JESD204_OP_LINK_RUNNING] = { + .per_link = ad9144_jesd204_link_running, + }, + }, + + .max_num_links = 1, + .num_retries = 2, + .sizeof_priv = sizeof(struct ad9144_jesd204_priv), +}; + static int ad9144_probe(struct spi_device *spi) { const struct spi_device_id *dev_id = spi_get_device_id(spi); - struct ad9144_jesd204_link_config link_config; struct cf_axi_converter *conv; struct ad9144_platform_data *pdata; struct ad9144_state *st; @@ -1177,6 +1327,17 @@ static int ad9144_probe(struct spi_device *spi) if (st == NULL) return -ENOMEM; + st->jdev = devm_jesd204_dev_register(&spi->dev, &jesd204_ad9144_init); + if (IS_ERR(st->jdev)) + return PTR_ERR(st->jdev); + + if (st->jdev) { + struct ad9144_jesd204_priv *priv; + + priv = jesd204_dev_priv(st->jdev); + priv->st = st; + } + st->id = (enum chip_id) dev_id->driver_data; st->interpolation = pdata->interpolation; st->fcenter_shift = pdata->fcenter_shift; @@ -1250,24 +1411,7 @@ static int ad9144_probe(struct spi_device *spi) conv->write_raw = ad9144_write_raw; conv->read_raw = ad9144_read_raw; conv->spi = spi; - - switch (st->id) { - case CHIPID_AD9135: - conv->id = ID_AD9135; - break; - case CHIPID_AD9136: - conv->id = ID_AD9136; - break; - case CHIPID_AD9144: - conv->id = ID_AD9144; - break; - case CHIPID_AD9154: - conv->id = ID_AD9154; - break; - default: - conv->id = ID_AD9152; - break; - } + conv->id = ID_AUTO_SYNTH_PARAM; /* generate channel list automatically */ ret = ad9144_get_clks(conv); if (ret < 0) { @@ -1280,23 +1424,31 @@ static int ad9144_probe(struct spi_device *spi) st->num_converters = ad9144_jesd_modes[pdata->jesd_link_mode].m; st->octets_per_frame = ad9144_jesd_modes[pdata->jesd_link_mode].f; - memset(&link_config, 0x00, sizeof(link_config)); + st->link_config.device_id = 0; + st->link_config.bank_id = 0; + st->link_config.num_lanes = st->num_lanes; + st->link_config.num_converters = st->num_converters; + st->link_config.octets_per_frame = st->octets_per_frame; + st->link_config.frames_per_multiframe = 32; + st->link_config.samples_per_conv_frame = ad9144_jesd_modes[pdata->jesd_link_mode].s; + + st->link_config.high_density = ad9144_jesd_modes[pdata->jesd_link_mode].hd; + st->link_config.scrambling = true; + st->link_config.subclass = pdata->jesd_subclass; + st->link_config.sysref.mode = pdata->sync_mode; + st->link_config.bits_per_sample = ad9144_jesd_modes[pdata->jesd_link_mode].np; + st->link_config.converter_resolution = ad9144_jesd_modes[pdata->jesd_link_mode].n; - link_config.did = 0; - link_config.bid = 0; - link_config.num_lanes = st->num_lanes; - link_config.num_converters = st->num_converters; - link_config.octets_per_frame = st->octets_per_frame; - link_config.frames_per_multiframe = 32; - link_config.samples_per_frame = ad9144_jesd_modes[pdata->jesd_link_mode].s; + for (i = 0; i < 8; i++) + st->lane_mux[i] = pdata->xbar_lane_sel[i]; - link_config.high_density = ad9144_jesd_modes[pdata->jesd_link_mode].hd; - link_config.scrambling = true; - link_config.subclass = pdata->jesd_subclass; - link_config.sysref.mode = pdata->sync_mode; + ret = ad9144_update_sysref(st, ad9144_get_sample_rate(st)); + if (ret < 0) + return ret; - for (i = 0; i < 8; i++) - link_config.lane_mux[i] = pdata->xbar_lane_sel[i]; + /* No need to continue here when jesd204-fsm enabled */ + if (st->jdev) + goto done; lane_rate_kHz = ad9144_get_lane_rate(st, ad9144_get_sample_rate(st)); dev_dbg(&spi->dev, "Setting lane rate %ld kHz\n", lane_rate_kHz); @@ -1308,26 +1460,24 @@ static int ad9144_probe(struct spi_device *spi) return ret; } - ret = ad9144_update_sysref(st, ad9144_get_sample_rate(st)); - if (ret < 0) - return ret; - ret = clk_prepare_enable(conv->clk[0]); if (ret < 0) { dev_err(&spi->dev, "Failed to enable JESD204 link: %d\n", ret); return ret; } - ret = ad9144_setup(st, &link_config); + ret = ad9144_setup(st, &st->link_config); if (ret < 0) { dev_err(&spi->dev, "Failed to setup device\n"); goto out; } - spi_set_drvdata(spi, conv); + ad9144_link_status_get(st); +done: + spi_set_drvdata(spi, conv); dev_dbg(&spi->dev, "Probed.\n"); - return 0; + return jesd204_fsm_start(st->jdev, JESD204_LINKS_ALL); out: return ret; } From aee84b307d048ae78269d106ebb750e90c1fdac7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 20 Jan 2022 15:43:28 +0100 Subject: [PATCH 110/407] iio: adc: ad9208: api_errors: Use errno EOPNOTSUPP in favor of ENOTSUP ENOTSUPP is not a SUSV4 error code, prefer EOPNOTSUPP Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9208/api_errors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad9208/api_errors.h b/drivers/iio/adc/ad9208/api_errors.h index 4528bcb2521001..38b0cf977a7004 100644 --- a/drivers/iio/adc/ad9208/api_errors.h +++ b/drivers/iio/adc/ad9208/api_errors.h @@ -34,7 +34,7 @@ /** Invalid parameter passed */ #define API_ERROR_INVALID_PARAM (-EINVAL) /** Not supported */ -#define API_ERROR_NOT_SUPPORTED (-ENOTSUP) +#define API_ERROR_NOT_SUPPORTED (-EOPNOTSUPP) /** The VCO is out of range */ #define API_ERROR_VCO_OUT_OF_RANGE (-EINVAL) /** FTW Acknowledge not received */ From 3c71a807225433a64ed334443760db9aece4ae51 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 20 Jan 2022 15:48:26 +0100 Subject: [PATCH 111/407] iio: adc: ad9208: ad9208_adc_api: Add ad9208_adc_get_input_scale() We already have ad9208_adc_set_input_scale() this adds the corresponding getter. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9208/AD9208.h | 2 ++ drivers/iio/adc/ad9208/ad9208_adc_api.c | 45 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/drivers/iio/adc/ad9208/AD9208.h b/drivers/iio/adc/ad9208/AD9208.h index 036d9e76ea6d12..d7ea4eaccfc2e6 100644 --- a/drivers/iio/adc/ad9208/AD9208.h +++ b/drivers/iio/adc/ad9208/AD9208.h @@ -1067,6 +1067,8 @@ int ad9208_get_revision(ad9208_handle_t *h, uint8_t *rev_major, int ad9208_adc_set_input_scale(ad9208_handle_t *h, ad9208_adc_scale_range_t full_scale_range); +int ad9208_adc_get_input_scale(ad9208_handle_t *h, uint8_t *full_scale_range); + int ad9208_get_decimation(ad9208_handle_t *h, uint8_t *dcm); #endif /* !__AD9208API_H__ */ diff --git a/drivers/iio/adc/ad9208/ad9208_adc_api.c b/drivers/iio/adc/ad9208/ad9208_adc_api.c index 51f60d974c2377..1d00d2a7ae2a06 100644 --- a/drivers/iio/adc/ad9208/ad9208_adc_api.c +++ b/drivers/iio/adc/ad9208/ad9208_adc_api.c @@ -257,6 +257,51 @@ int ad9208_adc_set_input_scale(ad9208_handle_t *h, return API_ERROR_OK; } +int ad9208_adc_get_input_scale(ad9208_handle_t *h, uint8_t *full_scale_range) +{ + int err; + uint8_t tmp_reg; + + if (!h) + return API_ERROR_INVALID_HANDLE_PTR; + + if (!full_scale_range) + return API_ERROR_INVALID_HANDLE_PTR; + + if (h->model == 0x9680) /* N/A */ + return API_ERROR_NOT_SUPPORTED; + + err = ad9208_register_read(h, + AD9208_FULL_SCALE_CFG_REG, &tmp_reg); + if (err != API_ERROR_OK) + return err; + + switch (AD9208_TRM_VREF(tmp_reg)) { + case 0: + *full_scale_range = AD9208_ADC_SCALE_2P04_VPP; + break; + case 0x8: + *full_scale_range = AD9208_ADC_SCALE_1P13_VPP; + break; + case 0x9: + *full_scale_range = AD9208_ADC_SCALE_1P25_VPP; + break; + case 0xD: + *full_scale_range = AD9208_ADC_SCALE_1P7_VPP; + break; + case 0xE: + *full_scale_range = AD9208_ADC_SCALE_1P81_VPP; + break; + case 0xF: + *full_scale_range = AD9208_ADC_SCALE_1P93_VPP; + break; + default: + return API_ERROR_INVALID_PARAM; + } + + return API_ERROR_OK; +} + static int ad9208_adc_set_vcm_export(ad9208_handle_t *h, uint8_t en) { int err; From 70b0448af1983218b101834d0433543605902739 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 20 Jan 2022 15:52:46 +0100 Subject: [PATCH 112/407] iio: adc: ad9208: ad9208_jesd_api: Enable some valid error prints This enables some additional error messages in case invalid JESD parameters are provided. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9208/ad9208_jesd_api.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/ad9208/ad9208_jesd_api.c b/drivers/iio/adc/ad9208/ad9208_jesd_api.c index 6224cb77efa30a..40a07582b318a6 100644 --- a/drivers/iio/adc/ad9208/ad9208_jesd_api.c +++ b/drivers/iio/adc/ad9208/ad9208_jesd_api.c @@ -84,46 +84,46 @@ static int check_jesd_params_range(jesd_param_t jesd_param) if ((jesd_param.jesd_L != 1) && (jesd_param.jesd_L != 2) && (jesd_param.jesd_L != 4) && (jesd_param.jesd_L != 8)) { - /*printf("API:AD9208:Err: Invalid JESD L \r\n"); */ + pr_err("API:AD9208:Err: Invalid JESD L\n"); return API_ERROR_INVALID_PARAM; } if ((jesd_param.jesd_M != 1) && (jesd_param.jesd_M != 2) && (jesd_param.jesd_M != 4) && (jesd_param.jesd_M != 8)) { - /*printf("API:AD9208:Err: Invalid JESD M \r\n"); */ + pr_err("API:AD9208:Err: Invalid JESD M\n"); return API_ERROR_INVALID_PARAM; } if ((jesd_param.jesd_F != 1) && (jesd_param.jesd_F != 2) && (jesd_param.jesd_F != 4) && (jesd_param.jesd_F != 8)) { - /*printf("API:AD9208:Err: Invalid JESD F \r\n"); */ + pr_err("API:AD9208:Err: Invalid JESD F\n"); return API_ERROR_INVALID_PARAM; } if ((jesd_param.jesd_N < N_MIN) || (jesd_param.jesd_N > N_MAX)) { - /*printf("API:AD9208:Err: Invalid JESD N \r\n"); */ + pr_err("API:AD9208:Err: Invalid JESD N\n"); return API_ERROR_INVALID_PARAM; } if ((jesd_param.jesd_K < K_MIN) || (jesd_param.jesd_K > K_MAX) || (jesd_param.jesd_K % 4 != 0)) { - /*printf("API:AD9208:Err: Invalid JESD K \r\n"); */ + pr_err("API:AD9208:Err: Invalid JESD K\n"); return API_ERROR_INVALID_PARAM; } if (jesd_param.jesd_CS > CS_MAX) { - /*printf("API:AD9208:Err: Invalid JESD CS \r\n"); */ + pr_err("API:AD9208:Err: Invalid JESD CS\n"); return API_ERROR_INVALID_PARAM; } if (jesd_param.jesd_CF > CF_DEFAULT) { - /*printf("API:AD9208:Err: Invalid JESD CF \r\n"); */ + pr_err("API:AD9208:Err: Invalid JESD CF\n"); return API_ERROR_INVALID_PARAM; } if ((jesd_param.jesd_NP != 8) && (jesd_param.jesd_NP != 16)) { - /*printf("API:AD9208:Err: Invalid JESD NP \r\n"); */ + pr_err("API:AD9208:Err: Invalid JESD NP\n"); return API_ERROR_INVALID_PARAM; } From 06897d61dda11d2ffc88182ac6bf45bfaacfd12d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 20 Jan 2022 16:00:06 +0100 Subject: [PATCH 113/407] iio: adc: ad9208: Enable ad9680 support in the ad9208 device driver Enable ad9680 support in the ad9208 device driver, and remove it from the original ad9680 driver. With this transition we can fully support different JESD modes. Besides that this also gets us enhanced features such as DDC and NCO. After some further testing other older generation devices will be supported here as well. So that we can retire the ad9680 driver in the near future. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9208.c | 187 ++++++++++++++++++----- drivers/iio/adc/ad9208/AD9208.h | 8 + drivers/iio/adc/ad9208/ad9208_adc_api.c | 28 +++- drivers/iio/adc/ad9208/ad9208_api.c | 30 ++-- drivers/iio/adc/ad9208/ad9208_jesd_api.c | 31 ++-- drivers/iio/adc/ad9208/ad9208_reg.h | 5 + drivers/iio/adc/ad9680.c | 2 +- 7 files changed, 231 insertions(+), 60 deletions(-) diff --git a/drivers/iio/adc/ad9208.c b/drivers/iio/adc/ad9208.c index e85ab11543cb98..6240d91cefca34 100644 --- a/drivers/iio/adc/ad9208.c +++ b/drivers/iio/adc/ad9208.c @@ -2,7 +2,7 @@ /* * Driver for AD9208 and similar high-speed Analog-to-Digital converters * - * Copyright 2019-2020 Analog Devices Inc. + * Copyright 2019-2022 Analog Devices Inc. */ #include @@ -25,6 +25,7 @@ #include "cf_axi_adc.h" #include "ad9208/AD9208.h" #include "ad9208/ad9208_reg.h" +#include "ad9208/api_errors.h" #include @@ -32,6 +33,7 @@ #include #include +#define CHIPID_AD9680 0xC5 #define CHIPID_AD9208 0xDF #define CHIPID_AD6684 0xDC #define CHIPID_AD6688 0xE2 @@ -46,6 +48,7 @@ enum { ID_AD9208, ID_AD9208_X2, + ID_AD9680, }; enum { @@ -70,7 +73,6 @@ struct ad9208_phy { struct jesd204_dev *jdev; struct jesd204_link jesd204_link; jesd_param_t jesd_param; - u8 current_scale; bool dc_filter_enable; u32 ddc_cnt; u32 dcm; @@ -359,6 +361,11 @@ static const int ad9208_scale_table[][2] = { {1930, AD9208_ADC_SCALE_1P93_VPP}, {2040, AD9208_ADC_SCALE_2P04_VPP}, }; +static const int ad9680_scale_table[][2] = { + {1460, 0x08}, {1580, 0x09}, {1700, 0x0A}, {1820, 0x0B}, + {1940, 0x00}, {2060, 0x0C}, +}; + static void ad9208_scale(struct axiadc_converter *conv, int index, unsigned int *val, unsigned int *val2) { @@ -398,9 +405,19 @@ static int ad9208_get_scale(struct axiadc_converter *conv, int *val, int *val2) { struct ad9208_phy *phy = conv->phy; unsigned int i; + u8 scale_val; + int ret; + + if (phy->ad9208.model == 0x9208) + ret = ad9208_adc_get_input_scale(&phy->ad9208, &scale_val); + else + ret = ad9208_register_read(&phy->ad9208, + AD9680_INPUT_FS_RANGE_REG, &scale_val); + if (ret) + return ret; for (i = 0; i < conv->chip_info->num_scales; i++) { - if (phy->current_scale == conv->chip_info->scale_table[i][1]) + if (scale_val == conv->chip_info->scale_table[i][1]) break; } @@ -414,17 +431,22 @@ static int ad9208_set_scale(struct axiadc_converter *conv, int val, int val2) struct ad9208_phy *phy = conv->phy; unsigned int scale_val[2]; unsigned int i; + int ret; for (i = 0; i < conv->chip_info->num_scales; i++) { ad9208_scale(conv, i, &scale_val[0], &scale_val[1]); if (scale_val[0] != val || scale_val[1] != val2) continue; - ad9208_adc_set_input_scale(&phy->ad9208, - conv->chip_info->scale_table[i][1]); + if (phy->ad9208.model == 0x9208) + ret = ad9208_adc_set_input_scale(&phy->ad9208, + conv->chip_info->scale_table[i][1]); + else + ret = ad9208_register_write(&phy->ad9208, + AD9680_INPUT_FS_RANGE_REG, + conv->chip_info->scale_table[i][1]); - phy->current_scale = conv->chip_info->scale_table[i][1]; - return 0; + return ret; } return -EINVAL; @@ -548,6 +570,17 @@ static struct iio_chan_spec_ext_info axiadc_ext_info[] = { {}, }; +static struct iio_chan_spec_ext_info ad9680_ext_info[] = { + IIO_ENUM("test_mode", IIO_SEPARATE, &ad9208_testmode_enum), + IIO_ENUM_AVAILABLE("test_mode", &ad9208_testmode_enum), + { + .name = "scale_available", + .read = ad9208_show_scale_available, + .shared = true, + }, + {}, +}; + static const struct iio_event_spec ad9208_events[] = { { .type = IIO_EV_TYPE_THRESH, @@ -589,6 +622,24 @@ static const struct iio_event_spec ad9208_events[] = { }, \ } +#define AD9680_CHAN(_chan, _si, _bits, _sign, _shift, _ev, _nb_ev) \ + { .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _chan, \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .ext_info = ad9680_ext_info, \ + .scan_index = _si, \ + .scan_type = { \ + .sign = _sign, \ + .realbits = _bits, \ + .storagebits = 16, \ + .shift = _shift, \ + }, \ + .event_spec = _ev, \ + .num_event_specs = _nb_ev, \ + } + static struct axiadc_chip_info axiadc_chip_info_tbl[] = { [ID_AD9208] = { .name = "AD9208", @@ -646,6 +697,29 @@ static struct axiadc_chip_info axiadc_chip_info_tbl[] = { .channel[14] = AD9208_MC_CHAN(14, 14, 14, 'S', 0), .channel[15] = AD9208_MC_CHAN(15, 15, 14, 'S', 0), }, + [ID_AD9680] = { + .name = "AD9680", + .max_rate = 1250000000UL, + .scale_table = ad9680_scale_table, + .num_scales = ARRAY_SIZE(ad9680_scale_table), + .num_channels = 2, + .channel[0] = AD9680_CHAN(0, 0, 14, 'S', 0, + ad9208_events, ARRAY_SIZE(ad9208_events)), + .channel[1] = AD9680_CHAN(1, 1, 14, 'S', 0, + ad9208_events, ARRAY_SIZE(ad9208_events)), + .channel[2] = AD9680_CHAN(2, 2, 14, 'S', 0, + ad9208_events, ARRAY_SIZE(ad9208_events)), + .channel[3] = AD9680_CHAN(3, 3, 14, 'S', 0, + ad9208_events, ARRAY_SIZE(ad9208_events)), + .channel[4] = AD9680_CHAN(4, 4, 14, 'S', 0, + ad9208_events, ARRAY_SIZE(ad9208_events)), + .channel[5] = AD9680_CHAN(5, 5, 14, 'S', 0, + ad9208_events, ARRAY_SIZE(ad9208_events)), + .channel[6] = AD9680_CHAN(6, 6, 14, 'S', 0, + ad9208_events, ARRAY_SIZE(ad9208_events)), + .channel[7] = AD9680_CHAN(7, 7, 14, 'S', 0, + ad9208_events, ARRAY_SIZE(ad9208_events)), + }, }; static int ad9208_set_sample_rate(struct axiadc_converter *conv, @@ -685,7 +759,7 @@ static int ad9208_request_clks(struct axiadc_converter *conv) return 0; } -static int ad9208_setup(struct spi_device *spi, bool ad9234) +static int ad9208_setup(struct spi_device *spi) { struct axiadc_converter *conv = spi_get_drvdata(spi); struct ad9208_phy *phy = conv->phy; @@ -711,7 +785,7 @@ static int ad9208_setup(struct spi_device *spi, bool ad9234) ret = ad9208_set_input_clk_duty_cycle_stabilizer(&phy->ad9208, phy->duty_cycle_stabilizer_en); - if (ret < 0) { + if (ret < 0 && ret != API_ERROR_NOT_SUPPORTED) { dev_err(&spi->dev, "Failed to set clk duty cycle stabilizer (%d)\n", ret); return ret; @@ -742,25 +816,22 @@ static int ad9208_setup(struct spi_device *spi, bool ad9234) return ret; } - phy->current_scale = AD9208_ADC_SCALE_1P7_VPP; - ret = ad9208_adc_set_input_cfg(&phy->ad9208, phy->analog_input_mode ? COUPLING_DC : COUPLING_AC, - phy->ext_vref_en, phy->current_scale); - if (ret) { + phy->ext_vref_en, AD9208_ADC_SCALE_1P7_VPP); + if (ret < 0 && ret != API_ERROR_NOT_SUPPORTED) { dev_err(&spi->dev, "Failed to set adc input config: %d\n", ret); return ret; } ret = ad9208_adc_set_input_buffer_cfg(&phy->ad9208, phy->buff_curr_n, phy->buff_curr_p, AD9208_BUFF_CURR_600_UA); - if (ret) { + if (ret < 0 && ret != API_ERROR_NOT_SUPPORTED) { dev_err(&spi->dev, "Failed to set input buffer config: %d\n", ret); return ret; } - ret = ad9208_adc_set_fc_ch_mode(&phy->ad9208, phy->fc_ch); if (ret) { dev_err(&spi->dev, "Failed to set channel mode: %d\n", ret); @@ -884,7 +955,7 @@ static int ad9208_setup(struct spi_device *spi, bool ad9234) } } while (!(pll_stat & AD9208_JESD_PLL_LOCK_STAT) && timeout--); - dev_info(&conv->spi->dev, "AD9208 PLL %s\n", + dev_info(&conv->spi->dev, "%s PLL %s\n", spi_get_device_id(spi)->name, pll_stat & AD9208_JESD_PLL_LOCK_STAT ? "LOCKED" : "UNLOCKED"); if (!phy->jdev) { @@ -917,10 +988,11 @@ static int ad9208_status_show(struct seq_file *file, void *offset) const char *hold_setup_desc; u8 hold, setup, phase, stat; - ad9208_register_read(&phy->ad9208, AD9208_IP_CLK_STAT_REG, &stat); - seq_printf(file, "Input clock %sdetected\n", - (stat & 0x01) ? "" : "not "); - + if (phy->ad9208.model == 0x9208) { + ad9208_register_read(&phy->ad9208, AD9208_IP_CLK_STAT_REG, &stat); + seq_printf(file, "Input clock %sdetected\n", + (stat & 0x01) ? "" : "not "); + } ad9208_jesd_get_pll_status(&phy->ad9208, &stat); seq_printf(file, "JESD204 PLL is %slocked\n", (stat & AD9208_JESD_PLL_LOCK_STAT) ? "" : "not "); @@ -1091,7 +1163,7 @@ static int ad9208_parse_dt(struct ad9208_phy *phy, struct device *dev) phy->powerdown_pin_en = of_property_read_bool(np, "adi,powerdown-pin-enable"); - tmp = AD9208_POWERUP; + tmp = AD9208_POWERDOWN; of_property_read_u32(np, "adi,powerdown-mode", &tmp); phy->powerdown_mode = tmp; @@ -1345,6 +1417,29 @@ static const struct jesd204_dev_data jesd204_ad9208_init = { .sizeof_priv = sizeof(struct ad9208_jesd204_priv), }; +static int ad9680_sfdr_fixup(struct spi_device *spi) +{ + struct axiadc_converter *conv = spi_get_drvdata(spi); + struct ad9208_phy *phy = conv->phy; + static const u32 sfdr_optim_regs[] = { + 0x16, 0x18, 0x19, 0x1A, 0x30, 0x11A, 0x934, 0x935 + }; + u32 sfdr_optim_vals[ARRAY_SIZE(sfdr_optim_regs)]; + int ret, tmp; + + tmp = of_property_read_u32_array(spi->dev.of_node, + "adi,sfdr-optimization-config", + sfdr_optim_vals, ARRAY_SIZE(sfdr_optim_regs)); + + if (tmp == 0) { + for (; tmp < ARRAY_SIZE(sfdr_optim_regs); tmp++) + ret |= ad9208_register_write(&phy->ad9208, sfdr_optim_regs[tmp], + sfdr_optim_vals[tmp]); + } + + return ret; +} + static int ad9208_probe(struct spi_device *spi) { struct axiadc_converter *conv; @@ -1353,7 +1448,7 @@ static int ad9208_probe(struct spi_device *spi) struct ad9208_jesd204_priv *priv; adi_chip_id_t chip_id; u8 api_rev[3]; - u32 spi_id; + u32 spi_id, chan_id; int ret; jdev = devm_jesd204_dev_register(&spi->dev, &jesd204_ad9208_init); @@ -1428,18 +1523,39 @@ static int ad9208_probe(struct spi_device *spi) case CHIPID_AD9689: case CHIPID_AD9694: case CHIPID_AD9695: - ret = ad9208_setup_chip_info_tbl(phy, (spi_id & ID_DUAL) ? - ID_AD9208_X2 : ID_AD9208); - if (ret) - break; - conv->chip_info = &phy->chip_info; - ret = ad9208_setup(spi, false); + phy->ad9208.model = 0x9208; + phy->ad9208.input_clk_min_hz = 2500000000ULL; + phy->ad9208.input_clk_max_hz = 6000000000ULL; + phy->ad9208.adc_clk_min_hz = 2500000000ULL; + phy->ad9208.adc_clk_max_hz = 3100000000ULL; + phy->ad9208.slr_max_mbps = 16000; + phy->ad9208.slr_min_mbps = 390; + chan_id = (spi_id & ID_DUAL) ? ID_AD9208_X2 : ID_AD9208; + break; + case CHIPID_AD9680: + phy->ad9208.model = 0x9680; + phy->ad9208.input_clk_min_hz = 300000000ULL; + phy->ad9208.input_clk_max_hz = 4000000000ULL; + phy->ad9208.adc_clk_min_hz = 300000000ULL; + phy->ad9208.adc_clk_max_hz = 1250000000ULL; + phy->ad9208.slr_max_mbps = 12500; + phy->ad9208.slr_min_mbps = 3125; + + ad9680_sfdr_fixup(spi); + chan_id = ID_AD9680; break; default: dev_err(&spi->dev, "Unrecognized CHIP_ID 0x%X\n", conv->id); return -ENODEV; } + ret = ad9208_setup_chip_info_tbl(phy, chan_id); + if (ret) + return ret; + + conv->chip_info = &phy->chip_info; + + ret = ad9208_setup(spi); if (ret) { if (ret != -EPROBE_DEFER) dev_err(&spi->dev, "Failed to initialize: %d\n", ret); @@ -1457,18 +1573,16 @@ static int ad9208_probe(struct spi_device *spi) conv->post_iio_register = ad9208_post_iio_register; conv->set_pnsel = ad9208_set_pnsel; - if (conv->id == CHIPID_AD9208) { - ret = ad9208_request_fd_irqs(conv); - if (ret < 0) - dev_warn(&spi->dev, - "Failed to request FastDetect IRQs (%d)", ret); - } + ret = ad9208_request_fd_irqs(conv); + if (ret < 0) + dev_warn(&spi->dev, + "Failed to request FastDetect IRQs (%d)", ret); ad9208_get_revision(&phy->ad9208, &api_rev[0], &api_rev[1], &api_rev[2]); dev_info(&spi->dev, "%s Rev. %u Grade %u (API %u.%u.%u) probed\n", - conv->chip_info->name, chip_id.dev_revision, + spi_get_device_id(spi)->name, chip_id.dev_revision, chip_id.prod_grade, api_rev[0], api_rev[1], api_rev[2]); return jesd204_fsm_start(jdev, JESD204_LINKS_ALL); @@ -1486,7 +1600,6 @@ static int ad9208_remove(struct spi_device *spi) clk_disable_unprepare(conv->lane_clk); - ad9208_deinit(&phy->ad9208); return 0; @@ -1501,6 +1614,7 @@ static const struct spi_device_id ad9208_id[] = { { "ad9694", CHIPID_AD9694 }, { "ad9695", CHIPID_AD9695 }, { "ad9697", CHIPID_AD9697 }, + { "ad9680", CHIPID_AD9680 }, {} }; MODULE_DEVICE_TABLE(spi, ad9208_id); @@ -1514,6 +1628,7 @@ static const struct of_device_id ad9208_of_match[] = { { .compatible = "adi,ad9694" }, { .compatible = "adi,ad9695" }, { .compatible = "adi,ad9697" }, + { .compatible = "adi,ad9680" }, { }, }; MODULE_DEVICE_TABLE(of, ad9208_of_match); diff --git a/drivers/iio/adc/ad9208/AD9208.h b/drivers/iio/adc/ad9208/AD9208.h index d7ea4eaccfc2e6..b11d5e4a410c15 100644 --- a/drivers/iio/adc/ad9208/AD9208.h +++ b/drivers/iio/adc/ad9208/AD9208.h @@ -85,6 +85,14 @@ typedef struct { hw_open_t hw_open; /**< Function Pointer to HAL initialization function*/ hw_close_t hw_close; /**< Function Pointer to HAL de-initialization function*/ uint64_t adc_clk_freq_hz; /**< ADC Clock Frequency in Hz. Valid range 2.5GHz to 3.1 GHz */ + + uint64_t input_clk_min_hz; + uint64_t input_clk_max_hz; + uint64_t adc_clk_min_hz; + uint64_t adc_clk_max_hz; + uint32_t slr_max_mbps; + uint32_t slr_min_mbps; + uint32_t model; } ad9208_handle_t; /** diff --git a/drivers/iio/adc/ad9208/ad9208_adc_api.c b/drivers/iio/adc/ad9208/ad9208_adc_api.c index 1d00d2a7ae2a06..d10477c2cd347e 100644 --- a/drivers/iio/adc/ad9208/ad9208_adc_api.c +++ b/drivers/iio/adc/ad9208/ad9208_adc_api.c @@ -226,6 +226,9 @@ int ad9208_adc_set_input_scale(ad9208_handle_t *h, if (h == NULL) return API_ERROR_INVALID_HANDLE_PTR; + if (h->model == 0x9680) /* N/A */ + return API_ERROR_NOT_SUPPORTED; + switch (full_scale_range) { case AD9208_ADC_SCALE_2P04_VPP: fs_val = 0; @@ -310,6 +313,9 @@ static int ad9208_adc_set_vcm_export(ad9208_handle_t *h, uint8_t en) if (h == NULL) return API_ERROR_INVALID_HANDLE_PTR; + if (h->model == 0x9680) /* N/A */ + return API_ERROR_NOT_SUPPORTED; + err = ad9208_register_read(h, AD9208_EXT_VCM_CTRL_REG, &tmp_reg); if (err != API_ERROR_OK) return err; @@ -334,6 +340,10 @@ int ad9208_adc_set_input_cfg(ad9208_handle_t *h, if (h == NULL) return API_ERROR_INVALID_HANDLE_PTR; + + if (h->model == 0x9680) /* N/A */ + return API_ERROR_NOT_SUPPORTED; + if ((analog_input_mode >= COUPLING_UNKNOWN) || (ext_vref > 1)) return API_ERROR_INVALID_PARAM; if ((analog_input_mode == COUPLING_DC) && (ext_vref == 1)) { @@ -386,6 +396,10 @@ int ad9208_adc_set_input_buffer_cfg(ad9208_handle_t *h, if (h == NULL) return API_ERROR_INVALID_HANDLE_PTR; + + if (h->model == 0x9680) /* N/A */ + return API_ERROR_NOT_SUPPORTED; + err = ad9208_check_buffer_current(buff_curr_n); if (err != API_ERROR_OK) return err; @@ -430,6 +444,9 @@ int ad9208_adc_set_dc_offset_filt_en(ad9208_handle_t *h, uint8_t en) if (en > 1) return API_ERROR_INVALID_PARAM; + if (h->model == 0x9680) /* N/A */ + return API_ERROR_NOT_SUPPORTED; + err = ad9208_register_read(h, AD9208_DC_OFFSET_CAL_CTRL, &tmp_reg); if (err != API_ERROR_OK) return err; @@ -941,13 +958,19 @@ int ad9208_adc_set_ddc_nco_reset(ad9208_handle_t *h) int ad9208_adc_set_clk_phase(ad9208_handle_t *h, uint8_t phase_adj) { int err; + uint16_t addr; if (h == NULL) return API_ERROR_INVALID_HANDLE_PTR; if (phase_adj > AD9208_IP_CLK_PHASE_ADJ(ALL)) return API_ERROR_INVALID_PARAM; - err = ad9208_register_write(h, AD9208_IP_CLK_PHASE_ADJ_REG, phase_adj); + if (h->model == 0x9680) + addr = AD9680_CLOCK_DIV_PHASE_REG; + else + addr = AD9208_IP_CLK_PHASE_ADJ_REG; + + err = ad9208_register_write(h, addr, phase_adj); if (err != API_ERROR_OK) return err; @@ -964,6 +987,9 @@ int ad9208_adc_temp_sensor_set_enable(ad9208_handle_t *h, uint8_t en) if (en > 1) return API_ERROR_INVALID_PARAM; + if (h->model == 0x9680) /* N/A */ + return API_ERROR_NOT_SUPPORTED; + err = ad9208_adc_set_vcm_export(h, 0x0); if (err != API_ERROR_OK) return err; diff --git a/drivers/iio/adc/ad9208/ad9208_api.c b/drivers/iio/adc/ad9208/ad9208_api.c index 41b4fb2f80e983..68eee2084eeadc 100644 --- a/drivers/iio/adc/ad9208/ad9208_api.c +++ b/drivers/iio/adc/ad9208/ad9208_api.c @@ -270,26 +270,31 @@ int ad9208_set_input_clk_cfg(ad9208_handle_t *h, uint64_t clk_freq_hz, if (h == NULL) return API_ERROR_INVALID_HANDLE_PTR; - if ((clk_freq_hz > AD9208_IP_CLK_MAX_HZ) || - (clk_freq_hz < AD9208_IP_CLK_MIN_HZ)) + if (clk_freq_hz > h->input_clk_max_hz || clk_freq_hz < h->input_clk_min_hz) return API_ERROR_INVALID_PARAM; if ((div != 1) && (div != 2) && (div != 4)) return API_ERROR_INVALID_PARAM; fs_hz = DIV_U64(clk_freq_hz, div); - if ((fs_hz > AD9208_ADC_CLK_MAX_HZ) || (fs_hz < AD9208_ADC_CLK_MIN_HZ)) + if (fs_hz > h->adc_clk_max_hz || fs_hz < h->adc_clk_min_hz) return API_ERROR_INVALID_PARAM; - err = ad9208_register_read(h, AD9208_IP_CLK_CFG_REG, &tmp_reg); - if (err != API_ERROR_OK) - return err; + if (h->model == 0x9680) { + err = ad9208_register_write(h, AD9680_CLOCK_DIV_REG, div - 1); + if (err != API_ERROR_OK) + return err; + } else { + err = ad9208_register_read(h, AD9208_IP_CLK_CFG_REG, &tmp_reg); + if (err != API_ERROR_OK) + return err; - tmp_reg &= ~AD9208_IP_CLK_DIV(ALL); - tmp_reg |= AD9208_IP_CLK_DIV(div - 1); - err = ad9208_register_write(h, AD9208_IP_CLK_CFG_REG, tmp_reg); - if (err != API_ERROR_OK) - return err; + tmp_reg &= ~AD9208_IP_CLK_DIV(ALL); + tmp_reg |= AD9208_IP_CLK_DIV(div - 1); + err = ad9208_register_write(h, AD9208_IP_CLK_CFG_REG, tmp_reg); + if (err != API_ERROR_OK) + return err; + } h->adc_clk_freq_hz = fs_hz; return API_ERROR_OK; @@ -316,6 +321,9 @@ int ad9208_set_input_clk_duty_cycle_stabilizer(ad9208_handle_t *h, uint8_t en) if (en > 1) return API_ERROR_INVALID_PARAM; + if (h->model == 0x9680) /* N/A */ + return API_ERROR_NOT_SUPPORTED; + tmp_reg_addr = AD9208_IP_CLK_DCS1_REG; err = ad9208_register_write(h, tmp_reg_addr, en); if (err != API_ERROR_OK) diff --git a/drivers/iio/adc/ad9208/ad9208_jesd_api.c b/drivers/iio/adc/ad9208/ad9208_jesd_api.c index 40a07582b318a6..dd4906206eadeb 100644 --- a/drivers/iio/adc/ad9208/ad9208_jesd_api.c +++ b/drivers/iio/adc/ad9208/ad9208_jesd_api.c @@ -144,7 +144,7 @@ int ad9208_jesd_enable_link(ad9208_handle_t *h, uint8_t en) err = ad9208_register_read(h, AD9208_JESD_LINK_CTRL1_REG, &tmp_reg); if (err != API_ERROR_OK) return err; - if (en) { + if (en && h->model != 0x9680) { err = ad9208_register_write_tbl(h, &ADI_REC_SERDES_INIT_TBL[0], ARRAY_SIZE @@ -184,7 +184,7 @@ int ad9208_jesd_set_if_config(ad9208_handle_t *h, if (h->adc_clk_freq_hz != 0) fout = DIV_U64(h->adc_clk_freq_hz, dcm); else { - /*printf("API:AD9208: JESD :INVALID: CLK FREQ \r\n"); */ + pr_err("API:AD9208: JESD :INVALID: CLK FREQ\n"); return API_ERROR_INVALID_PARAM; } /*Calculate Lane Rate */ @@ -192,15 +192,23 @@ int ad9208_jesd_set_if_config(ad9208_handle_t *h, slr = DIV_U64(DIV_U64(slr, 8), jesd_param.jesd_L); slr_mbps = DIV_U64(slr, 1000000); - if ((slr_mbps > LANE_RATE_MAX_MBPS) || (slr_mbps < LANE_RATE_MIN_MBPS)) { - /*printf("API:AD9208: JESD :INVALID: SLR :%lld \r\n", slr_mbps); */ + if (slr_mbps > h->slr_max_mbps || slr_mbps < h->slr_min_mbps) { + pr_err("API:AD9208: JESD :INVALID: SLR :%lld\n", slr_mbps); return API_ERROR_INVALID_PARAM; } /*CFG SERDES PLL for SLR */ - err = get_jesd_serdes_vco_cfg(slr_mbps, &vco_cfg); + if (h->model == 0x9680) { + if (slr_mbps < 6250) + err = ad9208_register_write(h, 0x56e, 0x10); + else + err = ad9208_register_write(h, 0x56e, 0x00); + } else { + err = get_jesd_serdes_vco_cfg(slr_mbps, &vco_cfg); + } if (err != API_ERROR_OK) return err; + err = ad9208_register_read(h, AD9208_JESD_SERDES_PLL_CFG_REG, &tmp_reg); if (err != API_ERROR_OK) return err; @@ -535,12 +543,13 @@ int ad9208_jesd_syref_config_set(ad9208_handle_t *h, err = ad9208_register_write(h, AD9208_SYSREF_CTRL_0_REG, tmp_reg); if (err != API_ERROR_OK) return err; - - tmp_reg = AD9208_SYSREF_WIN_NEG(neg_window_skew) | - AD9208_SYSREF_WIN_POS(pos_window_skew); - err = ad9208_register_write(h, AD9208_SYSREF_CTRL_2_REG, tmp_reg); - if (err != API_ERROR_OK) - return err; + if (h->model != 0x9680) { + tmp_reg = AD9208_SYSREF_WIN_NEG(neg_window_skew) | + AD9208_SYSREF_WIN_POS(pos_window_skew); + err = ad9208_register_write(h, AD9208_SYSREF_CTRL_2_REG, tmp_reg); + if (err != API_ERROR_OK) + return err; + } return API_ERROR_OK; } diff --git a/drivers/iio/adc/ad9208/ad9208_reg.h b/drivers/iio/adc/ad9208/ad9208_reg.h index b2ecf4969fc0ca..0a867597e24366 100644 --- a/drivers/iio/adc/ad9208/ad9208_reg.h +++ b/drivers/iio/adc/ad9208/ad9208_reg.h @@ -264,4 +264,9 @@ int ad9208_is_sync_spi_update_enabled(ad9208_handle_t *h, uint8_t *enabled); #define AD9208_FULL_SCALE_CFG_REG 0x1910 #define AD9208_TRM_VREF(x) (((x)&0xF)<<0) +/* AD9680 Registers */ +#define AD9680_CLOCK_DIV_REG 0x10B +#define AD9680_CLOCK_DIV_PHASE_REG 0x10C +#define AD9680_INPUT_FS_RANGE_REG 0x025 + #endif /*__AD9208_REG_H__*/ diff --git a/drivers/iio/adc/ad9680.c b/drivers/iio/adc/ad9680.c index 6148e579f508fa..7a449951f7cd94 100644 --- a/drivers/iio/adc/ad9680.c +++ b/drivers/iio/adc/ad9680.c @@ -1569,7 +1569,7 @@ static int ad9680_remove(struct spi_device *spi) } static const struct spi_device_id ad9680_id[] = { - { "ad9680", CHIPID_AD9680 }, +/* { "ad9680", CHIPID_AD9680 }, Now handled in the ad9208 device driver */ { "ad9234", CHIPID_AD9234 }, { "ad9684", CHIPID_AD9684 }, { "ad9694", CHIPID_AD9694 }, From 55365d8c5cf396901f2bc9114530311a84ef979d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 20 Jan 2022 17:29:32 +0100 Subject: [PATCH 114/407] arm64: dts: AD-FMCDAQ2-EBZ & AD-FMCDAQ3-EBZ switch to jesd204-fsm This patch enables jesd204-fsm support for the AD-FMCDAQ2-EBZ and AD-FMCDAQ3-EBZ projects. There is a bit more noise in this commit, since we try to unify the dtsi and dts across different architectures. We also add missing comment headers, update the copyright and remove come dead or commented code. Signed-off-by: Michael Hennerich --- arch/arm64/boot/dts/xilinx/adi-daq2.dtsi | 117 +++++++++++++++--- arch/arm64/boot/dts/xilinx/adi-daq3.dtsi | 106 +++++++++++++++- .../xilinx/zynqmp-zcu102-rev10-fmcdaq2.dts | 43 +++++-- .../xilinx/zynqmp-zcu102-rev10-fmcdaq3.dts | 44 +++++-- 4 files changed, 261 insertions(+), 49 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/adi-daq2.dtsi b/arch/arm64/boot/dts/xilinx/adi-daq2.dtsi index 3fed92d7e6ca5a..03d0016ce72265 100644 --- a/arch/arm64/boot/dts/xilinx/adi-daq2.dtsi +++ b/arch/arm64/boot/dts/xilinx/adi-daq2.dtsi @@ -1,20 +1,29 @@ -/ { - clocks { - - }; -}; +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCDAQ2-EBZ + * Link: https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq2-ebz + * + * board_revision: + * + * Copyright 2016-2022 Analog Devices Inc. + */ +#include &fmc_spi { clk0_ad9523: ad9523-1@0 { + #address-cells = <1>; + #size-cells = <0>; compatible = "adi,ad9523-1"; reg = <0>; spi-max-frequency = <10000000>; - #address-cells = <1>; - #size-cells = <0>; - - clock-output-names = "ad9523-1_out0", "ad9523-1_out1", "ad9523-1_out2", "ad9523-1_out3", "ad9523-1_out4", "ad9523-1_out5", "ad9523-1_out6", "ad9523-1_out7", "ad9523-1_out8", "ad9523-1_out9", "ad9523-1_out10", "ad9523-1_out11", "ad9523-1_out12", "ad9523-1_out13"; + clock-output-names = + "ad9523-1_out0", "ad9523-1_out1", "ad9523-1_out2", + "ad9523-1_out3", "ad9523-1_out4", "ad9523-1_out5", + "ad9523-1_out6", "ad9523-1_out7", "ad9523-1_out8", + "ad9523-1_out9", "ad9523-1_out10", "ad9523-1_out11", + "ad9523-1_out12", "ad9523-1_out13"; #clock-cells = <1>; adi,vcxo-freq = <125000000>; @@ -48,15 +57,14 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <1>; -// adi,output-dis; }; + ad9523_0_c4:channel@4 { reg = <4>; adi,extended-name = "ADC_CLK_FMC"; adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <2>; -// adi,output-dis; }; ad9523_0_c5:channel@5 { @@ -65,7 +73,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c6:channel@6 { @@ -74,7 +81,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c7:channel@7 { @@ -83,7 +89,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c8:channel@8 { @@ -92,7 +97,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c9:channel@9 { @@ -101,7 +105,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <2>; -// adi,output-dis; }; ad9523_0_c13:channel@13 { @@ -110,21 +113,55 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <1>; -// adi,output-dis; }; }; dac0_ad9144: ad9144@1 { + #address-cells = <1>; + #size-cells = <0>; compatible = "adi,ad9144"; reg = <1>; spi-max-frequency = <1000000>; - clocks = <&axi_ad9144_jesd>, <&clk0_ad9523 1>, <&clk0_ad9523 8>; - clock-names = "jesd_dac_clk", "dac_clk", "dac_sysref"; + clocks = <&clk0_ad9523 1>; + clock-names = "dac_clk"; + + /* + * | MODE | M | L | S | F | HD | N | N' | + * | 00 | 4 | 8 | 1 | 1 | 1 | 16 | 16 | + * | 01 | 4 | 8 | 2 | 2 | 0 | 16 | 16 | + * | 02 | 4 | 4 | 1 | 2 | 0 | 16 | 16 | + * | 03 | 4 | 2 | 1 | 4 | 0 | 16 | 16 | + * | 04 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 05 | 2 | 4 | 2 | 2 | 0 | 16 | 16 | + * | 06 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + * | 07 | 2 | 1 | 1 | 4 | 0 | 16 | 16 | + * | 08 | 1 | 4 | 2 | 1 | 1 | 16 | 16 | + * | 09 | 1 | 2 | 1 | 1 | 1 | 16 | 16 | + * | 10 | 1 | 1 | 1 | 2 | 0 | 16 | 16 | + * | 11 | 2 | 8 | 2 | 1 | 1 | 16 | 16 | + * | 12 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 13 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + */ + + adi,jesd-link-mode = <4>; + adi,sysref-mode = <1>; /* JESD204_SYSREF_CONTINUOUS */ + adi,subclass = <1>; + adi,interpolation = <1>; + adi,frequency-center-shift = <0>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <1>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9144_core 1 0>; }; adc0_ad9680: ad9680@2 { + #address-cells = <1>; + #size-cells = <0>; compatible = "adi,ad9680"; reg = <2>; @@ -132,6 +169,46 @@ clocks = <&axi_ad9680_jesd>, <&clk0_ad9523 13>, <&clk0_ad9523 5>; clock-names = "jesd_adc_clk", "adc_clk", "adc_sysref"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <0>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9680_core 0 0>; + + adi,powerdown-mode = ; + + adi,sampling-frequency = /bits/ 64 <1000000000>; + adi,input-clock-divider-ratio = <1>; + + adi,sysref-lmfc-offset = <0>; + adi,sysref-pos-window-skew = <0>; + adi,sysref-neg-window-skew = <0>; + adi,sysref-mode = ; + adi,sysref-nshot-ignore-count = <0>; + + /* JESD204 parameters */ + + adi,converters-per-device = <2>; /* JESD204 (M) */ + adi,lanes-per-device = <4>; /* JESD204 (L) */ + adi,octets-per-frame = <1>; /* JESD204 (F) */ + adi,frames-per-multiframe = <32>; /* JESD204 (K) */ + adi,converter-resolution = <14>; /* JESD204 (N) */ + adi,bits-per-sample = <16>; /* JESD204 (N') */ + adi,control-bits-per-sample = <2>; /* JESD204 (CS) */ + adi,subclass = <1>; /* JESD204 (SUBCLASSV) */ + + /* DDC setup */ + + adi,ddc-channel-number = ; + + ad9208_ddc0: channel@0 { + reg = <0>; + adi,decimation = <2>; + adi,nco-mode-select = ; + adi,nco-channel-carrier-frequency-hz = /bits/ 64 <70000000>; + adi,nco-channel-phase-offset = /bits/ 64 <0>; + }; }; }; - diff --git a/arch/arm64/boot/dts/xilinx/adi-daq3.dtsi b/arch/arm64/boot/dts/xilinx/adi-daq3.dtsi index cf9bb70220167c..9b3c54e54c18f4 100644 --- a/arch/arm64/boot/dts/xilinx/adi-daq3.dtsi +++ b/arch/arm64/boot/dts/xilinx/adi-daq3.dtsi @@ -1,10 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCDAQ3-EBZ + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq3-ebz + * + * board_revision: + * + * Copyright (C) 2015-2022 Analog Devices Inc. + */ #include +#include &fmc_spi { clk0_ad9528: ad9528@0 { #address-cells = <1>; #size-cells = <0>; - #clock-cells = <1>; compatible = "adi,ad9528"; spi-cpol; @@ -14,8 +23,14 @@ reg = <0>; clock-output-names = "ad9528_out0", "ad9528_out1", "ad9528_out2", "ad9528_out3", "ad9528_out4", "ad9528_out5", "ad9528_out6", "ad9528_out7", "ad9528_out8", "ad9528_out9", "ad9528_out10", "ad9528_out11", "ad9528_out12", "ad9528_out13"; + #clock-cells = <1>; + adi,vcxo-freq = <100000000>; + jesd204-device; + #jesd204-cells = <2>; + jesd204-sysref-provider; + /* PLL1 config */ adi,pll1-bypass-enable; adi,osc-in-diff-enable; @@ -33,6 +48,7 @@ /* SYSREF config */ adi,sysref-src = ; adi,sysref-k-div = <128>; + adi,sysref-pattern-mode = ; adi,rpole2 = ; adi,rzero = ; @@ -63,6 +79,7 @@ adi,divider-phase = <0>; adi,channel-divider = <1>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c6: channel@6 { @@ -72,6 +89,7 @@ adi,divider-phase = <0>; adi,channel-divider = <2>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c7: channel@7 { @@ -81,6 +99,7 @@ adi,divider-phase = <0>; adi,channel-divider = <2>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c8: channel@8 { @@ -90,6 +109,7 @@ adi,divider-phase = <0>; adi,channel-divider = <1>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c9: channel@9 { @@ -112,6 +132,8 @@ }; dac0_ad9152: ad9152@1 { + #address-cells = <1>; + #size-cells = <0>; compatible = "adi,ad9152"; spi-cpol; @@ -120,11 +142,44 @@ adi,spi-3wire-enable; reg = <1>; - clocks = <&axi_ad9152_jesd>, <&clk0_ad9528 2>, <&clk0_ad9528 5>; - clock-names = "jesd_dac_clk", "dac_clk", "dac_sysref"; + clocks = <&clk0_ad9528 2>; + clock-names = "dac_clk"; + + /* + * | MODE | M | L | S | F | HD | N | N' | + * | 00 | 4 | 8 | 1 | 1 | 1 | 16 | 16 | + * | 01 | 4 | 8 | 2 | 2 | 0 | 16 | 16 | + * | 02 | 4 | 4 | 1 | 2 | 0 | 16 | 16 | + * | 03 | 4 | 2 | 1 | 4 | 0 | 16 | 16 | + * | 04 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 05 | 2 | 4 | 2 | 2 | 0 | 16 | 16 | + * | 06 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + * | 07 | 2 | 1 | 1 | 4 | 0 | 16 | 16 | + * | 08 | 1 | 4 | 2 | 1 | 1 | 16 | 16 | + * | 09 | 1 | 2 | 1 | 1 | 1 | 16 | 16 | + * | 10 | 1 | 1 | 1 | 2 | 0 | 16 | 16 | + * | 11 | 2 | 8 | 2 | 1 | 1 | 16 | 16 | + * | 12 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 13 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + */ + + adi,jesd-link-mode = <4>; + adi,sysref-mode = <1>; /* JESD204_SYSREF_CONTINUOUS */ + adi,subclass = <1>; + adi,interpolation = <1>; + adi,frequency-center-shift = <0>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <1>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9152_core 1 0>; }; adc0_ad9680: ad9680@2 { + #address-cells = <1>; + #size-cells = <0>; compatible = "adi,ad9680"; spi-cpol; @@ -136,7 +191,48 @@ /* Content of Registers: 0x16, 0x18, 0x19, 0x1A, 0x30, 0x11A, 0x934, 0x935 */ adi,sfdr-optimization-config = <0xE 0xA0 0x50 0x09 0x18 0x00 0x1F 0x04>; - clocks = <&axi_ad9680_jesd>, <&clk0_ad9528 13>, <&clk0_ad9528 8>; - clock-names = "jesd_adc_clk", "adc_clk", "adc_sysref"; + clocks = <&clk0_ad9528 13>; + clock-names = "adc_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <0>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9680_core 0 0>; + + adi,powerdown-mode = ; + + adi,sampling-frequency = /bits/ 64 <1233333333>; + adi,input-clock-divider-ratio = <1>; + + adi,sysref-lmfc-offset = <0>; + adi,sysref-pos-window-skew = <0>; + adi,sysref-neg-window-skew = <0>; + adi,sysref-mode = ; + adi,sysref-nshot-ignore-count = <0>; + + /* JESD204 parameters */ + + adi,converters-per-device = <2>; /* JESD204 (M) */ + adi,lanes-per-device = <4>; /* JESD204 (L) */ + adi,octets-per-frame = <1>; /* JESD204 (F) */ + adi,frames-per-multiframe = <32>; /* JESD204 (K) */ + adi,converter-resolution = <14>; /* JESD204 (N) */ + adi,bits-per-sample = <16>; /* JESD204 (N') */ + adi,control-bits-per-sample = <2>; /* JESD204 (CS) */ + adi,subclass = <1>; /* JESD204 (SUBCLASSV) */ + + /* DDC setup */ + + adi,ddc-channel-number = ; + + ad9208_ddc0: channel@0 { + reg = <0>; + adi,decimation = <2>; + adi,nco-mode-select = ; + adi,nco-channel-carrier-frequency-hz = /bits/ 64 <70000000>; + adi,nco-channel-phase-offset = /bits/ 64 <0>; + }; }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq2.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq2.dts index c44b3b86b1643f..84f7a93c681983 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq2.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq2.dts @@ -6,7 +6,7 @@ * hdl_project: * board_revision: <> * - * Copyright 2016-2020 Analog Devices Inc. + * Copyright 2016-2022 Analog Devices Inc. */ #include "zynqmp-zcu102-rev1.0.dts" @@ -93,6 +93,11 @@ dma-names = "tx"; spibus-connected = <&dac0_ad9144>; adi,axi-pl-fifo-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_jesd 1 0>; }; axi_ad9144_jesd: axi-jesd204-tx@84a90000 { @@ -104,14 +109,13 @@ clocks = <&zynqmp_clk 71>, <&axi_ad9144_adxcvr 1>, <&axi_ad9144_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <2>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_adxcvr 1 0>; }; axi_ad9680_core: axi-ad9680-hpc@84a10000 { @@ -120,6 +124,11 @@ dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&adc0_ad9680>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_jesd 0 0>; }; axi_ad9680_jesd: axi-jesd204-rx@84aa0000 { @@ -131,11 +140,13 @@ clocks = <&zynqmp_clk 71>, <&axi_ad9680_adxcvr 1>, <&axi_ad9680_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - #clock-cells = <0>; clock-output-names = "jesd_adc_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_adxcvr 0 0>; }; axi_ad9680_adxcvr: axi-adxcvr-rx@84a50000{ @@ -149,8 +160,12 @@ clock-output-names = "adc_gt_clk", "rx_out_clk"; adi,sys-clk-select = ; - adi,out-clk-select = ; + adi,out-clk-select = ; adi,use-lpm-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; axi_ad9144_adxcvr: axi-adxcvr-tx@84a60000{ @@ -164,8 +179,12 @@ clock-output-names = "dac_gt_clk", "tx_out_clk"; adi,sys-clk-select = ; - adi,out-clk-select = ; + adi,out-clk-select = ; adi,use-lpm-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; axi_sysid_0: axi-sysid-0@85000000 { diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq3.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq3.dts index 847f5feedbe222..a65087598898eb 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq3.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq3.dts @@ -6,7 +6,7 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2015-2019 Analog Devices Inc. + * Copyright (C) 2015-2022 Analog Devices Inc. */ #include "zynqmp-zcu102-rev1.0.dts" @@ -90,6 +90,11 @@ dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&adc0_ad9680>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_jesd 0 0>; }; axi_ad9152_core: axi-ad9152-hpc@84a04000 { @@ -99,6 +104,11 @@ dma-names = "tx"; spibus-connected = <&dac0_ad9152>; adi,axi-pl-fifo-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9152_jesd 1 0>; }; axi_ad9680_jesd: axi-jesd204-rx@84aa0000 { @@ -109,11 +119,13 @@ clocks = <&zynqmp_clk 71>, <&axi_ad9680_adxcvr 1>, <&axi_ad9680_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - #clock-cells = <0>; clock-output-names = "jesd_adc_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_adxcvr 0 0>; }; axi_ad9680_adxcvr: axi-adxcvr-rx@84a50000 { @@ -124,11 +136,16 @@ clock-names = "conv"; adi,sys-clk-select = ; - adi,out-clk-select = ; + adi,out-clk-select = ; adi,use-lpm-enable; #clock-cells = <1>; clock-output-names = "adc_gt_clk", "rx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&clk0_ad9528 0 0>; }; axi_ad9152_jesd: axi-jesd204-tx@84a90000 { @@ -140,14 +157,13 @@ clocks = <&zynqmp_clk 71>, <&axi_ad9152_adxcvr 1>, <&axi_ad9152_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <2>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9152_adxcvr 1 0>; }; axi_ad9152_adxcvr: axi-adxcvr-tx@84a60000 { @@ -158,11 +174,15 @@ clock-names = "conv"; adi,sys-clk-select = ; - adi,out-clk-select = ; + adi,out-clk-select = ; adi,use-lpm-enable; #clock-cells = <1>; clock-output-names = "dac_gt_clk", "tx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; axi_sysid_0: axi-sysid-0@85000000 { From 13a3776ba0eb047da1e650aeb679b0a6fa682e7c Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 21 Jan 2022 11:16:38 +0100 Subject: [PATCH 115/407] arm: dts: AD-FMCDAQ2-EBZ & AD-FMCDAQ3-EBZ switch to jesd204-fsm This patch enables jesd204-fsm support for the AD-FMCDAQ2-EBZ and AD-FMCDAQ3-EBZ projects. There is a bit more noise in this commit, since we try to unify the dtsi and dts across different architectures. We also add missing comment headers, update the copyright and remove come dead or commented code. Signed-off-by: Michael Hennerich --- arch/arm/boot/dts/adi-daq2.dtsi | 123 +++++++++++--- arch/arm/boot/dts/adi-daq3.dtsi | 156 ++++++++++++++---- .../boot/dts/socfpga_arria10_socdk_daq2.dts | 42 +++-- .../boot/dts/zynq-zc706-adv7511-fmcdaq2.dts | 36 +++- .../dts/zynq-zc706-adv7511-fmcdaq3-revC.dts | 111 +------------ .../boot/dts/zynq-zc706-adv7511-fmcdaq3.dts | 51 ++++-- 6 files changed, 319 insertions(+), 200 deletions(-) diff --git a/arch/arm/boot/dts/adi-daq2.dtsi b/arch/arm/boot/dts/adi-daq2.dtsi index d4aafaf50abdea..ed224f3d259f0d 100644 --- a/arch/arm/boot/dts/adi-daq2.dtsi +++ b/arch/arm/boot/dts/adi-daq2.dtsi @@ -1,20 +1,31 @@ -/ { - clocks { - - }; -}; +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCDAQ2-EBZ + * Link: https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq2-ebz + * + * board_revision: + * + * Copyright 2014-2022 Analog Devices Inc. + */ +#include &fmc_spi { clk0_ad9523: ad9523-1@0 { + #address-cells = <1>; + #size-cells = <0>; compatible = "adi,ad9523-1"; reg = <0>; + spi-max-frequency = <10000000>; + + clock-output-names = + "ad9523-1_out0", "ad9523-1_out1", "ad9523-1_out2", + "ad9523-1_out3", "ad9523-1_out4", "ad9523-1_out5", + "ad9523-1_out6", "ad9523-1_out7", "ad9523-1_out8", + "ad9523-1_out9", "ad9523-1_out10", "ad9523-1_out11", + "ad9523-1_out12", "ad9523-1_out13"; #clock-cells = <1>; - #address-cells = <1>; - #size-cells = <0>; - spi-max-frequency = <10000000>; - clock-output-names = "ad9523-1_out0", "ad9523-1_out1", "ad9523-1_out2", "ad9523-1_out3", "ad9523-1_out4", "ad9523-1_out5", "ad9523-1_out6", "ad9523-1_out7", "ad9523-1_out8", "ad9523-1_out9", "ad9523-1_out10", "ad9523-1_out11", "ad9523-1_out12", "ad9523-1_out13"; adi,vcxo-freq = <125000000>; adi,spi-3wire-enable; adi,pll1-bypass-enable; @@ -46,15 +57,14 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <1>; -// adi,output-dis; }; + ad9523_0_c4:channel@4 { reg = <4>; adi,extended-name = "ADC_CLK_FMC"; adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <2>; -// adi,output-dis; }; ad9523_0_c5:channel@5 { @@ -63,7 +73,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c6:channel@6 { @@ -72,7 +81,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c7:channel@7 { @@ -81,7 +89,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c8:channel@8 { @@ -90,7 +97,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c9:channel@9 { @@ -99,7 +105,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <2>; -// adi,output-dis; }; ad9523_0_c13:channel@13 { @@ -108,28 +113,102 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <1>; -// adi,output-dis; }; }; dac0_ad9144: ad9144@1 { + #address-cells = <1>; + #size-cells = <0>; compatible = "adi,ad9144"; reg = <1>; spi-max-frequency = <1000000>; - clocks = <&axi_ad9144_jesd>, <&clk0_ad9523 1>, <&clk0_ad9523 8>; - clock-names = "jesd_dac_clk", "dac_clk", "dac_sysref"; + clocks = <&clk0_ad9523 1>; + clock-names = "dac_clk"; + + /* + * | MODE | M | L | S | F | HD | N | N' | + * | 00 | 4 | 8 | 1 | 1 | 1 | 16 | 16 | + * | 01 | 4 | 8 | 2 | 2 | 0 | 16 | 16 | + * | 02 | 4 | 4 | 1 | 2 | 0 | 16 | 16 | + * | 03 | 4 | 2 | 1 | 4 | 0 | 16 | 16 | + * | 04 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 05 | 2 | 4 | 2 | 2 | 0 | 16 | 16 | + * | 06 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + * | 07 | 2 | 1 | 1 | 4 | 0 | 16 | 16 | + * | 08 | 1 | 4 | 2 | 1 | 1 | 16 | 16 | + * | 09 | 1 | 2 | 1 | 1 | 1 | 16 | 16 | + * | 10 | 1 | 1 | 1 | 2 | 0 | 16 | 16 | + * | 11 | 2 | 8 | 2 | 1 | 1 | 16 | 16 | + * | 12 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 13 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + */ + + adi,jesd-link-mode = <4>; + adi,sysref-mode = <1>; /* JESD204_SYSREF_CONTINUOUS */ + adi,subclass = <1>; + adi,interpolation = <1>; + adi,frequency-center-shift = <0>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <1>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9144_core 1 0>; }; adc0_ad9680: ad9680@2 { + #address-cells = <1>; + #size-cells = <0>; compatible = "adi,ad9680"; reg = <2>; spi-max-frequency = <1000000>; - clocks = <&axi_ad9680_jesd>, <&clk0_ad9523 13>, <&clk0_ad9523 5>; - clock-names = "jesd_adc_clk", "adc_clk", "adc_sysref"; + clocks = <&clk0_ad9523 13>; + clock-names = "adc_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <0>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9680_core 0 0>; + + adi,powerdown-mode = ; + + adi,sampling-frequency = /bits/ 64 <1000000000>; + adi,input-clock-divider-ratio = <1>; + + adi,sysref-lmfc-offset = <0>; + adi,sysref-pos-window-skew = <0>; + adi,sysref-neg-window-skew = <0>; + adi,sysref-mode = ; + adi,sysref-nshot-ignore-count = <0>; + + /* JESD204 parameters */ + + adi,converters-per-device = <2>; /* JESD204 (M) */ + adi,lanes-per-device = <4>; /* JESD204 (L) */ + adi,octets-per-frame = <1>; /* JESD204 (F) */ + adi,frames-per-multiframe = <32>; /* JESD204 (K) */ + adi,converter-resolution = <14>; /* JESD204 (N) */ + adi,bits-per-sample = <16>; /* JESD204 (N') */ + adi,control-bits-per-sample = <2>; /* JESD204 (CS) */ + adi,subclass = <1>; /* JESD204 (SUBCLASSV) */ + + /* DDC setup */ + + adi,ddc-channel-number = ; + + ad9208_ddc0: channel@0 { + reg = <0>; + adi,decimation = <2>; + adi,nco-mode-select = ; + adi,nco-channel-carrier-frequency-hz = /bits/ 64 <70000000>; + adi,nco-channel-phase-offset = /bits/ 64 <0>; + }; }; }; - diff --git a/arch/arm/boot/dts/adi-daq3.dtsi b/arch/arm/boot/dts/adi-daq3.dtsi index 7f545f69afbe31..9b3c54e54c18f4 100644 --- a/arch/arm/boot/dts/adi-daq3.dtsi +++ b/arch/arm/boot/dts/adi-daq3.dtsi @@ -1,26 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCDAQ3-EBZ + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq3-ebz + * + * board_revision: + * + * Copyright (C) 2015-2022 Analog Devices Inc. + */ #include +#include &fmc_spi { clk0_ad9528: ad9528@0 { + #address-cells = <1>; + #size-cells = <0>; compatible = "adi,ad9528"; - reg = <0>; spi-cpol; spi-cpha; spi-max-frequency = <10000000>; adi,spi-3wire-enable; + reg = <0>; - #address-cells = <1>; - #size-cells = <0>; + clock-output-names = "ad9528_out0", "ad9528_out1", "ad9528_out2", "ad9528_out3", "ad9528_out4", "ad9528_out5", "ad9528_out6", "ad9528_out7", "ad9528_out8", "ad9528_out9", "ad9528_out10", "ad9528_out11", "ad9528_out12", "ad9528_out13"; #clock-cells = <1>; - clock-output-names = "ad9528_out0", "ad9528_out1", "ad9528_out2", "ad9528_out3", "ad9528_out4", "ad9528_out5", "ad9528_out6", "ad9528_out7", "ad9528_out8", "ad9528_out9", "ad9528_out10", "ad9528_out11", "ad9528_out12", "ad9528_out13"; - adi,vcxo-freq = <125000000>; + adi,vcxo-freq = <100000000>; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-sysref-provider; /* PLL1 config */ adi,pll1-bypass-enable; adi,osc-in-diff-enable; + /* PLL2 config */ /* * Valid ranges based on VCO locking range: * 1150.000 MHz - 1341.666 MHz @@ -28,32 +43,17 @@ * 690.000 MHz - 805.000 MHz */ adi,pll2-m1-frequency = <1233333333>; - - /* Manual divider configuration / -// adi,pll2-ndiv-a-cnt = <2>; /* a = N % 4 */ -// adi,pll2-ndiv-b-cnt = <7>; /* b = N / 4 */ -// adi,pll2-vco-div-m1 = <3>; -// adi,pll2-n2-div = <10>; /* N / M1 */ -// adi,pll2-r1-div = <1>; adi,pll2-charge-pump-current-nA = <35000>; /* SYSREF config */ adi,sysref-src = ; adi,sysref-k-div = <128>; + adi,sysref-pattern-mode = ; adi,rpole2 = ; adi,rzero = ; adi,cpole1 = ; - ad9528_0_c13: channel@13 { - reg = <13>; - adi,extended-name = "ADC_CLK"; - adi,driver-mode = ; - adi,divider-phase = <0>; - adi,channel-divider = <1>; - adi,signal-source = ; - }; - ad9528_0_c2: channel@2 { reg = <2>; adi,extended-name = "DAC_CLK"; @@ -65,7 +65,7 @@ ad9528_0_c4: channel@4 { reg = <4>; - adi,extended-name = "ADC_CLK_FMC"; + adi,extended-name = "DAC_CLK_FMC"; adi,driver-mode = ; adi,divider-phase = <0>; adi,channel-divider = <2>; @@ -74,79 +74,165 @@ ad9528_0_c5: channel@5 { reg = <5>; - adi,extended-name = "ADC_SYSREF"; + adi,extended-name = "DAC_SYSREF"; adi,driver-mode = ; adi,divider-phase = <0>; adi,channel-divider = <1>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c6: channel@6 { reg = <6>; - adi,extended-name = "CLKD_ADC_SYSREF"; + adi,extended-name = "CLKD_DAC_SYSREF"; adi,driver-mode = ; adi,divider-phase = <0>; adi,channel-divider = <2>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c7: channel@7 { reg = <7>; - adi,extended-name = "CLKD_DAC_SYSREF"; + adi,extended-name = "CLKD_ADC_SYSREF"; adi,driver-mode = ; adi,divider-phase = <0>; adi,channel-divider = <2>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c8: channel@8 { reg = <8>; - adi,extended-name = "DAC_SYSREF"; + adi,extended-name = "ADC_SYSREF"; adi,driver-mode = ; adi,divider-phase = <0>; adi,channel-divider = <1>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c9: channel@9 { reg = <9>; - adi,extended-name = "DAC_CLK_FMC"; + adi,extended-name = "ADC_CLK_FMC"; adi,driver-mode = ; adi,divider-phase = <0>; adi,channel-divider = <2>; adi,signal-source = ; }; + + ad9528_0_c13: channel@13 { + reg = <13>; + adi,extended-name = "ADC_CLK"; + adi,driver-mode = ; + adi,divider-phase = <0>; + adi,channel-divider = <1>; + adi,signal-source = ; + }; }; dac0_ad9152: ad9152@1 { + #address-cells = <1>; + #size-cells = <0>; compatible = "adi,ad9152"; - reg = <1>; spi-cpol; spi-cpha; spi-max-frequency = <10000000>; adi,spi-3wire-enable; + reg = <1>; + + clocks = <&clk0_ad9528 2>; + clock-names = "dac_clk"; - clocks = <&axi_ad9152_jesd>, <&clk0_ad9528 2>, <&clk0_ad9528 8>; - clock-names = "jesd_dac_clk", "dac_clk", "dac_sysref"; + /* + * | MODE | M | L | S | F | HD | N | N' | + * | 00 | 4 | 8 | 1 | 1 | 1 | 16 | 16 | + * | 01 | 4 | 8 | 2 | 2 | 0 | 16 | 16 | + * | 02 | 4 | 4 | 1 | 2 | 0 | 16 | 16 | + * | 03 | 4 | 2 | 1 | 4 | 0 | 16 | 16 | + * | 04 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 05 | 2 | 4 | 2 | 2 | 0 | 16 | 16 | + * | 06 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + * | 07 | 2 | 1 | 1 | 4 | 0 | 16 | 16 | + * | 08 | 1 | 4 | 2 | 1 | 1 | 16 | 16 | + * | 09 | 1 | 2 | 1 | 1 | 1 | 16 | 16 | + * | 10 | 1 | 1 | 1 | 2 | 0 | 16 | 16 | + * | 11 | 2 | 8 | 2 | 1 | 1 | 16 | 16 | + * | 12 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 13 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + */ - /* Fix for an early DAQ3 design bug (swapped SERDIN+ / SERDIN- pins) */ - //adi,lanes2-3-swap-data; + adi,jesd-link-mode = <4>; + adi,sysref-mode = <1>; /* JESD204_SYSREF_CONTINUOUS */ + adi,subclass = <1>; + adi,interpolation = <1>; + adi,frequency-center-shift = <0>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <1>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9152_core 1 0>; }; adc0_ad9680: ad9680@2 { + #address-cells = <1>; + #size-cells = <0>; compatible = "adi,ad9680"; - reg = <2>; spi-cpol; spi-cpha; spi-max-frequency = <10000000>; adi,spi-3wire-enable; + reg = <2>; /* Content of Registers: 0x16, 0x18, 0x19, 0x1A, 0x30, 0x11A, 0x934, 0x935 */ adi,sfdr-optimization-config = <0xE 0xA0 0x50 0x09 0x18 0x00 0x1F 0x04>; - clocks = <&axi_ad9680_jesd>, <&clk0_ad9528 13>, <&clk0_ad9528 5>; - clock-names = "jesd_adc_clk", "adc_clk", "adc_sysref"; + clocks = <&clk0_ad9528 13>; + clock-names = "adc_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <0>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9680_core 0 0>; + + adi,powerdown-mode = ; + + adi,sampling-frequency = /bits/ 64 <1233333333>; + adi,input-clock-divider-ratio = <1>; + + adi,sysref-lmfc-offset = <0>; + adi,sysref-pos-window-skew = <0>; + adi,sysref-neg-window-skew = <0>; + adi,sysref-mode = ; + adi,sysref-nshot-ignore-count = <0>; + + /* JESD204 parameters */ + + adi,converters-per-device = <2>; /* JESD204 (M) */ + adi,lanes-per-device = <4>; /* JESD204 (L) */ + adi,octets-per-frame = <1>; /* JESD204 (F) */ + adi,frames-per-multiframe = <32>; /* JESD204 (K) */ + adi,converter-resolution = <14>; /* JESD204 (N) */ + adi,bits-per-sample = <16>; /* JESD204 (N') */ + adi,control-bits-per-sample = <2>; /* JESD204 (CS) */ + adi,subclass = <1>; /* JESD204 (SUBCLASSV) */ + + /* DDC setup */ + + adi,ddc-channel-number = ; + + ad9208_ddc0: channel@0 { + reg = <0>; + adi,decimation = <2>; + adi,nco-mode-select = ; + adi,nco-channel-carrier-frequency-hz = /bits/ 64 <70000000>; + adi,nco-channel-phase-offset = /bits/ 64 <0>; + }; }; }; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_daq2.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_daq2.dts index bbedaab07e1a6d..13691839192306 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_daq2.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_daq2.dts @@ -4,9 +4,9 @@ * Link: https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq2-ebz * * hdl_project: - * board_revision: + * board_revision: * - * Copyright 2016-2019 Analog Devices Inc. + * Copyright 2016-2022 Analog Devices Inc. */ /dts-v1/; #include "socfpga_arria10_socdk.dtsi" @@ -121,6 +121,11 @@ spibus-connected = <&dac0_ad9144>; adi,axi-pl-fifo-enable; plddrbypass-gpios = <&sys_gpio_out 12 0>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_jesd 1 0>; }; axi_ad9144_jesd: axi-jesd204-tx@20000 { @@ -133,14 +138,14 @@ clocks = <&sys_clk>, <&tx_device_clk_pll>, <&axi_ad9144_xcvr>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <2>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_xcvr 1 0>; + }; axi_ad9680_core: axi-ad9680-hpc@50000 { @@ -149,6 +154,11 @@ dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&adc0_ad9680>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_jesd 0 0>; }; axi_ad9680_jesd: axi-jesd204-rx@40000 { @@ -161,11 +171,13 @@ clocks = <&sys_clk>, <&rx_device_clk_pll>, <&axi_ad9680_xcvr>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - #clock-cells = <0>; clock-output-names = "jesd_adc_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_xcvr 0 0>; }; axi_ad9144_xcvr: axi-ad9144-xcvr@24000 { @@ -182,6 +194,10 @@ clocks = <&clk0_ad9523 9>, <&tx_device_clk_pll>; clock-names = "ref", "link"; clock-output-names = "jesd204_tx_lane_clock"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; axi_ad9680_xcvr: axi-ad9680-xcvr@44000 { @@ -197,6 +213,10 @@ clocks = <&clk0_ad9523 4>, <&rx_device_clk_pll>; clock-names = "ref", "link"; clock-output-names = "jesd204_rx_lane_clock"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; tx_device_clk_pll: altera-a10-fpll@25000 { diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq2.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq2.dts index 8598325ae0b16b..d42b078d1d0ad6 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq2.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq2.dts @@ -4,7 +4,7 @@ * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq2-ebz * * hdl_project: - * board_revision: <> + * board_revision: * * Copyright (C) 2014-2019 Analog Devices Inc. */ @@ -88,6 +88,11 @@ dma-names = "tx"; spibus-connected = <&dac0_ad9144>; adi,axi-pl-fifo-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_jesd 1 0>; }; axi_ad9144_jesd: axi-jesd204-tx@44a90000 { @@ -99,14 +104,13 @@ clocks = <&clkc 16>, <&axi_ad9144_adxcvr 1>, <&axi_ad9144_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <2>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_adxcvr 1 0>; }; axi_ad9680_core: axi-ad9680-hpc@44a10000 { @@ -115,6 +119,11 @@ dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&adc0_ad9680>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_jesd 0 0>; }; axi_ad9680_jesd: axi-jesd204-rx@44aa0000 { @@ -131,6 +140,11 @@ #clock-cells = <0>; clock-output-names = "jesd_adc_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_adxcvr 0 0>; }; axi_ad9680_adxcvr: axi-adxcvr-rx@44a50000 { @@ -146,6 +160,10 @@ adi,sys-clk-select = ; adi,out-clk-select = ; adi,use-lpm-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; axi_ad9144_adxcvr: axi-adxcvr-tx@44a60000 { @@ -161,6 +179,10 @@ adi,sys-clk-select = ; adi,out-clk-select = ; adi,use-lpm-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; }; diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3-revC.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3-revC.dts index a29cd14071deb1..ec22c25c364892 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3-revC.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3-revC.dts @@ -4,115 +4,8 @@ * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq3-ebz * * hdl_project: - * board_revision: + * board_revision: * - * Copyright (C) 2015-2019 Analog Devices Inc. + * Copyright (C) 2015-2022 Analog Devices Inc. */ #include "zynq-zc706-adv7511-fmcdaq3.dts" - -/delete-node/ &ad9528_0_c13; -/delete-node/ &ad9528_0_c2; -/delete-node/ &ad9528_0_c6; -/delete-node/ &ad9528_0_c7; -/delete-node/ &ad9528_0_c5; -/delete-node/ &ad9528_0_c8; -/delete-node/ &ad9528_0_c4; -/delete-node/ &ad9528_0_c9; - -&clk0_ad9528 { - - adi,vcxo-freq = <100000000>; - /* PLL2 config for VCO = 3600MHz, N = 36*/ -// adi,pll2-n2-div = <12>; /* N / M1 */ - - ad9528_0_c13: channel@13 { - reg = <13>; - adi,extended-name = "ADC_CLK"; - adi,driver-mode = ; - adi,divider-phase = <0>; - adi,channel-divider = <1>; - adi,signal-source = ; - }; - - ad9528_0_c2: channel@2 { - reg = <2>; - adi,extended-name = "DAC_CLK"; - adi,driver-mode = ; - adi,divider-phase = <0>; - adi,channel-divider = <1>; - adi,signal-source = ; - }; - - ad9528_0_c9: channel@9 { - reg = <9>; - adi,extended-name = "ADC_CLK_FMC"; - adi,driver-mode = ; - adi,divider-phase = <0>; - adi,channel-divider = <2>; - adi,signal-source = ; - }; - - ad9528_0_c8: channel@8 { - reg = <8>; - adi,extended-name = "ADC_SYSREF"; - adi,driver-mode = ; - adi,divider-phase = <0>; - adi,channel-divider = <1>; - adi,signal-source = ; - }; - - ad9528_0_c7: channel@7 { - reg = <7>; - adi,extended-name = "CLKD_ADC_SYSREF"; - adi,driver-mode = ; - adi,divider-phase = <0>; - adi,channel-divider = <2>; - adi,signal-source = ; - }; - - ad9528_0_c6: channel@6 { - reg = <6>; - adi,extended-name = "CLKD_DAC_SYSREF"; - adi,driver-mode = ; - adi,divider-phase = <0>; - adi,channel-divider = <2>; - adi,signal-source = ; - }; - - ad9528_0_c5: channel@5 { - reg = <5>; - adi,extended-name = "DAC_SYSREF"; - adi,driver-mode = ; - adi,divider-phase = <0>; - adi,channel-divider = <1>; - adi,signal-source = ; - }; - - ad9528_0_c4: channel@4 { - reg = <4>; - adi,extended-name = "DAC_CLK_FMC"; - adi,driver-mode = ; - adi,divider-phase = <0>; - adi,channel-divider = <2>; - adi,signal-source = ; - }; -}; - -&dac0_ad9152 { - clocks = <&axi_ad9152_jesd>, <&clk0_ad9528 2>, <&clk0_ad9528 5>; -}; - -&adc0_ad9680 { - clocks = <&axi_ad9680_jesd>, <&clk0_ad9528 13>, <&clk0_ad9528 8>; -}; - -&axi_ad9680_adxcvr { - clocks = <&clk0_ad9528 9>, <&clk0_ad9528 7>; -}; - -&axi_ad9152_adxcvr { - clocks = <&clk0_ad9528 4>, <&clk0_ad9528 6>; - adi,vco1-max-khz = <12333340>; -}; - - diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3.dts index 6ba89857bac809..502a3456722c96 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3.dts @@ -4,9 +4,9 @@ * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq3-ebz * * hdl_project: - * board_revision: <> + * board_revision: * - * Copyright (C) 2015-2019 Analog Devices Inc. + * Copyright (C) 2015-2022 Analog Devices Inc. */ /dts-v1/; @@ -87,8 +87,12 @@ dma-names = "tx"; spibus-connected = <&dac0_ad9152>; - adi,axi-pl-fifo-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9152_jesd 1 0>; }; axi_ad9152_jesd: axi-jesd204-tx@44a90000 { @@ -99,15 +103,13 @@ clocks = <&clkc 16>, <&axi_ad9152_adxcvr 1>, <&axi_ad9152_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <2>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9152_adxcvr 1 0>; }; axi_ad9680_core: axi-ad9680-hpc@44a10000 { @@ -117,6 +119,11 @@ dma-names = "rx"; spibus-connected = <&adc0_ad9680>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_jesd 0 0>; }; axi_ad9680_jesd: axi-jesd204-rx@44aa0000 { @@ -127,12 +134,13 @@ clocks = <&clkc 16>, <&axi_ad9680_adxcvr 1>, <&axi_ad9680_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - #clock-cells = <0>; + clock-output-names = "jesd_adc_lane_clk"; + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_adxcvr 0 0>; }; axi_ad9680_adxcvr: axi-adxcvr-rx@44a50000 { @@ -141,7 +149,7 @@ compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a50000 0x1000>; - clocks = <&clk0_ad9528 4>; + clocks = <&clk0_ad9528 9>; clock-names = "conv"; #clock-cells = <1>; @@ -149,7 +157,13 @@ adi,sys-clk-select = ; adi,out-clk-select = ; + adi,vco1-max-khz = <12333340>; adi,use-lpm-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&clk0_ad9528 0 0>; }; axi_ad9152_adxcvr: axi-adxcvr-tx@44a60000 { @@ -158,7 +172,7 @@ compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a60000 0x1000>; - clocks = <&clk0_ad9528 9>; + clocks = <&clk0_ad9528 4>; clock-names = "conv"; #clock-cells = <1>; @@ -166,6 +180,11 @@ adi,sys-clk-select = ; adi,out-clk-select = ; + adi,vco1-max-khz = <12333340>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; }; From 2aa72a040913a3a6c4ef0b6b5f4d5cddf1009d5a Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 21 Jan 2022 11:17:06 +0100 Subject: [PATCH 116/407] microblaze: dts: AD-FMCDAQ2-EBZ & AD-FMCDAQ3-EBZ switch to jesd204-fsm This patch enables jesd204-fsm support for the AD-FMCDAQ2-EBZ and AD-FMCDAQ3-EBZ projects. There is a bit more noise in this commit, since we try to unify the dtsi and dts across different architectures. We also add missing comment headers, update the copyright and remove come dead or commented code. Signed-off-by: Michael Hennerich --- arch/microblaze/boot/dts/adi-daq2.dtsi | 128 ++++++++++++++++---- arch/microblaze/boot/dts/adi-daq3.dtsi | 102 +++++++++++++++- arch/microblaze/boot/dts/kc705_fmcdaq2.dts | 47 +++++-- arch/microblaze/boot/dts/kcu105_fmcdaq2.dts | 47 +++++-- arch/microblaze/boot/dts/kcu105_fmcdaq3.dts | 47 +++++-- arch/microblaze/boot/dts/vc707_fmcdaq2.dts | 46 +++++-- arch/microblaze/boot/dts/vcu118_fmcdaq3.dts | 46 +++++-- 7 files changed, 381 insertions(+), 82 deletions(-) diff --git a/arch/microblaze/boot/dts/adi-daq2.dtsi b/arch/microblaze/boot/dts/adi-daq2.dtsi index 92f62bafbc919e..841bb9f8cca002 100644 --- a/arch/microblaze/boot/dts/adi-daq2.dtsi +++ b/arch/microblaze/boot/dts/adi-daq2.dtsi @@ -1,23 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCDAQ2-EBZ + * Link: https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq2-ebz + * + * board_revision: + * + * Copyright 2014-2022 Analog Devices Inc. + */ +#include &fmc_spi { - clk0_ad9523: ad9523-1@0 { #address-cells = <1>; #size-cells = <0>; - #clock-cells = <1>; - compatible = "ad9523-1"; + compatible = "adi,ad9523-1"; reg = <0>; spi-cpol; spi-cpha; spi-max-frequency = <10000000>; - clock-output-names = "ad9523-1_out0", "ad9523-1_out1", "ad9523-1_out2", "ad9523-1_out3", "ad9523-1_out4", "ad9523-1_out5", "ad9523-1_out6", "ad9523-1_out7", "ad9523-1_out8", "ad9523-1_out9", "ad9523-1_out10", "ad9523-1_out11", "ad9523-1_out12", "ad9523-1_out13"; + + clock-output-names = + "ad9523-1_out0", "ad9523-1_out1", "ad9523-1_out2", + "ad9523-1_out3", "ad9523-1_out4", "ad9523-1_out5", + "ad9523-1_out6", "ad9523-1_out7", "ad9523-1_out8", + "ad9523-1_out9", "ad9523-1_out10", "ad9523-1_out11", + "ad9523-1_out12", "ad9523-1_out13"; + #clock-cells = <1>; + adi,vcxo-freq = <125000000>; adi,spi-3wire-enable; adi,pll1-bypass-enable; adi,osc-in-diff-enable; adi,pll2-charge-pump-current-nA = <413000>; + /* * Valid ranges based on VCO locking range: * 980.00 MHz - 1033.33 MHz @@ -27,10 +44,10 @@ adi,pll2-m1-freq = <1000000000>; /* Manual PLL2 divider configuration */ - //adi,pll2-ndiv-a-cnt = <0>; - //adi,pll2-ndiv-b-cnt = <6>; - //adi,pll2-r2-div = <1>; - //adi,pll2-vco-div-m1 = <3>; +// adi,pll2-r2-div = <1>; +// adi,pll2-vco-div-m1 = <3>; +// adi,pll2-ndiv-a-cnt = <0>; /* a = N % 4 */ +// adi,pll2-ndiv-b-cnt = <6>; /* b = N / 4 */ adi,rpole2 = <0>; adi,rzero = <7>; @@ -42,15 +59,14 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <1>; -// adi,output-dis; }; + ad9523_0_c4:channel@4 { reg = <4>; adi,extended-name = "ADC_CLK_FMC"; adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <2>; -// adi,output-dis; }; ad9523_0_c5:channel@5 { @@ -59,7 +75,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c6:channel@6 { @@ -68,7 +83,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c7:channel@7 { @@ -77,7 +91,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c8:channel@8 { @@ -86,7 +99,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <128>; -// adi,output-dis; }; ad9523_0_c9:channel@9 { @@ -95,7 +107,6 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <2>; -// adi,output-dis; }; ad9523_0_c13:channel@13 { @@ -104,33 +115,106 @@ adi,driver-mode = <3>; adi,divider-phase = <1>; adi,channel-divider = <1>; -// adi,output-dis; }; }; dac0_ad9144: ad9144@1 { #address-cells = <1>; #size-cells = <0>; - compatible = "ad9144"; + compatible = "adi,ad9144"; reg = <1>; spi-cpol; spi-cpha; + spi-max-frequency = <1000000>; - clocks = <&axi_ad9144_jesd>, <&clk0_ad9523 1>, <&clk0_ad9523 8>; - clock-names = "jesd_dac_clk", "dac_clk", "dac_sysref"; + clocks = <&clk0_ad9523 1>; + clock-names = "dac_clk"; + + /* + * | MODE | M | L | S | F | HD | N | N' | + * | 00 | 4 | 8 | 1 | 1 | 1 | 16 | 16 | + * | 01 | 4 | 8 | 2 | 2 | 0 | 16 | 16 | + * | 02 | 4 | 4 | 1 | 2 | 0 | 16 | 16 | + * | 03 | 4 | 2 | 1 | 4 | 0 | 16 | 16 | + * | 04 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 05 | 2 | 4 | 2 | 2 | 0 | 16 | 16 | + * | 06 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + * | 07 | 2 | 1 | 1 | 4 | 0 | 16 | 16 | + * | 08 | 1 | 4 | 2 | 1 | 1 | 16 | 16 | + * | 09 | 1 | 2 | 1 | 1 | 1 | 16 | 16 | + * | 10 | 1 | 1 | 1 | 2 | 0 | 16 | 16 | + * | 11 | 2 | 8 | 2 | 1 | 1 | 16 | 16 | + * | 12 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 13 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + */ + + adi,jesd-link-mode = <4>; + adi,sysref-mode = <1>; /* JESD204_SYSREF_CONTINUOUS */ + adi,subclass = <1>; + adi,interpolation = <1>; + adi,frequency-center-shift = <0>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <1>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9144_core 1 0>; }; adc0_ad9680: ad9680@2 { #address-cells = <1>; #size-cells = <0>; - compatible = "ad9680"; + compatible = "adi,ad9680"; reg = <2>; - spi-max-frequency = <1000000>; spi-cpol; spi-cpha; + + spi-max-frequency = <1000000>; + clocks = <&axi_ad9680_jesd>, <&clk0_ad9523 13>, <&clk0_ad9523 5>; clock-names = "jesd_adc_clk", "adc_clk", "adc_sysref"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <0>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9680_core 0 0>; + + adi,powerdown-mode = ; + + adi,sampling-frequency = /bits/ 64 <1000000000>; + adi,input-clock-divider-ratio = <1>; + + adi,sysref-lmfc-offset = <0>; + adi,sysref-pos-window-skew = <0>; + adi,sysref-neg-window-skew = <0>; + adi,sysref-mode = ; + adi,sysref-nshot-ignore-count = <0>; + + /* JESD204 parameters */ + + adi,converters-per-device = <2>; /* JESD204 (M) */ + adi,lanes-per-device = <4>; /* JESD204 (L) */ + adi,octets-per-frame = <1>; /* JESD204 (F) */ + adi,frames-per-multiframe = <32>; /* JESD204 (K) */ + adi,converter-resolution = <14>; /* JESD204 (N) */ + adi,bits-per-sample = <16>; /* JESD204 (N') */ + adi,control-bits-per-sample = <2>; /* JESD204 (CS) */ + adi,subclass = <1>; /* JESD204 (SUBCLASSV) */ + + /* DDC setup */ + + adi,ddc-channel-number = ; + + ad9208_ddc0: channel@0 { + reg = <0>; + adi,decimation = <2>; + adi,nco-mode-select = ; + adi,nco-channel-carrier-frequency-hz = /bits/ 64 <70000000>; + adi,nco-channel-phase-offset = /bits/ 64 <0>; + }; }; }; - diff --git a/arch/microblaze/boot/dts/adi-daq3.dtsi b/arch/microblaze/boot/dts/adi-daq3.dtsi index e14a80cf904ac7..74274a8cf761b8 100644 --- a/arch/microblaze/boot/dts/adi-daq3.dtsi +++ b/arch/microblaze/boot/dts/adi-daq3.dtsi @@ -1,10 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCDAQ3-EBZ + * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq3-ebz + * + * board_revision: + * + * Copyright (C) 2018-2022 Analog Devices Inc. + */ #include +#include &fmc_spi { clk0_ad9528: ad9528@0 { #address-cells = <1>; #size-cells = <0>; - #clock-cells = <1>; compatible = "adi,ad9528"; spi-cpol; @@ -14,8 +23,14 @@ reg = <0>; clock-output-names = "ad9528_out0", "ad9528_out1", "ad9528_out2", "ad9528_out3", "ad9528_out4", "ad9528_out5", "ad9528_out6", "ad9528_out7", "ad9528_out8", "ad9528_out9", "ad9528_out10", "ad9528_out11", "ad9528_out12", "ad9528_out13"; + #clock-cells = <1>; + adi,vcxo-freq = <100000000>; + jesd204-device; + #jesd204-cells = <2>; + jesd204-sysref-provider; + /* PLL1 config */ adi,pll1-bypass-enable; adi,osc-in-diff-enable; @@ -33,6 +48,7 @@ /* SYSREF config */ adi,sysref-src = ; adi,sysref-k-div = <128>; + adi,sysref-pattern-mode = ; adi,rpole2 = ; adi,rzero = ; @@ -63,6 +79,7 @@ adi,divider-phase = <0>; adi,channel-divider = <1>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c6: channel@6 { @@ -72,6 +89,7 @@ adi,divider-phase = <0>; adi,channel-divider = <2>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c7: channel@7 { @@ -81,6 +99,7 @@ adi,divider-phase = <0>; adi,channel-divider = <2>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c8: channel@8 { @@ -90,6 +109,7 @@ adi,divider-phase = <0>; adi,channel-divider = <1>; adi,signal-source = ; + adi,jesd204-sysref-chan; }; ad9528_0_c9: channel@9 { @@ -122,8 +142,39 @@ adi,spi-3wire-enable; reg = <1>; - clocks = <&axi_ad9152_jesd>, <&clk0_ad9528 2>, <&clk0_ad9528 5>; - clock-names = "jesd_dac_clk", "dac_clk", "dac_sysref"; + clocks = <&clk0_ad9528 2>; + clock-names = "dac_clk"; + + /* + * | MODE | M | L | S | F | HD | N | N' | + * | 00 | 4 | 8 | 1 | 1 | 1 | 16 | 16 | + * | 01 | 4 | 8 | 2 | 2 | 0 | 16 | 16 | + * | 02 | 4 | 4 | 1 | 2 | 0 | 16 | 16 | + * | 03 | 4 | 2 | 1 | 4 | 0 | 16 | 16 | + * | 04 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 05 | 2 | 4 | 2 | 2 | 0 | 16 | 16 | + * | 06 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + * | 07 | 2 | 1 | 1 | 4 | 0 | 16 | 16 | + * | 08 | 1 | 4 | 2 | 1 | 1 | 16 | 16 | + * | 09 | 1 | 2 | 1 | 1 | 1 | 16 | 16 | + * | 10 | 1 | 1 | 1 | 2 | 0 | 16 | 16 | + * | 11 | 2 | 8 | 2 | 1 | 1 | 16 | 16 | + * | 12 | 2 | 4 | 1 | 1 | 1 | 16 | 16 | + * | 13 | 2 | 2 | 1 | 2 | 0 | 16 | 16 | + */ + + adi,jesd-link-mode = <4>; + adi,sysref-mode = <1>; /* JESD204_SYSREF_CONTINUOUS */ + adi,subclass = <1>; + adi,interpolation = <1>; + adi,frequency-center-shift = <0>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <1>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9152_core 1 0>; }; adc0_ad9680: ad9680@2 { @@ -140,7 +191,48 @@ /* Content of Registers: 0x16, 0x18, 0x19, 0x1A, 0x30, 0x11A, 0x934, 0x935 */ adi,sfdr-optimization-config = <0xE 0xA0 0x50 0x09 0x18 0x00 0x1F 0x04>; - clocks = <&axi_ad9680_jesd>, <&clk0_ad9528 13>, <&clk0_ad9528 8>; - clock-names = "jesd_adc_clk", "adc_clk", "adc_sysref"; + clocks = <&clk0_ad9528 13>; + clock-names = "adc_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <0>; /* This is the TOP device */ + jesd204-link-ids = <0>; + jesd204-inputs = <&axi_ad9680_core 0 0>; + + adi,powerdown-mode = ; + + adi,sampling-frequency = /bits/ 64 <1233333333>; + adi,input-clock-divider-ratio = <1>; + + adi,sysref-lmfc-offset = <0>; + adi,sysref-pos-window-skew = <0>; + adi,sysref-neg-window-skew = <0>; + adi,sysref-mode = ; + adi,sysref-nshot-ignore-count = <0>; + + /* JESD204 parameters */ + + adi,converters-per-device = <2>; /* JESD204 (M) */ + adi,lanes-per-device = <4>; /* JESD204 (L) */ + adi,octets-per-frame = <1>; /* JESD204 (F) */ + adi,frames-per-multiframe = <32>; /* JESD204 (K) */ + adi,converter-resolution = <14>; /* JESD204 (N) */ + adi,bits-per-sample = <16>; /* JESD204 (N') */ + adi,control-bits-per-sample = <2>; /* JESD204 (CS) */ + adi,subclass = <1>; /* JESD204 (SUBCLASSV) */ + + /* DDC setup */ + + adi,ddc-channel-number = ; + + ad9208_ddc0: channel@0 { + reg = <0>; + adi,decimation = <2>; + adi,nco-mode-select = ; + adi,nco-channel-carrier-frequency-hz = /bits/ 64 <70000000>; + adi,nco-channel-phase-offset = /bits/ 64 <0>; + }; }; }; diff --git a/arch/microblaze/boot/dts/kc705_fmcdaq2.dts b/arch/microblaze/boot/dts/kc705_fmcdaq2.dts index 8cb43e5e358669..fe91c89c480eef 100644 --- a/arch/microblaze/boot/dts/kc705_fmcdaq2.dts +++ b/arch/microblaze/boot/dts/kc705_fmcdaq2.dts @@ -4,9 +4,9 @@ * Link: https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq2-ebz * * hdl_project: - * board_revision: <> + * board_revision: * - * Copyright 2016-2020 Analog Devices Inc. + * Copyright 2016-2022 Analog Devices Inc. */ /dts-v1/; @@ -68,13 +68,20 @@ }; }; }; + axi_ad9680_core: axi-ad9680-hpc@44a10000 { compatible = "adi,axi-ad9680-1.0"; reg = <0x44a10000 0x10000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&adc0_ad9680>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_jesd 0 0>; }; + axi_ad9144_core: axi-ad9144-hpc@44a04000 { compatible = "adi,axi-ad9144-1.0"; reg = <0x44a04000 0x10000>; @@ -82,7 +89,13 @@ dma-names = "tx"; spibus-connected = <&dac0_ad9144>; adi,axi-pl-fifo-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_jesd 1 0>; }; + axi_ad9680_jesd: axi-jesd204-rx@44aa0000 { compatible = "adi,axi-jesd204-rx-1.0"; reg = <0x44aa0000 0x4000>; @@ -92,12 +105,15 @@ clocks = <&clk_bus_0>, <&axi_ad9680_adxcvr 1>, <&axi_ad9680_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - #clock-cells = <0>; clock-output-names = "jesd_adc_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_adxcvr 0 0>; }; + axi_ad9680_adxcvr: axi-ad9680-adxcvr@44a50000 { compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a50000 0x10000>; @@ -112,7 +128,12 @@ #clock-cells = <1>; clock-output-names = "adc_gt_clk", "rx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; + axi_ad9144_jesd: axi-jesd204-tx@44a90000 { compatible = "adi,axi-jesd204-tx-1.0"; reg = <0x44a90000 0x4000>; @@ -122,15 +143,15 @@ clocks = <&clk_bus_0>, <&axi_ad9144_adxcvr 1>, <&axi_ad9144_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <2>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_adxcvr 1 0>; }; + axi_ad9144_adxcvr: axi-ad9144-adxcvr@44a60000 { compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a60000 0x10000>; @@ -144,6 +165,10 @@ #clock-cells = <1>; clock-output-names = "dac_gt_clk", "tx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; }; diff --git a/arch/microblaze/boot/dts/kcu105_fmcdaq2.dts b/arch/microblaze/boot/dts/kcu105_fmcdaq2.dts index 8edad7f56fb41d..3dae69b43dfc4b 100644 --- a/arch/microblaze/boot/dts/kcu105_fmcdaq2.dts +++ b/arch/microblaze/boot/dts/kcu105_fmcdaq2.dts @@ -4,9 +4,9 @@ * Link: https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq2-ebz * * hdl_project: - * board_revision: <> + * board_revision: * - * Copyright 2016-2020 Analog Devices Inc. + * Copyright 2016-2022 Analog Devices Inc. */ /dts-v1/; @@ -68,13 +68,20 @@ }; }; }; + axi_ad9680_core: axi-ad9680-hpc@44a10000 { compatible = "adi,axi-ad9680-1.0"; reg = <0x44a10000 0x10000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&adc0_ad9680>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_jesd 0 0>; }; + axi_ad9144_core: axi-ad9144-hpc@44a04000 { compatible = "adi,axi-ad9144-1.0"; reg = <0x44a04000 0x10000>; @@ -82,7 +89,13 @@ dma-names = "tx"; spibus-connected = <&dac0_ad9144>; adi,axi-pl-fifo-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_jesd 1 0>; }; + axi_ad9680_jesd: axi-jesd204-rx@44aa0000 { compatible = "adi,axi-jesd204-rx-1.0"; reg = <0x44aa0000 0x4000>; @@ -92,12 +105,15 @@ clocks = <&clk_bus_0>, <&axi_ad9680_adxcvr 1>, <&axi_ad9680_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - #clock-cells = <0>; clock-output-names = "jesd_adc_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_adxcvr 0 0>; }; + axi_ad9680_adxcvr: axi-ad9680-adxcvr@44a50000 { compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a50000 0x10000>; @@ -111,7 +127,12 @@ #clock-cells = <1>; clock-output-names = "adc_gt_clk", "rx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; + axi_ad9144_jesd: axi-jesd204-tx@44a90000 { compatible = "adi,axi-jesd204-tx-1.0"; reg = <0x44a90000 0x4000>; @@ -121,15 +142,15 @@ clocks = <&clk_bus_0>, <&axi_ad9144_adxcvr 1>, <&axi_ad9144_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <2>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_adxcvr 1 0>; }; + axi_ad9144_adxcvr: axi-ad9144-adxcvr@44a60000 { compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a60000 0x10000>; @@ -143,6 +164,10 @@ #clock-cells = <1>; clock-output-names = "dac_gt_clk", "tx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; }; diff --git a/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts b/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts index c774bf77bde74c..5fabf16cfcef93 100644 --- a/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts +++ b/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts @@ -4,9 +4,9 @@ * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq3-ebz * * hdl_project: - * board_revision: <> + * board_revision: * - * Copyright (C) 2015-2021 Analog Devices Inc. + * Copyright (C) 2015-2022 Analog Devices Inc. */ /dts-v1/; @@ -67,13 +67,20 @@ }; }; }; + axi_ad9680_core: axi-ad9680-hpc@44a10000 { compatible = "adi,axi-ad9680-1.0"; reg = <0x44a10000 0x10000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&adc0_ad9680>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_jesd 0 0>; }; + axi_ad9152_core: axi-ad9152-hpc@44a04000 { compatible = "adi,axi-ad9144-1.0"; reg = <0x44a04000 0x10000>; @@ -81,7 +88,13 @@ dma-names = "tx"; spibus-connected = <&dac0_ad9152>; adi,axi-pl-fifo-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9152_jesd 1 0>; }; + axi_ad9680_jesd: axi-jesd204-rx@44aa0000 { compatible = "adi,axi-jesd204-rx-1.0"; reg = <0x44aa0000 0x4000>; @@ -91,12 +104,15 @@ clocks = <&clk_bus_0>, <&axi_ad9680_adxcvr 1>, <&axi_ad9680_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - #clock-cells = <0>; clock-output-names = "jesd_adc_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_adxcvr 0 0>; }; + axi_ad9680_adxcvr: axi-ad9680-adxcvr@44a50000 { compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a50000 0x10000>; @@ -110,7 +126,12 @@ #clock-cells = <1>; clock-output-names = "adc_gt_clk", "rx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; + axi_ad9152_jesd: axi-jesd204-tx@44a90000 { compatible = "adi,axi-jesd204-tx-1.0"; reg = <0x44a90000 0x4000>; @@ -120,15 +141,15 @@ clocks = <&clk_bus_0>, <&axi_ad9152_adxcvr 1>, <&axi_ad9152_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <2>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9152_adxcvr 1 0>; }; + axi_ad9152_adxcvr: axi-ad9152-adxcvr@44a60000 { compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a60000 0x10000>; @@ -142,6 +163,10 @@ #clock-cells = <1>; clock-output-names = "dac_gt_clk", "tx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; }; diff --git a/arch/microblaze/boot/dts/vc707_fmcdaq2.dts b/arch/microblaze/boot/dts/vc707_fmcdaq2.dts index 06fd427d2a709f..7d6bf3f0e58247 100644 --- a/arch/microblaze/boot/dts/vc707_fmcdaq2.dts +++ b/arch/microblaze/boot/dts/vc707_fmcdaq2.dts @@ -4,9 +4,9 @@ * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq2-ebz * * hdl_project: - * board_revision: <> + * board_revision: * - * Copyright (C) 2014-2021 Analog Devices Inc. + * Copyright (C) 2014-2022 Analog Devices Inc. */ /dts-v1/; @@ -69,7 +69,13 @@ dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&adc0_ad9680>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_jesd 0 0>; }; + axi_ad9144_core: axi-ad9144-hpc@44a04000 { compatible = "adi,axi-ad9144-1.0"; reg = <0x44a04000 0x10000>; @@ -77,7 +83,13 @@ dma-names = "tx"; spibus-connected = <&dac0_ad9144>; adi,axi-pl-fifo-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_jesd 1 0>; }; + axi_ad9680_jesd: axi-jesd204-rx@44aa0000 { compatible = "adi,axi-jesd204-rx-1.0"; reg = <0x44aa0000 0x4000>; @@ -87,12 +99,15 @@ clocks = <&clk_bus_0>, <&axi_ad9680_adxcvr 1>, <&axi_ad9680_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - #clock-cells = <0>; clock-output-names = "jesd_adc_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_adxcvr 0 0>; }; + axi_ad9680_adxcvr: axi-ad9680-adxcvr@44a50000 { compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a50000 0x10000>; @@ -106,7 +121,12 @@ #clock-cells = <1>; clock-output-names = "adc_gt_clk", "rx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; + axi_ad9144_jesd: axi-jesd204-tx@44a90000 { compatible = "adi,axi-jesd204-tx-1.0"; reg = <0x44a90000 0x4000>; @@ -116,15 +136,15 @@ clocks = <&clk_bus_0>, <&axi_ad9144_adxcvr 1>, <&axi_ad9144_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <2>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9144_adxcvr 1 0>; }; + axi_ad9144_adxcvr: axi-ad9144-adxcvr@44a60000 { compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a60000 0x10000>; @@ -138,6 +158,10 @@ #clock-cells = <1>; clock-output-names = "dac_gt_clk", "tx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; }; diff --git a/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts b/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts index 46a62efbd35361..07a72c4132aaae 100644 --- a/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts +++ b/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts @@ -4,9 +4,9 @@ * https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq3-ebz * * hdl_project: - * board_revision: <> + * board_revision: * - * Copyright (C) 2015-2021 Analog Devices Inc. + * Copyright (C) 2015-2022 Analog Devices Inc. */ /dts-v1/; @@ -74,7 +74,13 @@ dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&adc0_ad9680>; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_jesd 0 0>; }; + axi_ad9152_core: axi-ad9152-hpc@44a04000 { compatible = "adi,axi-ad9144-1.0"; reg = <0x44a04000 0x10000>; @@ -82,7 +88,13 @@ dma-names = "tx"; spibus-connected = <&dac0_ad9152>; adi,axi-pl-fifo-enable; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9152_jesd 1 0>; }; + axi_ad9680_jesd: axi-jesd204-rx@44aa0000 { compatible = "adi,axi-jesd204-rx-1.0"; reg = <0x44aa0000 0x4000>; @@ -92,12 +104,15 @@ clocks = <&clk_bus_0>, <&axi_ad9680_adxcvr 1>, <&axi_ad9680_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - #clock-cells = <0>; clock-output-names = "jesd_adc_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9680_adxcvr 0 0>; }; + axi_ad9680_adxcvr: axi-ad9680-adxcvr@44a50000 { compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a50000 0x10000>; @@ -111,7 +126,12 @@ #clock-cells = <1>; clock-output-names = "adc_gt_clk", "rx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; + axi_ad9152_jesd: axi-jesd204-tx@44a90000 { compatible = "adi,axi-jesd204-tx-1.0"; reg = <0x44a90000 0x4000>; @@ -121,15 +141,15 @@ clocks = <&clk_bus_0>, <&axi_ad9152_adxcvr 1>, <&axi_ad9152_adxcvr 0>; clock-names = "s_axi_aclk", "device_clk", "lane_clk"; - adi,octets-per-frame = <1>; - adi,frames-per-multiframe = <32>; - adi,converter-resolution = <16>; - adi,bits-per-sample = <16>; - adi,converters-per-device = <2>; - #clock-cells = <0>; clock-output-names = "jesd_dac_lane_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; + jesd204-inputs = <&axi_ad9152_adxcvr 1 0>; }; + axi_ad9152_adxcvr: axi-ad9152-adxcvr@44a60000 { compatible = "adi,axi-adxcvr-1.0"; reg = <0x44a60000 0x10000>; @@ -143,6 +163,10 @@ #clock-cells = <1>; clock-output-names = "dac_gt_clk", "tx_out_clk"; + + /* jesd204-fsm support */ + jesd204-device; + #jesd204-cells = <2>; }; }; From 71c2f961f6f454eee972057b62dac8550fcf21cf Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 21 Jan 2022 12:57:32 +0100 Subject: [PATCH 117/407] iio: jesd204: axi_adxcvr: adxcvr_clk_enable() don't error with bufstatus For now don't error out in case of an buf status underrun/overflow. Signed-off-by: Michael Hennerich --- drivers/iio/jesd204/axi_adxcvr.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/iio/jesd204/axi_adxcvr.c b/drivers/iio/jesd204/axi_adxcvr.c index dfb2e8fbc4edb9..4d3ddc306caba8 100644 --- a/drivers/iio/jesd204/axi_adxcvr.c +++ b/drivers/iio/jesd204/axi_adxcvr.c @@ -513,9 +513,6 @@ static int adxcvr_clk_enable(struct clk_hw *hw) adxcvr_sys_clock_sel_names[st->sys_clk_sel], st->tx_enable ? "TX" : "RX", "buffer overflow", status); - - if (bufstatus_err) - return -EIO; } return ret; From 6a6888ebe25f4aeaaeda907556f04b792ca1e46a Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 21 Jan 2022 13:19:49 +0100 Subject: [PATCH 118/407] iio: jesd204: axi_jesd204_[rx|tx]: Add some more debug information This adds some additional debug information. No functional change. Signed-off-by: Michael Hennerich --- drivers/iio/jesd204/axi_jesd204_rx.c | 9 +++++++++ drivers/iio/jesd204/axi_jesd204_tx.c | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/iio/jesd204/axi_jesd204_rx.c b/drivers/iio/jesd204/axi_jesd204_rx.c index 3b16b4a81a5fa9..07007c495bf3c1 100644 --- a/drivers/iio/jesd204/axi_jesd204_rx.c +++ b/drivers/iio/jesd204/axi_jesd204_rx.c @@ -838,6 +838,9 @@ static int axi_jesd204_rx_jesd204_link_pre_setup(struct jesd204_dev *jdev, } rate = clk_round_rate(jesd->lane_clk, lane_rate); + dev_dbg(dev, "%s: Link%u round lane rate %lu returned %ld\n", + __func__, lnk->link_id, lane_rate, rate); + if (rate != (long)lane_rate) { struct clk *parent; @@ -848,8 +851,14 @@ static int axi_jesd204_rx_jesd204_link_pre_setup(struct jesd204_dev *jdev, parent = clk_get_parent(jesd->lane_clk); rate = clk_get_rate(parent); + dev_dbg(dev, "%s: Link%u lane parent rate %ld link_rate %ld\n", + __func__, lnk->link_id, rate, link_rate); + if (rate != (long)link_rate) { rate = clk_round_rate(parent, link_rate); + dev_dbg(dev, "%s: Link%u round lane parent rate %ld\n", + __func__, lnk->link_id, rate); + if (rate == (long)link_rate) { ret = clk_set_rate(parent, link_rate); if (!ret && !IS_ERR_OR_NULL(jesd->conv2_clk)) diff --git a/drivers/iio/jesd204/axi_jesd204_tx.c b/drivers/iio/jesd204/axi_jesd204_tx.c index d020f0e9ca48f8..8cce050d754600 100644 --- a/drivers/iio/jesd204/axi_jesd204_tx.c +++ b/drivers/iio/jesd204/axi_jesd204_tx.c @@ -626,6 +626,9 @@ static int axi_jesd204_tx_jesd204_link_pre_setup(struct jesd204_dev *jdev, } rate = clk_round_rate(jesd->lane_clk, lane_rate); + dev_dbg(dev, "%s: Link%u round lane rate %lu returned %ld\n", + __func__, lnk->link_id, lane_rate, rate); + if (rate != (long)lane_rate) { struct clk *parent; @@ -636,8 +639,14 @@ static int axi_jesd204_tx_jesd204_link_pre_setup(struct jesd204_dev *jdev, parent = clk_get_parent(jesd->lane_clk); rate = clk_get_rate(parent); + dev_dbg(dev, "%s: Link%u lane parent rate %ld link_rate %ld\n", + __func__, lnk->link_id, rate, link_rate); + if (rate != (long)link_rate) { rate = clk_round_rate(parent, link_rate); + dev_dbg(dev, "%s: Link%u round lane parent rate %ld\n", + __func__, lnk->link_id, rate); + if (rate == (long)link_rate) { ret = clk_set_rate(parent, link_rate); if (!ret && !IS_ERR(jesd->conv2_clk)) From 61c357fa55d731f384bd677ed388bdede8246007 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Fri, 21 Jan 2022 19:52:54 +0200 Subject: [PATCH 119/407] iio: altera_adxcvr: Prevent clock already disabled/unprepared warnings In case st->link_clk is disabled/unprepared without being prepared/enabled previously, a warning and the backtrace will be displayed. Signed-off-by: Dragos Bogdan --- drivers/iio/jesd204/altera_adxcvr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iio/jesd204/altera_adxcvr.c b/drivers/iio/jesd204/altera_adxcvr.c index 53de5c8da57911..dabecdb7edc357 100644 --- a/drivers/iio/jesd204/altera_adxcvr.c +++ b/drivers/iio/jesd204/altera_adxcvr.c @@ -431,7 +431,8 @@ static void adxcvr_link_clk_work(struct work_struct *work) link_rate = READ_ONCE(st->lane_rate) * (1000 / 40); - clk_disable_unprepare(st->link_clk); + if (__clk_is_enabled(st->link_clk)) + clk_disable_unprepare(st->link_clk); /* * Due to rounding errors link_rate might not contain the exact rate. From 677db9fdba91a5c8826d198a989f8f17e981e8a7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 24 Jan 2022 13:59:15 +0100 Subject: [PATCH 120/407] iio: adc: ad9208: ad9208_adc_api: Fix NCO for AD9680 This patch handles the 12-bit FTW found on AD9680. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9208/ad9208_adc_api.c | 37 +++++++++++++++++++++++-- drivers/iio/adc/ad9208/api_def.h | 3 ++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad9208/ad9208_adc_api.c b/drivers/iio/adc/ad9208/ad9208_adc_api.c index d10477c2cd347e..de52e4b27be526 100644 --- a/drivers/iio/adc/ad9208/ad9208_adc_api.c +++ b/drivers/iio/adc/ad9208/ad9208_adc_api.c @@ -708,6 +708,33 @@ int ad9208_adc_set_ddc_nco_mode(ad9208_handle_t *h, return API_ERROR_OK; } +int ad9680_adc_set_ddc_nco_ftw(ad9208_handle_t *h, uint8_t ddc_ch, + uint64_t ftw, uint64_t mod_a, uint64_t mod_b) +{ + int err, offset; + uint8_t tmp_reg; + + if (h == NULL) + return API_ERROR_INVALID_HANDLE_PTR; + if (ddc_ch >= AD9208_NOF_FC_MAX) + return API_ERROR_INVALID_PARAM; + offset = (AD9208_DDCX_REG_OFFSET * ddc_ch); + + err = ad9208_register_write(h, (0x314 + offset), + ADI_GET_BYTE(ftw, 0)); + if (err != API_ERROR_OK) + return err; + err = ad9208_register_write(h, (0x315 + offset), + ADI_GET_BYTE(ftw, 8)); + if (err != API_ERROR_OK) + return err; + + ad9208_is_sync_spi_update_enabled(h, &tmp_reg); + if (tmp_reg) + ad9208_register_chip_transfer(h); + return API_ERROR_OK; +} + int ad9208_adc_set_ddc_nco_ftw(ad9208_handle_t *h, uint8_t ddc_ch, uint64_t ftw, uint64_t mod_a, uint64_t mod_b) { @@ -716,6 +743,10 @@ int ad9208_adc_set_ddc_nco_ftw(ad9208_handle_t *h, uint8_t ddc_ch, if (h == NULL) return API_ERROR_INVALID_HANDLE_PTR; + + if (h->model == 0x9680) + return ad9680_adc_set_ddc_nco_ftw(h, ddc_ch, ftw, 0, 0); + if (ddc_ch >= AD9208_NOF_FC_MAX) return API_ERROR_INVALID_PARAM; offset = (AD9208_DDCX_REG_OFFSET * ddc_ch); @@ -875,7 +906,7 @@ int ad9208_adc_set_ddc_nco(ad9208_handle_t *h, uint8_t ddc_ch, * value is integer power of 2 */ tmp_freq = DIV_U64(h->adc_clk_freq_hz, carrier_freq_hz); - tmp_freq = DIV_U64(ADI_POW2_48, tmp_freq); + tmp_freq = DIV_U64(h->model != 0x9680 ? ADI_POW2_48 : ADI_POW2_12, tmp_freq); /* Write FTW */ err = ad9208_adc_set_ddc_nco_ftw(h, ddc_ch, tmp_freq, 0, 0); @@ -905,9 +936,9 @@ int ad9208_adc_set_ddc_nco(ad9208_handle_t *h, uint8_t ddc_ch, ftw = DIV_U64(M * ((uint64_t) 1u << i), N); ftw *= ((uint64_t) 1u << (48 - i)); } else - ftw = DIV_U64(M * (ADI_POW2_48), N); + ftw = DIV_U64(M * (h->model != 0x9680 ? ADI_POW2_48 : ADI_POW2_12), N); - adi_api_utils_mult_128(M, ADI_POW2_48, &tmp_ah, &tmp_al); + adi_api_utils_mult_128(M, h->model != 0x9680 ? ADI_POW2_48 : ADI_POW2_12, &tmp_ah, &tmp_al); adi_api_utils_mod_128(tmp_ah, tmp_al, N, &tmp_fl); maw = tmp_fl; diff --git a/drivers/iio/adc/ad9208/api_def.h b/drivers/iio/adc/ad9208/api_def.h index 64dd802ec9f1a8..861d1f3c2f66c9 100644 --- a/drivers/iio/adc/ad9208/api_def.h +++ b/drivers/iio/adc/ad9208/api_def.h @@ -20,6 +20,9 @@ #define ADI_POW2_48 ((uint64_t)1u << 48) #define ADI_MAXUINT48 (ADI_POW2_48 - 1) +#define ADI_POW2_12 ((uint64_t)1u << 12) +#define ADI_MAXUINT12 (ADI_POW2_12 - 1) + #define ADI_POW2_32 ((uint64_t)1u << 32) #define ADI_MAXUINT32 (ADI_POW2_32 - 1) #define ADI_MAXUINT24 (0xFFFFFF) From 0a1d0c107181f4b5c0382dee04508b1835615873 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 24 Jan 2022 14:03:02 +0100 Subject: [PATCH 121/407] iio: adc: ad9208: ad9208_jesd_api: AD9680 JESD M,L,F set via quick conf On AD9680 M, L and F can only be set via the quick configuration register. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9208/ad9208_jesd_api.c | 10 ++++++++++ drivers/iio/adc/ad9208/ad9208_reg.h | 1 + 2 files changed, 11 insertions(+) diff --git a/drivers/iio/adc/ad9208/ad9208_jesd_api.c b/drivers/iio/adc/ad9208/ad9208_jesd_api.c index dd4906206eadeb..0c30a7f9002ea0 100644 --- a/drivers/iio/adc/ad9208/ad9208_jesd_api.c +++ b/drivers/iio/adc/ad9208/ad9208_jesd_api.c @@ -218,6 +218,16 @@ int ad9208_jesd_set_if_config(ad9208_handle_t *h, if (err != API_ERROR_OK) return err; + if (h->model == 0x9680) { + tmp_reg = ilog2(jesd_param.jesd_F); + tmp_reg |= ilog2(jesd_param.jesd_M) << 3; + tmp_reg |= ilog2(jesd_param.jesd_L) << 6; + + err = ad9208_register_write(h, AD9680_JESD_QUICK_CONF_REG, tmp_reg); + if (err != API_ERROR_OK) + return err; + } + /*Set NOF Converters */ err = ad9208_register_write(h, AD9208_JESD_M_CFG_REG, diff --git a/drivers/iio/adc/ad9208/ad9208_reg.h b/drivers/iio/adc/ad9208/ad9208_reg.h index 0a867597e24366..85f6fd28597528 100644 --- a/drivers/iio/adc/ad9208/ad9208_reg.h +++ b/drivers/iio/adc/ad9208/ad9208_reg.h @@ -268,5 +268,6 @@ int ad9208_is_sync_spi_update_enabled(ad9208_handle_t *h, uint8_t *enabled); #define AD9680_CLOCK_DIV_REG 0x10B #define AD9680_CLOCK_DIV_PHASE_REG 0x10C #define AD9680_INPUT_FS_RANGE_REG 0x025 +#define AD9680_JESD_QUICK_CONF_REG 0x570 #endif /*__AD9208_REG_H__*/ From 32af9cfdac0e8243ff257e8d32881b28aaaaca5c Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 24 Jan 2022 14:07:13 +0100 Subject: [PATCH 122/407] iio: adc: ad9208: IIO_CHAN_INFO_SAMP_FREQ use chip decimation In order to retain the proper sampling_frequency we need to take the chip decimation into account. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9208.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ad9208.c b/drivers/iio/adc/ad9208.c index 6240d91cefca34..57d1842e812c17 100644 --- a/drivers/iio/adc/ad9208.c +++ b/drivers/iio/adc/ad9208.c @@ -1026,16 +1026,20 @@ static int ad9208_read_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long info) { struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev); + struct ad9208_phy *phy = conv->phy; + u64 freq; + int ret; switch (info) { case IIO_CHAN_INFO_SCALE: return ad9208_get_scale(conv, val, val2); case IIO_CHAN_INFO_SAMP_FREQ: - if (!conv->clk) - return -ENODEV; + ret = ad9208_get_adc_clk_freq(&phy->ad9208, &freq); + if (ret) + return ret; - *val = conv->adc_clk = clk_get_rate_scaled(conv->clk, - &conv->adc_clkscale); + do_div(freq, phy->dcm); + *val = conv->adc_clk = freq; return IIO_VAL_INT; } From f0198b559c47a63c06c3b3d13c879cb0d9cc07be Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 24 Jan 2022 14:23:02 +0100 Subject: [PATCH 123/407] dts: zynqmp-zcu102-rev10-fmcdaq2_m4_l4: Add DDC/DUC & NCO example This uses the new parameterize JESD204 configuration feature in the DAQ2 HDL project. // Synthesis parameter: // RX_JESD_M = 4 // RX_JESD_L = 4 // RX_JESD_S = 1 // TX_JESD_M = 4 // TX_JESD_L = 4 // TX_JESD_S = 1 Signed-off-by: Michael Hennerich --- .../zynqmp-zcu102-rev10-fmcdaq2_m4_l4.dts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq2_m4_l4.dts diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq2_m4_l4.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq2_m4_l4.dts new file mode 100644 index 00000000000000..7f762d2b41ef9b --- /dev/null +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-fmcdaq2_m4_l4.dts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD-FMCDAQ2-EBZ using M4, L4 + * Link: https://wiki.analog.com/resources/eval/user-guides/ad-fmcdaq2-ebz + * + * hdl_project: + * board_revision: + * + * Copyright 2022 Analog Devices Inc. + */ + +#include "zynqmp-zcu102-rev10-fmcdaq2.dts" + +// Synthesis parameter: +// RX_JESD_M = 4 +// RX_JESD_L = 4 +// RX_JESD_S = 1 +// TX_JESD_M = 4 +// TX_JESD_L = 4 +// TX_JESD_S = 1 + +&dac0_ad9144 { + adi,jesd-link-mode = <2>; + adi,interpolation = <2>; + + adi,frequency-center-shift = <100000000>; +}; + +&adc0_ad9680 { + adi,converters-per-device = <4>; /* JESD204 (M) */ + adi,octets-per-frame = <2>; /* JESD204 (F) */ + + /* DDC setup */ + adi,ddc-channel-number = ; + ad9208_ddc0: channel@0 { + reg = <0>; + adi,decimation = <4>; + adi,nco-mode-select = ; + adi,nco-channel-carrier-frequency-hz = /bits/ 64 <100000000>; + adi,nco-channel-phase-offset = /bits/ 64 <0>; + }; + + ad9208_ddc1: channel@1 { + reg = <1>; + adi,decimation = <4>; + adi,nco-mode-select = ; + adi,nco-channel-carrier-frequency-hz = /bits/ 64 <100000000>; + adi,nco-channel-phase-offset = /bits/ 64 <0>; + }; +}; From 03f03be4e1121d80e07a769ffa8e5b03a1748ad2 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 24 Jan 2022 08:45:20 +0100 Subject: [PATCH 124/407] dts: ad908x: Fix dt property - rename adi,nco-mode -> adi,nco-mixer-mode Rename adi,nco-mode -> adi,nco-mixer-mode in order to reflect the latest ad9081 driver code. Signed-off-by: Michael Hennerich --- arch/arm/boot/dts/adi-ad9081-fmc-ebz.dtsi | 8 ++--- .../dts/socfpga_arria10_socdk_ad9081_np12.dts | 8 ++--- .../dts/zynq-zc706-adv7511-ad9081-np12.dts | 8 ++--- ...190-reva-ad9081-204c-txmode22-rxmode23.dts | 2 +- .../dts/xilinx/versal-vck190-reva-ad9081.dts | 4 +-- ...u102-rev10-ad9081-204b-txmode9-rxmode4.dts | 8 ++--- ...u102-rev10-ad9081-204c-txmode0-rxmode1.dts | 8 ++--- ...nqmp-zcu102-rev10-ad9081-m8-l4-overlay.dts | 8 ++--- ...ynqmp-zcu102-rev10-ad9081-m8-l4-qpllrx.dts | 8 ++--- .../zynqmp-zcu102-rev10-ad9081-m8-l4.dts | 8 ++--- ...-204c-txmode22-rxmode23-dual-multi-top.dts | 4 +-- ...v10-ad9082-204c-txmode22-rxmode23-dual.dts | 4 +-- ...02-rev10-ad9082-204c-txmode22-rxmode23.dts | 2 +- .../zynqmp-zcu102-rev10-ad9082-m4-l8.dts | 4 +-- .../dts/xilinx/zynqmp-zcu102-rev10-ad9208.dts | 2 +- .../zynqmp-zcu102-rev10-ad9988-fmcb-m8-l4.dts | 8 ++--- ...vcu118_ad9081_204c_txmode_10_rxmode_11.dts | 4 +-- ..._204c_txmode_10_rxmode_11_lr_24_75Gbps.dts | 4 +-- ...vcu118_ad9081_204c_txmode_23_rxmode_25.dts | 4 +-- ..._204c_txmode_23_rxmode_25_lr_24_75Gbps.dts | 4 +-- ..._204c_txmode_24_rxmode_26_lr_24_75Gbps.dts | 8 ++--- .../boot/dts/vcu118_ad9081_m8_l4.dts | 8 ++--- ...18_quad_ad9081_204b_txmode_9_rxmode_10.dts | 32 +++++++++---------- ...8_quad_ad9081_204c_txmode_10_rxmode_11.dts | 16 +++++----- ...18_quad_ad9081_204c_txmode_11_rxmode_4.dts | 32 +++++++++---------- ...9081_204c_txmode_11_rxmode_4_direct_6g.dts | 32 +++++++++---------- ...d_ad9081_204c_txmode_23_rxmode_25_revc.dts | 16 +++++----- ...d_ad9081_204c_txmode_29_rxmode_24_revc.dts | 32 +++++++++---------- ...8_quad_ad9082_204c_txmode_12_rxmode_13.dts | 8 ++--- ...8_quad_ad9082_204c_txmode_23_rxmode_25.dts | 16 +++++----- ...118_quad_ad9082_204c_txmode_3_rxmode_2.dts | 16 +++++----- .../boot/dts/vcu128_ad9081_m8_l4.dts | 8 ++--- 32 files changed, 167 insertions(+), 167 deletions(-) diff --git a/arch/arm/boot/dts/adi-ad9081-fmc-ebz.dtsi b/arch/arm/boot/dts/adi-ad9081-fmc-ebz.dtsi index a1024d47aa093e..2860e774005e5e 100644 --- a/arch/arm/boot/dts/adi-ad9081-fmc-ebz.dtsi +++ b/arch/arm/boot/dts/adi-ad9081-fmc-ebz.dtsi @@ -258,25 +258,25 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc2: adc@2 { reg = <2>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc3: adc@3 { reg = <3>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; }; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_ad9081_np12.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_ad9081_np12.dts index e41bc69aaaf5bc..fb633f6659d8b8 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_ad9081_np12.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_ad9081_np12.dts @@ -178,25 +178,25 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc2: adc@2 { reg = <2>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc3: adc@3 { reg = <3>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; }; diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9081-np12.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9081-np12.dts index 068fdcf6f51699..2140c61731becc 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9081-np12.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9081-np12.dts @@ -234,25 +234,25 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc2: adc@2 { reg = <2>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc3: adc@3 { reg = <3>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; }; diff --git a/arch/arm64/boot/dts/xilinx/versal-vck190-reva-ad9081-204c-txmode22-rxmode23.dts b/arch/arm64/boot/dts/xilinx/versal-vck190-reva-ad9081-204c-txmode22-rxmode23.dts index 4d159b3ffb6c81..dbcaf28623206b 100644 --- a/arch/arm64/boot/dts/xilinx/versal-vck190-reva-ad9081-204c-txmode22-rxmode23.dts +++ b/arch/arm64/boot/dts/xilinx/versal-vck190-reva-ad9081-204c-txmode22-rxmode23.dts @@ -284,7 +284,7 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; }; diff --git a/arch/arm64/boot/dts/xilinx/versal-vck190-reva-ad9081.dts b/arch/arm64/boot/dts/xilinx/versal-vck190-reva-ad9081.dts index 762db30a39a648..621217c9333f5b 100644 --- a/arch/arm64/boot/dts/xilinx/versal-vck190-reva-ad9081.dts +++ b/arch/arm64/boot/dts/xilinx/versal-vck190-reva-ad9081.dts @@ -445,13 +445,13 @@ reg = <0>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; }; adi,channelizer-paths { diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-204b-txmode9-rxmode4.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-204b-txmode9-rxmode4.dts index ce02858c41e285..c7314a57f46f06 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-204b-txmode9-rxmode4.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-204b-txmode9-rxmode4.dts @@ -304,28 +304,28 @@ reg = <0>; adi,decimation = <6>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 1000 MHz */ - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <6>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 1000 MHz */ - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ }; ad9081_adc2: adc@2 { reg = <2>; adi,decimation = <6>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 1000 MHz */ - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan4>, <&ad9081_rx_fddc_chan6>; /* Static for now */ }; ad9081_adc3: adc@3 { reg = <3>; adi,decimation = <6>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 1000 MHz */ - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan5>, <&ad9081_rx_fddc_chan7>; /* Static for now */ }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-204c-txmode0-rxmode1.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-204c-txmode0-rxmode1.dts index 71479ce7e6ad76..a90f2ee4d457a2 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-204c-txmode0-rxmode1.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-204c-txmode0-rxmode1.dts @@ -307,7 +307,7 @@ reg = <0>; adi,decimation = <6>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 1000 MHz */ - adi,nco-mode = ; + adi,nco-mixer-mode = ; adi,digital-gain-6db-enable; //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ }; @@ -315,7 +315,7 @@ reg = <1>; adi,decimation = <6>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 1000 MHz */ - adi,nco-mode = ; + adi,nco-mixer-mode = ; adi,digital-gain-6db-enable; //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ }; @@ -323,7 +323,7 @@ reg = <2>; adi,decimation = <6>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 1000 MHz */ - adi,nco-mode = ; + adi,nco-mixer-mode = ; adi,digital-gain-6db-enable; //adi,crossbar-select = <&ad9081_rx_fddc_chan4>, <&ad9081_rx_fddc_chan6>; /* Static for now */ }; @@ -331,7 +331,7 @@ reg = <3>; adi,decimation = <6>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 1000 MHz */ - adi,nco-mode = ; + adi,nco-mixer-mode = ; adi,digital-gain-6db-enable; //adi,crossbar-select = <&ad9081_rx_fddc_chan5>, <&ad9081_rx_fddc_chan7>; /* Static for now */ }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-overlay.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-overlay.dts index 2429f14c75cfc8..e633cdb4f20b37 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-overlay.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-overlay.dts @@ -297,28 +297,28 @@ reg = <0>; adi,decimation = <3>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <3>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ }; ad9081_adc2: adc@2 { reg = <2>; adi,decimation = <3>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan4>, <&ad9081_rx_fddc_chan6>; /* Static for now */ }; ad9081_adc3: adc@3 { reg = <3>; adi,decimation = <3>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan5>, <&ad9081_rx_fddc_chan7>; /* Static for now */ }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-qpllrx.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-qpllrx.dts index d8be4c615af6cd..b1501882a0e5b7 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-qpllrx.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-qpllrx.dts @@ -347,28 +347,28 @@ reg = <0>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ }; ad9081_adc2: adc@2 { reg = <2>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan4>, <&ad9081_rx_fddc_chan6>; /* Static for now */ }; ad9081_adc3: adc@3 { reg = <3>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan5>, <&ad9081_rx_fddc_chan7>; /* Static for now */ }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4.dts index baac4463186069..13ec7b80bc9ef4 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4.dts @@ -260,28 +260,28 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ }; ad9081_adc2: adc@2 { reg = <2>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan4>, <&ad9081_rx_fddc_chan6>; /* Static for now */ }; ad9081_adc3: adc@3 { reg = <3>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan5>, <&ad9081_rx_fddc_chan7>; /* Static for now */ }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts index fb39a02c263ed5..b9248ebda0b72c 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts @@ -538,14 +538,14 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <(1000000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts index 34127561c9a8b0..e6911b75ade197 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts @@ -480,14 +480,14 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <(1000000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23.dts index 09a224f133c071..b6ca0e8e9b4bcd 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23.dts @@ -283,7 +283,7 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-m4-l8.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-m4-l8.dts index 3e2b44e8318cfe..7e96586af9017b 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-m4-l8.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-m4-l8.dts @@ -245,14 +245,14 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <(1000000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9208.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9208.dts index 0305a274975621..b3d1d45eac7f47 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9208.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9208.dts @@ -167,7 +167,7 @@ ad9208_ddc0: channel@0 { reg = <0>; adi,decimation = <2>; - adi,nco-mode-select = ; + adi,nco-mixer-mode-select = ; adi,nco-channel-carrier-frequency-hz = /bits/ 64 <70000000>; adi,nco-channel-phase-offset = /bits/ 64 <0>; adi,ddc-gain-6dB-enable; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9988-fmcb-m8-l4.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9988-fmcb-m8-l4.dts index 44a6abede75c9a..b0af7e23325974 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9988-fmcb-m8-l4.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9988-fmcb-m8-l4.dts @@ -282,28 +282,28 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <250000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <500000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ }; ad9081_adc2: adc@2 { reg = <2>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan4>, <&ad9081_rx_fddc_chan6>; /* Static for now */ }; ad9081_adc3: adc@3 { reg = <3>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <1500000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan5>, <&ad9081_rx_fddc_chan7>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11.dts b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11.dts index 64604511f2dd64..72416d4858333c 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11.dts @@ -225,14 +225,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx0_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11_lr_24_75Gbps.dts b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11_lr_24_75Gbps.dts index e9aa4b88c1a113..2c0360161129d2 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11_lr_24_75Gbps.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11_lr_24_75Gbps.dts @@ -224,14 +224,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx0_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25.dts b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25.dts index 9f44c97ad96a52..a3bf93e70f05ee 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25.dts @@ -175,13 +175,13 @@ reg = <0>; adi,decimation = <3>; adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <3>; adi,nco-frequency-shift-hz = /bits/ 64 <(1100000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; }; adi,channelizer-paths { diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps.dts b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps.dts index 5eebba5439482f..4dc05550798cd2 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps.dts @@ -171,13 +171,13 @@ reg = <0>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; }; adi,channelizer-paths { diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_24_rxmode_26_lr_24_75Gbps.dts b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_24_rxmode_26_lr_24_75Gbps.dts index 7b04c15a9472e9..4eb25d95234338 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_24_rxmode_26_lr_24_75Gbps.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_24_rxmode_26_lr_24_75Gbps.dts @@ -192,25 +192,25 @@ reg = <0>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc2: adc@2 { reg = <2>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; ad9081_adc3: adc@3 { reg = <3>; adi,decimation = <2>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; }; }; adi,channelizer-paths { diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_m8_l4.dts b/arch/microblaze/boot/dts/vcu118_ad9081_m8_l4.dts index 035aa0f73803b9..732842a2e10887 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_m8_l4.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_m8_l4.dts @@ -184,28 +184,28 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ }; ad9081_adc2: adc@2 { reg = <2>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan4>, <&ad9081_rx_fddc_chan6>; /* Static for now */ }; ad9081_adc3: adc@3 { reg = <3>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan5>, <&ad9081_rx_fddc_chan7>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts index 2178c23cf4d281..74256459462bf2 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts @@ -301,28 +301,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx0_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx0_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan4>, <&trx0_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx0_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan5>, <&trx0_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -476,28 +476,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan0>, <&trx1_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx1_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan1>, <&trx1_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx1_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan4>, <&trx1_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx1_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan5>, <&trx1_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -651,28 +651,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan0>, <&trx2_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx2_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan1>, <&trx2_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx2_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan4>, <&trx2_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx2_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan5>, <&trx2_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -826,28 +826,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan0>, <&trx3_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx3_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan1>, <&trx3_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx3_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan4>, <&trx3_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx3_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan5>, <&trx3_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts index 4613dc9b6bfffe..5595383d8a2aeb 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts @@ -313,14 +313,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx0_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -442,14 +442,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan0>, <&trx1_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx1_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan1>, <&trx1_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -571,14 +571,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan0>, <&trx2_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx2_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan1>, <&trx2_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -700,14 +700,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan0>, <&trx3_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx3_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan1>, <&trx3_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts index 1d4764928130cf..c97c9f0a3b7411 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts @@ -354,28 +354,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx0_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx0_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan4>, <&trx0_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx0_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan5>, <&trx0_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -550,28 +550,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan0>, <&trx1_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx1_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan1>, <&trx1_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx1_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan4>, <&trx1_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx1_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan5>, <&trx1_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -746,28 +746,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan0>, <&trx2_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx2_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan1>, <&trx2_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx2_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan4>, <&trx2_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx2_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan5>, <&trx2_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -942,28 +942,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan0>, <&trx3_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx3_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan1>, <&trx3_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx3_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan4>, <&trx3_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx3_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan5>, <&trx3_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts index 65cdfaaa6ff011..ca7a0b523fb7a2 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts @@ -360,28 +360,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx0_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx0_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan4>, <&trx0_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx0_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan5>, <&trx0_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -561,28 +561,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan0>, <&trx1_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx1_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan1>, <&trx1_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx1_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan4>, <&trx1_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx1_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan5>, <&trx1_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -762,28 +762,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan0>, <&trx2_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx2_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan1>, <&trx2_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx2_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan4>, <&trx2_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx2_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan5>, <&trx2_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -963,28 +963,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan0>, <&trx3_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx3_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan1>, <&trx3_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx3_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan4>, <&trx3_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx3_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan5>, <&trx3_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts index 7fd76a56a2b552..a0d65195de64ca 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts @@ -388,14 +388,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx0_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -520,14 +520,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan0>, <&trx1_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx1_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan1>, <&trx1_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -652,14 +652,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan0>, <&trx2_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx2_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan1>, <&trx2_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -784,14 +784,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan0>, <&trx3_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx3_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan1>, <&trx3_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts index ae161aac5dd29a..52d52e9f264d46 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts @@ -406,28 +406,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx0_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx0_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan4>, <&trx0_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx0_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan5>, <&trx0_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -585,28 +585,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan0>, <&trx1_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx1_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan1>, <&trx1_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx1_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan4>, <&trx1_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx1_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan5>, <&trx1_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -764,28 +764,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan0>, <&trx2_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx2_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan1>, <&trx2_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx2_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan4>, <&trx2_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx2_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan5>, <&trx2_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -943,28 +943,28 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan0>, <&trx3_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx3_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan1>, <&trx3_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx3_ad9081_adc2: adc@2 { reg = <2>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan4>, <&trx3_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx3_ad9081_adc3: adc@3 { reg = <3>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan5>, <&trx3_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts index d3afd7e593d4a1..898c7b872fb649 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts @@ -351,7 +351,7 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; }; @@ -460,7 +460,7 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan0>, <&trx1_ad9081_rx_fddc_chan2>; /* Static for now */ }; }; @@ -569,7 +569,7 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan0>, <&trx2_ad9081_rx_fddc_chan2>; /* Static for now */ }; }; @@ -678,7 +678,7 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan0>, <&trx3_ad9081_rx_fddc_chan2>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts index d99e6f5d7eaaa0..e4f6a1e10cc829 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts @@ -374,14 +374,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx0_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -507,14 +507,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan0>, <&trx1_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx1_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan1>, <&trx1_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -640,14 +640,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan0>, <&trx2_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx2_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan1>, <&trx2_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -773,14 +773,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan0>, <&trx3_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx3_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan1>, <&trx3_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts index 9ac3747fcbe509..0c4a9372c5c2c3 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts @@ -375,14 +375,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx0_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -526,14 +526,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan0>, <&trx1_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx1_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan1>, <&trx1_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -677,14 +677,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan0>, <&trx2_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx2_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan1>, <&trx2_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; @@ -828,14 +828,14 @@ reg = <0>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan0>, <&trx3_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx3_ad9081_adc1: adc@1 { reg = <1>; adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan1>, <&trx3_ad9081_rx_fddc_chan3>; /* Static for now */ }; }; diff --git a/arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts b/arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts index c5bfec03637e73..d6487dc02c374c 100644 --- a/arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts +++ b/arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts @@ -184,28 +184,28 @@ reg = <0>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan0>, <&ad9081_rx_fddc_chan2>; /* Static for now */ }; ad9081_adc1: adc@1 { reg = <1>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <(-400000000)>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan1>, <&ad9081_rx_fddc_chan3>; /* Static for now */ }; ad9081_adc2: adc@2 { reg = <2>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan4>, <&ad9081_rx_fddc_chan6>; /* Static for now */ }; ad9081_adc3: adc@3 { reg = <3>; adi,decimation = <4>; adi,nco-frequency-shift-hz = /bits/ 64 <100000000>; - adi,nco-mode = ; + adi,nco-mixer-mode = ; //adi,crossbar-select = <&ad9081_rx_fddc_chan5>, <&ad9081_rx_fddc_chan7>; /* Static for now */ }; }; From 9923944e06dd64a9cd28db758991d7d63aefbf6e Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Fri, 21 Jan 2022 13:57:28 +0200 Subject: [PATCH 125/407] iio: core: Update symbolic label with upstream If a label is defined in the device tree for this channel add that to the channel specific attributes. This is useful for userspace to be able to identify an individual channel. Signed-off-by: Cristian Pop Link: https://lore.kernel.org/r/20200928090959.88842-1-cristian.pop@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 52 +++++++++++++++++++++++++++------ include/linux/iio/iio.h | 8 +++-- include/linux/iio/types.h | 1 - 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 48be9f1d8fde47..f25c71d1aec695 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -141,7 +141,6 @@ static const char * const iio_modifier_names[] = { /* relies on pairs of these shared then separate */ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_RAW] = "raw", - [IIO_CHAN_INFO_LABEL] = "label", [IIO_CHAN_INFO_PROCESSED] = "input", [IIO_CHAN_INFO_SCALE] = "scale", [IIO_CHAN_INFO_OFFSET] = "offset", @@ -684,6 +683,19 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) } EXPORT_SYMBOL_GPL(iio_format_value); +static ssize_t iio_read_channel_label(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + if (!indio_dev->info->read_label) + return -EINVAL; + + return indio_dev->info->read_label(indio_dev, this_attr->c, buf); +} + static ssize_t iio_read_channel_info(struct device *dev, struct device_attribute *attr, char *buf) @@ -694,19 +706,14 @@ static ssize_t iio_read_channel_info(struct device *dev, int ret; int val_len = 2; - if (indio_dev->info->read_raw_multi) { + if (indio_dev->info->read_raw_multi) ret = indio_dev->info->read_raw_multi(indio_dev, this_attr->c, INDIO_MAX_RAW_ELEMENTS, vals, &val_len, this_attr->address); - } else { - if (this_attr->address == IIO_CHAN_INFO_LABEL && - this_attr->c->label_name) - return sprintf(buf, "%s\n", this_attr->c->label_name); - + else ret = indio_dev->info->read_raw(indio_dev, this_attr->c, &vals[0], &vals[1], this_attr->address); - } if (ret < 0) return ret; @@ -1157,6 +1164,29 @@ int __iio_add_chan_devattr(const char *postfix, return ret; } +static int iio_device_add_channel_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + int ret; + + if (!indio_dev->info->read_label) + return 0; + + ret = __iio_add_chan_devattr("label", + chan, + &iio_read_channel_label, + NULL, + 0, + IIO_SEPARATE, + &indio_dev->dev, + &iio_dev_opaque->channel_attr_list); + if (ret < 0) + return ret; + + return 1; +} + static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, enum iio_shared_by shared_by, @@ -1290,6 +1320,11 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, return ret; attrcount += ret; + ret = iio_device_add_channel_label(indio_dev, chan); + if (ret < 0) + return ret; + attrcount += ret; + if (chan->ext_info) { unsigned int i = 0; for (ext_info = chan->ext_info; ext_info->name; ext_info++) { @@ -1449,7 +1484,6 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) attrcount_orig++; } attrcount = attrcount_orig; - /* * New channel registration method - relies on the fact a group does * not need to be initialized if its name is NULL. diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 65a1679ea7f8ae..4c785797203aa6 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -240,7 +240,6 @@ struct iio_event_spec { * correspond to the first name that the channel is referred * to by in the datasheet (e.g. IND), or the nearest * possible compound name (e.g. IND-INC). - * @label_name: Unique name to identify which channel this is. * @modified: Does a modifier apply to this channel. What these are * depends on the channel type. Modifier is set in * channel2. Examples are IIO_MOD_X for axial sensors about @@ -278,7 +277,6 @@ struct iio_chan_spec { const struct iio_chan_spec_ext_info *ext_info; const char *extend_name; const char *datasheet_name; - const char *label_name; unsigned modified:1; unsigned indexed:1; unsigned output:1; @@ -386,6 +384,8 @@ struct iio_trigger; /* forward declaration */ * and max. For lists, all possible values are enumerated. * @write_raw: function to write a value to the device. * Parameters are the same as for read_raw. + * @read_label: function to request label name for a specified label, + * for better channel identification. * @write_raw_get_fmt: callback function to query the expected * format/precision. If not set by the driver, write_raw * returns IIO_VAL_INT_PLUS_MICRO. @@ -444,6 +444,10 @@ struct iio_info { int val2, long mask); + int (*read_label)(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + char *label); + int (*write_raw_get_fmt)(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, long mask); diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 4f3d112929cc96..6297ebf2743b9f 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -34,7 +34,6 @@ enum iio_available_type { enum iio_chan_info_enum { IIO_CHAN_INFO_RAW = 0, - IIO_CHAN_INFO_LABEL, IIO_CHAN_INFO_PROCESSED, IIO_CHAN_INFO_SCALE, IIO_CHAN_INFO_OFFSET, From 88c34541d05669086abf9d47329c9156a1ae1db1 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Fri, 21 Jan 2022 14:49:34 +0200 Subject: [PATCH 126/407] drivers: iio: addac: one-bit-adc-dac: Update label storage Update accordingly to upstream version of channel label implementation. Signed-off-by: Cristian Pop --- drivers/iio/addac/one-bit-adc-dac.c | 39 ++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/drivers/iio/addac/one-bit-adc-dac.c b/drivers/iio/addac/one-bit-adc-dac.c index 5e0158384b3a26..24a650602f9358 100644 --- a/drivers/iio/addac/one-bit-adc-dac.c +++ b/drivers/iio/addac/one-bit-adc-dac.c @@ -18,9 +18,12 @@ enum ch_direction { }; struct one_bit_adc_dac_state { + int in_num_ch; + int out_num_ch; struct platform_device *pdev; struct gpio_descs *in_gpio_descs; struct gpio_descs *out_gpio_descs; + const char **labels; }; static int one_bit_adc_dac_read_raw(struct iio_dev *indio_dev, @@ -65,9 +68,24 @@ static int one_bit_adc_dac_write_raw(struct iio_dev *indio_dev, } } +static int one_bit_adc_dac_read_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, char *label) +{ + struct one_bit_adc_dac_state *st = iio_priv(indio_dev); + int ch; + + if (chan->output) + ch = chan->channel + st->in_num_ch; + else + ch = chan->channel; + + return sprintf(label, "%s\n", st->labels[ch]); +} + static const struct iio_info one_bit_adc_dac_info = { .read_raw = &one_bit_adc_dac_read_raw, .write_raw = &one_bit_adc_dac_write_raw, + .read_label = &one_bit_adc_dac_read_label, }; static int one_bit_adc_dac_set_ch(struct iio_chan_spec *channels, @@ -87,17 +105,23 @@ static int one_bit_adc_dac_set_ch(struct iio_chan_spec *channels, return 0; } -static void one_bit_adc_dac_set_channel_label(struct device *device, +static int one_bit_adc_dac_set_channel_label(struct iio_dev *indio_dev, struct iio_chan_spec *channels, int num_channels) { + struct device *device = indio_dev->dev.parent; + struct one_bit_adc_dac_state *st = iio_priv(indio_dev); struct fwnode_handle *fwnode; struct fwnode_handle *child; - struct iio_chan_spec *chan; const char *label; int crt_ch = 0; fwnode = dev_fwnode(device); + + st->labels = devm_kcalloc(device, num_channels, sizeof(*st->labels), GFP_KERNEL); + if (!st->labels) + return -ENOMEM; + fwnode_for_each_child_node(fwnode, child) { if (fwnode_property_read_u32(child, "reg", &crt_ch)) continue; @@ -108,10 +132,10 @@ static void one_bit_adc_dac_set_channel_label(struct device *device, if (fwnode_property_read_string(child, "label", &label)) continue; - chan = &channels[crt_ch]; - chan->info_mask_separate |= BIT(IIO_CHAN_INFO_LABEL); - chan->label_name = label; + st->labels[crt_ch] = label; } + + return 0; } static int one_bit_adc_dac_parse_dt(struct iio_dev *indio_dev) @@ -147,7 +171,10 @@ static int one_bit_adc_dac_parse_dt(struct iio_dev *indio_dev) if (ret) return ret; - one_bit_adc_dac_set_channel_label(indio_dev->dev.parent, channels, in_num_ch + out_num_ch); + ret = one_bit_adc_dac_set_channel_label(indio_dev, channels, in_num_ch + out_num_ch); + if (ret) + return ret; + indio_dev->channels = channels; indio_dev->num_channels = in_num_ch + out_num_ch; From 056244f4e75171f10ada589a1fbb09e436230043 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 26 Jan 2022 09:35:55 +0200 Subject: [PATCH 127/407] drivers: iio: adc: ad9081: Update label storage Update accordingly to upstream version of channel label implementation. Signed-off-by: Cristian Pop Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 6baeacef52153b..8d351e003c443f 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -162,6 +162,9 @@ struct ad9081_phy { struct delayed_work dwork; + const char **rx_labels; + const char **tx_labels; + u32 mcs_cached_val; u32 multidevice_instance_count; @@ -2155,6 +2158,16 @@ static int ad9081_write_raw(struct iio_dev *indio_dev, return 0; } +static int ad9081_read_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, char *label) +{ + struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev); + struct ad9081_phy *phy = conv->phy; + + return sprintf(label, "%s\n", + chan->output ? phy->tx_labels[chan->channel] : + phy->rx_labels[chan->channel]); +} static const char* const ffh_modes[] = { "phase_continuous", "phase_incontinuous", "phase_coherent" @@ -3931,6 +3944,12 @@ static int ad9081_setup_chip_info_tbl(struct ad9081_phy *phy, return -EINVAL; } + phy->rx_labels = devm_kcalloc(&phy->spi->dev, + m * phy->multidevice_instance_count, + sizeof(*phy->rx_labels), GFP_KERNEL); + if (!phy->rx_labels) + return -ENOMEM; + for (c = 0, i = 0; i < (m * phy->multidevice_instance_count); i++, c++) { phy->chip_info.channel[c].type = IIO_VOLTAGE; @@ -3957,19 +3976,23 @@ static int ad9081_setup_chip_info_tbl(struct ad9081_phy *phy, phy->chip_info.channel[c].scan_type.storagebits = (phy->jtx_link_rx[0].jesd_param.jesd_np > 8) ? 16 : 8; phy->chip_info.channel[c].scan_type.sign = 's'; - phy->chip_info.channel[c].info_mask_separate |= BIT(IIO_CHAN_INFO_LABEL); if (i < m) { phy->chip_info.channel[c].ext_info = rxadc_ext_info; - phy->chip_info.channel[c].label_name = + phy->rx_labels[phy->chip_info.channel[c].channel] = ad9081_lable_writer(phy, &phy->chip_info.channel[c]); } else { - phy->chip_info.channel[c].label_name = "buffer_only"; + phy->rx_labels[phy->chip_info.channel[c].channel] = "buffer_only"; } } m = phy->jrx_link_tx[0].jesd_param.jesd_m * - (ad9081_link_is_dual(phy->jrx_link_tx) ? 2 : 1); + (ad9081_link_is_dual(phy->jrx_link_tx) ? 2 : 1); + + phy->tx_labels = devm_kcalloc(&phy->spi->dev, m, + sizeof(*phy->tx_labels), GFP_KERNEL); + if (!phy->tx_labels) + return -ENOMEM; for (i = 0; i < m; i++, c++) { phy->chip_info.channel[c].type = IIO_VOLTAGE; @@ -3984,11 +4007,11 @@ static int ad9081_setup_chip_info_tbl(struct ad9081_phy *phy, BIT(IIO_CHAN_INFO_SAMP_FREQ); phy->chip_info.channel[c].info_mask_separate = - BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_LABEL); + BIT(IIO_CHAN_INFO_ENABLE); phy->chip_info.channel[c].ext_info = txdac_ext_info; - phy->chip_info.channel[c].label_name = ad9081_lable_writer(phy, - &phy->chip_info.channel[c]); + phy->tx_labels[phy->chip_info.channel[c].channel] = + ad9081_lable_writer(phy, &phy->chip_info.channel[c]); } phy->chip_info.channel[c].type = IIO_TEMP; @@ -4007,6 +4030,7 @@ static int ad9081_setup_chip_info_tbl(struct ad9081_phy *phy, static const struct iio_info ad9081_iio_info = { .read_raw = &ad9081_read_raw, .write_raw = &ad9081_write_raw, + .read_label = &ad9081_read_label, .debugfs_reg_access = &ad9081_reg_access, .attrs = &ad9081_phy_attribute_group, }; From 8ece9df55f2d525deb4e555c29d425c3f5d858fe Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 26 Jan 2022 09:43:24 +0200 Subject: [PATCH 128/407] iio:beamformer:adar300x: Remove channel label This property was redundant and set with the name of the channel and is not necessary, it also uses the old implementation of channel label. Signed-off-by: Cristian Pop --- drivers/iio/beamformer/adar300x.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/iio/beamformer/adar300x.c b/drivers/iio/beamformer/adar300x.c index a80f7c285c0710..e0eaac405b3d41 100644 --- a/drivers/iio/beamformer/adar300x.c +++ b/drivers/iio/beamformer/adar300x.c @@ -182,9 +182,7 @@ .channel = (_num), \ .address = (_id), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_LABEL), \ - .label_name = name, \ + BIT(IIO_CHAN_INFO_SCALE), \ .scan_index = (_id), \ .scan_type = { \ .sign = 'u', \ @@ -202,9 +200,7 @@ .channel = (_num), \ .address = (_id), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_LABEL), \ - .label_name = name, \ + BIT(IIO_CHAN_INFO_SCALE), \ .scan_index = (_id), \ .scan_type = { \ .sign = 'u', \ From 06dfcb78a4f314d45342ce9075b717168601f081 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 26 Jan 2022 15:23:08 +0100 Subject: [PATCH 129/407] iio: adc: cf_axi_adc_core: Add read_label cb() and forward Not sure how this behaves for client devices which don't set it... Signed-off-by: Michael Hennerich --- drivers/iio/adc/cf_axi_adc.h | 3 +++ drivers/iio/adc/cf_axi_adc_core.c | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/iio/adc/cf_axi_adc.h b/drivers/iio/adc/cf_axi_adc.h index f11b2f48586e58..41aa81323872f1 100644 --- a/drivers/iio/adc/cf_axi_adc.h +++ b/drivers/iio/adc/cf_axi_adc.h @@ -260,6 +260,9 @@ struct axiadc_converter { enum iio_event_direction dir, int state); + int (*read_label)(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, char *label); + int (*post_setup)(struct iio_dev *indio_dev); int (*post_iio_register)(struct iio_dev *indio_dev); int (*set_pnsel)(struct iio_dev *indio_dev, unsigned chan, diff --git a/drivers/iio/adc/cf_axi_adc_core.c b/drivers/iio/adc/cf_axi_adc_core.c index 9f11d6d6376f4e..30d036d1790c8e 100644 --- a/drivers/iio/adc/cf_axi_adc_core.c +++ b/drivers/iio/adc/cf_axi_adc_core.c @@ -642,6 +642,20 @@ static int axiadc_write_raw(struct iio_dev *indio_dev, } } +static int axiadc_read_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, char *label) +{ + struct axiadc_state *st = iio_priv(indio_dev); + struct axiadc_converter *conv = to_converter(st->dev_spi); + + if (conv && conv->read_label) + return conv->read_label(indio_dev, chan, label); + else if (chan->extend_name) + return sprintf(label, "%s\n", chan->extend_name); + else + return -ENOSYS; +} + static int axiadc_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, enum iio_event_info info, int *val, @@ -784,6 +798,7 @@ static const struct iio_info axiadc_info = { .write_event_config = &axiadc_write_event_config, .debugfs_reg_access = &axiadc_reg_access, .update_scan_mode = &axiadc_update_scan_mode, + .read_label = &axiadc_read_label, }; struct axiadc_spidev { From cc695c1dacfb12e3b4bba92d6e3921b03f24b4b7 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 26 Jan 2022 10:32:39 +0200 Subject: [PATCH 130/407] arch:arm:dts:ad6676: remove extra eeprom node According to the schematic, there is only one eeprom device connected to the fmc I2C bus. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-ad6676-fmc.dts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad6676-fmc.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad6676-fmc.dts index 6970f2a174a648..f1c2e19f9f251f 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad6676-fmc.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad6676-fmc.dts @@ -84,11 +84,6 @@ compatible = "at24,24c02"; reg = <0x50>; }; - - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; }; i2c@6 { /* LPC IIC */ @@ -99,11 +94,6 @@ compatible = "at24,24c02"; reg = <0x50>; }; - - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; }; }; From bfbef451a5a7231d8043fbac457e32f13a86ea86 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 26 Jan 2022 10:40:38 +0200 Subject: [PATCH 131/407] arch:arm:dts:fmcomms11: remove extra eeprom On the fmcomms11 board there is only one eeprom device linked to the fmc i2c, according to the datasheet. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-fmcomms11.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcomms11.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcomms11.dts index 329971934225af..ef4a6be95b71c6 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcomms11.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcomms11.dts @@ -26,11 +26,6 @@ reg = <0x50>; }; - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; - ad7291@2f { compatible = "adi,ad7291"; reg = <0x2f>; From 315962e1be8264f77db976cb44784d0f8469928e Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 26 Jan 2022 10:58:34 +0200 Subject: [PATCH 132/407] arch:arm:dts:ad9739a: remove eeprom According to the schematic, there is no eeprom device connected to the fmc i2c. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-ad9739a-fmc.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9739a-fmc.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9739a-fmc.dts index 7d4279eec1cfdf..ff6b57c6234263 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9739a-fmc.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9739a-fmc.dts @@ -19,11 +19,6 @@ #size-cells = <0>; #address-cells = <1>; reg = <6>; - - eeprom@50 { - compatible = "at24,24c02"; - reg = <0x50>; - }; }; }; From db22f2b85fd8a4a400a2ae4fb3ea20f345094dd4 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 26 Jan 2022 11:22:56 +0200 Subject: [PATCH 133/407] arch:arm:dts:adrv9009: remove extra eeprom According to the schematic, there is only one eeprom device linked to the fmc i2c. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-adrv9009.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9009.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9009.dts index 23214d65bb3df2..4b99d25897710a 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9009.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9009.dts @@ -28,11 +28,6 @@ reg = <0x50>; }; - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; - ad7291@2f { compatible = "adi,ad7291"; reg = <0x2f>; From a0068b9d92595f2275bafe118ee0214a3995c8c0 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 26 Jan 2022 11:24:13 +0200 Subject: [PATCH 134/407] arch:arm:dts:adrv9371: remove extra eeprom According to the schematic, there is only one eeprom device linked to the fmc i2c. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-adrv9371.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9371.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9371.dts index 99637580977206..0b98ed05ee7a52 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9371.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9371.dts @@ -27,11 +27,6 @@ reg = <0x50>; }; - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; - ad7291@2f { compatible = "adi,ad7291"; reg = <0x2f>; From d2b9949722c13008513ff98121124059b5618b43 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 25 Jan 2022 16:07:53 +0200 Subject: [PATCH 135/407] arch:arm:dts: fix daq2 zc706 dts The board has only one EEPROM device mapped at address 0x50. Fixes error: `xiic-i2c 41600000.i2c: Timeout waiting at Tx empty` Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq2.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq2.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq2.dts index d42b078d1d0ad6..5fd524258939b3 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq2.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq2.dts @@ -25,11 +25,6 @@ reg = <0x50>; }; - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; - ad7291@2f { compatible = "adi,ad7291"; reg = <0x2f>; From a7064610e8f3e03f80df0bca72f2b7dc61985738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 21 Jan 2022 16:51:55 +0100 Subject: [PATCH 136/407] iio: adrv9002: make use of sysfs_emit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace all 'sprintf()' with 'sysfs_emit()' when reading sysfs attributes. Signed-off-by: Nuno Sá --- drivers/iio/adc/navassa/adrv9002.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/navassa/adrv9002.c b/drivers/iio/adc/navassa/adrv9002.c index 41f7834525138d..53330f50eb6d7c 100644 --- a/drivers/iio/adc/navassa/adrv9002.c +++ b/drivers/iio/adc/navassa/adrv9002.c @@ -573,7 +573,7 @@ static ssize_t adrv9002_attr_show(struct device *dev, struct device_attribute *a if (table >= ADRV9002_FH_TABLES_NR) table = ADRV9002_FH_TABLES_NR; - return sprintf(buf, "%s\n", adrv9002_hop_table[table]); + return sysfs_emit(buf, "%s\n", adrv9002_hop_table[table]); default: return -EINVAL; } @@ -720,7 +720,7 @@ static ssize_t adrv9002_phy_lo_read(struct iio_dev *indio_dev, return adrv9002_dev_err(phy); } - ret = sprintf(buf, "%llu\n", lo_freq.carrierFrequency_Hz); + ret = sysfs_emit(buf, "%llu\n", lo_freq.carrierFrequency_Hz); break; default: ret = -EINVAL; @@ -1295,7 +1295,8 @@ static ssize_t adrv9002_phy_rx_read(struct iio_dev *indio_dev, return adrv9002_dev_err(phy); } - ret = sprintf(buf, "%d\n", calls_mask[channel] & rx_track_calls[private] ? 1 : 0); + ret = sysfs_emit(buf, "%d\n", + calls_mask[channel] & rx_track_calls[private] ? 1 : 0); break; case RX_DECIMATION_POWER: /* it might depend on proper AGC parameters */ @@ -1307,7 +1308,7 @@ static ssize_t adrv9002_phy_rx_read(struct iio_dev *indio_dev, return adrv9002_dev_err(phy); } - ret = sprintf(buf, "%u.%02u dB\n", dec_pwr_mdb / 1000, dec_pwr_mdb % 1000); + ret = sysfs_emit(buf, "%u.%02u dB\n", dec_pwr_mdb / 1000, dec_pwr_mdb % 1000); break; case RX_RSSI: ret = adi_adrv9001_Rx_Rssi_Read(phy->adrv9001, @@ -1317,11 +1318,11 @@ static ssize_t adrv9002_phy_rx_read(struct iio_dev *indio_dev, return adrv9002_dev_err(phy); } - ret = sprintf(buf, "%u.%02u dB\n", rssi_pwr_mdb / 1000, rssi_pwr_mdb % 1000); + ret = sysfs_emit(buf, "%u.%02u dB\n", rssi_pwr_mdb / 1000, rssi_pwr_mdb % 1000); break; case RX_RF_BANDWIDTH: rx_cfg = &phy->curr_profile->rx.rxChannelCfg[chan->channel]; - ret = sprintf(buf, "%u\n", rx_cfg->profile.primarySigBandwidth_Hz); + ret = sysfs_emit(buf, "%u\n", rx_cfg->profile.primarySigBandwidth_Hz); break; case RX_NCO_FREQUENCY: if (!rx_cfg->profile.rxDpProfile.rxNbDem.rxNbNco.rxNbNcoEn) { @@ -1329,7 +1330,7 @@ static ssize_t adrv9002_phy_rx_read(struct iio_dev *indio_dev, return -ENOTSUPP; } - ret = sprintf(buf, "%d\n", rx->channel.nco_freq); + ret = sysfs_emit(buf, "%d\n", rx->channel.nco_freq); break; case RX_ADC_SWITCH: ret = adi_adrv9001_Rx_AdcSwitchEnable_Get(phy->adrv9001, @@ -1340,7 +1341,7 @@ static ssize_t adrv9002_phy_rx_read(struct iio_dev *indio_dev, return adrv9002_dev_err(phy); } - ret = sprintf(buf, "%d\n", enable); + ret = sysfs_emit(buf, "%d\n", enable); break; case RX_BBDC: if (!rx->orx_en && port == ADI_ORX) { @@ -1355,7 +1356,7 @@ static ssize_t adrv9002_phy_rx_read(struct iio_dev *indio_dev, return adrv9002_dev_err(phy); } - ret = sprintf(buf, "%d\n", bbdc); + ret = sysfs_emit(buf, "%d\n", bbdc); break; case RX_BBDC_LOOP_GAIN: ret = adi_adrv9010_bbdc_LoopGain_Get(phy->adrv9001, rx->channel.number, &val); @@ -1509,10 +1510,10 @@ static ssize_t adrv9002_phy_tx_read(struct iio_dev *indio_dev, } val = calls_mask[channel] & tx_track_calls[private] ? 1 : 0; - ret = sprintf(buf, "%d\n", val); + ret = sysfs_emit(buf, "%d\n", val); break; case TX_RF_BANDWIDTH: - ret = sprintf(buf, "%d\n", tx_cfg->primarySigBandwidth_Hz); + ret = sysfs_emit(buf, "%d\n", tx_cfg->primarySigBandwidth_Hz); break; case TX_NCO_FREQUENCY: /* @@ -1524,7 +1525,7 @@ static ssize_t adrv9002_phy_tx_read(struct iio_dev *indio_dev, return -ENOTSUPP; } - ret = sprintf(buf, "%d\n", tx->channel.nco_freq); + ret = sysfs_emit(buf, "%d\n", tx->channel.nco_freq); break; default: ret = -EINVAL; From cb671e0075be26708b584a59a285cc24f8c113c2 Mon Sep 17 00:00:00 2001 From: Bogdan Togorean Date: Mon, 31 Jan 2022 14:33:24 +0200 Subject: [PATCH 137/407] arch: arm64: adi_zynq_defconfig: Build SI5341 driver On ZynqMP platforms SI5341 chip is used to generate ref clock for PSGTR. If this driver is not available the Display port is not initializing and there is no video output. USB3, SATA, PCIE can be affected too. Signed-off-by: Bogdan Togorean --- arch/arm64/configs/adi_zynqmp_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/adi_zynqmp_defconfig b/arch/arm64/configs/adi_zynqmp_defconfig index d81ac9a5f0312f..09fec1e5c28f30 100644 --- a/arch/arm64/configs/adi_zynqmp_defconfig +++ b/arch/arm64/configs/adi_zynqmp_defconfig @@ -302,6 +302,7 @@ CONFIG_XILINX_FCLK=y CONFIG_COMMON_CLK_SI514=y CONFIG_COMMON_CLK_SI570=y CONFIG_COMMON_CLK_SI5324=y +CONFIG_COMMON_CLK_SI5341=y CONFIG_COMMON_CLK_AXI_CLKGEN=y CONFIG_COMMON_CLK_XLNX_CLKWZRD=y CONFIG_COMMON_CLK_ZYNQMP=y From 142729eaf1e5255f8f00eb45401c78f832ddcce0 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 31 Jan 2022 13:58:35 +0200 Subject: [PATCH 138/407] arch:arm:dts:fmcadc2 remove extra eeprom According to the schematic, there is only one eeprom device connected to the fmc i2c, having the slave address 0x50. Signed-off-by: Antoniu Miclaus --- .../arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc2.dts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc2.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc2.dts index 83244dcf6eadb3..df9aba19c72e16 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc2.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc2.dts @@ -58,11 +58,6 @@ compatible = "at24,24c02"; reg = <0x50>; }; - - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; }; i2c@6 { /* LPC IIC */ @@ -73,11 +68,6 @@ compatible = "at24,24c02"; reg = <0x50>; }; - - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; }; }; From 31c53679febda7016c7f93184fc07c163c67f822 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 31 Jan 2022 14:03:30 +0200 Subject: [PATCH 139/407] arch:arm:dts:fmcadc7 remove extra eeprom According to the schematic, there is only one eeprom device connected to the fmc i2c, having the slave address 0x50. Signed-off-by: Antoniu Miclaus --- .../arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc7.dts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc7.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc7.dts index 7f6ce692870658..79b1fc281cb6f4 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc7.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc7.dts @@ -80,11 +80,6 @@ compatible = "at24,24c02"; reg = <0x50>; }; - - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; }; i2c@6 { /* LPC IIC */ @@ -95,11 +90,6 @@ compatible = "at24,24c02"; reg = <0x50>; }; - - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; }; }; From 1532d293b5a8a7aa5db6bc2a67c22c47d834950c Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 31 Jan 2022 14:08:55 +0200 Subject: [PATCH 140/407] arch:arm:dts:fmcjesdadc1 remove extra eeprom According to the schematic, there is only one eeprom device connected to the fmc i2c, having the slave address 0x50. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts index 7bb91a847a559a..629fd1b1ad19ef 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts @@ -25,11 +25,6 @@ reg = <0x50>; }; - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; - ad7291@2f { compatible = "adi,ad7291"; reg = <0x2f>; From 05427790adbf03056f2c5dfb2556acb8d3d115f1 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 31 Jan 2022 15:43:43 +0200 Subject: [PATCH 141/407] arch:arm64: fix zynqmp build Fix CI detected issue for the adi_zynqmp_defconfig. Fixes: cb671e0075be26708b584a59a285cc24f8c113c2 (arch:arm64:adi_zynq_defconfig: Build SI5341 driver) Signed-off-by: Antoniu Miclaus --- arch/arm64/configs/adi_zynqmp_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/configs/adi_zynqmp_defconfig b/arch/arm64/configs/adi_zynqmp_defconfig index 09fec1e5c28f30..6302b3b22da5c9 100644 --- a/arch/arm64/configs/adi_zynqmp_defconfig +++ b/arch/arm64/configs/adi_zynqmp_defconfig @@ -299,10 +299,10 @@ CONFIG_ION=y CONFIG_ION_SYSTEM_HEAP=y CONFIG_ION_CMA_HEAP=y CONFIG_XILINX_FCLK=y +CONFIG_COMMON_CLK_SI5341=y CONFIG_COMMON_CLK_SI514=y CONFIG_COMMON_CLK_SI570=y CONFIG_COMMON_CLK_SI5324=y -CONFIG_COMMON_CLK_SI5341=y CONFIG_COMMON_CLK_AXI_CLKGEN=y CONFIG_COMMON_CLK_XLNX_CLKWZRD=y CONFIG_COMMON_CLK_ZYNQMP=y From 4d90bd5b4b9d3ebf72f23997e8aa71179b8daec7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 26 Jan 2022 16:01:44 +0100 Subject: [PATCH 142/407] iio: adc: ad9081: Add standalone mode support The standalone mode is used when no transport layer core driver is connected. In this case the ad9081 driver registers the IIO device. The user can enable this mode by adding the 'adi,standalone-enable' device tree attribute. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 8d351e003c443f..84b3c5f59b52ad 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -182,6 +182,7 @@ struct ad9081_phy { bool is_initialized; bool tx_disable; bool rx_disable; + bool standalone; struct device_settings_cache device_cache; @@ -3840,6 +3841,8 @@ static int ad9081_parse_dt(struct ad9081_phy *phy, struct device *dev) struct device_node *np = dev->of_node; int ret; + phy->standalone = of_property_read_bool(np, "adi,standalone-enable"); + phy->multidevice_instance_count = 1; of_property_read_u32(np, "adi,multidevice-instance-count", &phy->multidevice_instance_count); @@ -4656,7 +4659,7 @@ static int ad9081_probe(struct spi_device *spi) conv->attrs = &ad9081_phy_attribute_group; - if (!jesd204_dev_is_top(jdev)) { + if (phy->standalone || !jesd204_dev_is_top(jdev)) { ret = ad9081_register_iiodev(conv); if (ret) goto out_clk_del_provider; @@ -4712,7 +4715,7 @@ static int ad9081_remove(struct spi_device *spi) cancel_delayed_work_sync(&phy->dwork); - if (!jesd204_dev_is_top(phy->jdev)) + if (phy->standalone || !jesd204_dev_is_top(phy->jdev)) iio_device_unregister(conv->indio_dev); clk_disable_unprepare(phy->dev_clk); From 5cb32bb87eaaf5a6e9dad5bd977b2879a386c8b4 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 28 Jan 2022 09:35:37 +0100 Subject: [PATCH 143/407] iio: adc: ad9081: Add powerdown support This adds support for dynamic powerdown. Writing device attribute powerdown with 'Yy1Nn0', or [oO][NnFf] for "on" and "off", will either stop the jesd204 fsm, reset the device and power down an optional regulator (vdd), or do the opposite in reverse order. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 107 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 84b3c5f59b52ad..bce5a9313d533c 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -25,6 +25,7 @@ #include #include #include +#include #define JESD204_OF_PREFIX "adi," #include @@ -85,6 +86,7 @@ enum { AD9081_JESD204_FSM_STATE, AD9081_JESD204_FSM_RESUME, AD9081_JESD204_FSM_CTRL, + AD9081_POWER_DOWN, }; struct ad9081_jesd204_priv { @@ -155,6 +157,7 @@ struct ad9081_phy { struct gpio_desc *rx2_en_gpio; struct gpio_desc *tx1_en_gpio; struct gpio_desc *tx2_en_gpio; + struct regulator *supply_reg; struct clk *clks[NUM_AD9081_CLKS]; struct ad9081_clock clk_priv[NUM_AD9081_CLKS]; @@ -2174,6 +2177,73 @@ static const char* const ffh_modes[] = { "phase_continuous", "phase_incontinuous", "phase_coherent" }; +static int ad9081_set_power_state(struct ad9081_phy *phy, bool on) +{ + struct axiadc_converter *conv = spi_get_drvdata(phy->spi); + int ret; + + if (on) { + if (phy->is_initialized) + return 0; + + if (phy->supply_reg) { + ret = regulator_enable(phy->supply_reg); + if (ret) { + dev_err(&phy->spi->dev, + "%s: Failed to enable vdd supply voltage!\n", + __func__); + return ret; + } + } + + ret = adi_ad9081_device_reset(&phy->ad9081, + conv->reset_gpio ? AD9081_HARD_RESET_AND_INIT : + AD9081_SOFT_RESET_AND_INIT); + if (ret < 0) { + dev_err(&phy->spi->dev, "%s: reset/init failed (%d)\n", + __func__, ret); + return ret; + } + + ret = ad9081_setup(phy->spi); + if (ret < 0) { + dev_err(&phy->spi->dev, "%s: setup failed (%d)\n", + __func__, ret); + return ret; + } + + jesd204_fsm_stop(phy->jdev, JESD204_LINKS_ALL); + jesd204_fsm_clear_errors(phy->jdev, JESD204_LINKS_ALL); + ret = jesd204_fsm_start(phy->jdev, JESD204_LINKS_ALL); + } else { + if (!phy->is_initialized) + return 0; + + jesd204_fsm_stop(phy->jdev, JESD204_LINKS_ALL); + + ret = adi_ad9081_device_reset(&phy->ad9081, + conv->reset_gpio ? AD9081_HARD_RESET_AND_INIT : + AD9081_SOFT_RESET_AND_INIT); + if (ret < 0) { + dev_err(&phy->spi->dev, "%s: reset/init failed (%d)\n", + __func__, ret); + return ret; + } + + if (phy->supply_reg) { + ret = regulator_disable(phy->supply_reg); + if (ret) { + dev_err(&phy->spi->dev, + "%s: Failed to disable vdd supply voltage!\n", + __func__); + return ret; + } + } + } + + return ret; +} + static ssize_t ad9081_phy_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -2374,6 +2444,12 @@ static ssize_t ad9081_phy_store(struct device *dev, ret = 0; } + break; + case AD9081_POWER_DOWN: + ret = strtobool(buf, &enable); + if (ret) + break; + ret = ad9081_set_power_state(phy, !enable); break; default: ret = -EINVAL; @@ -2521,6 +2597,9 @@ static ssize_t ad9081_phy_show(struct device *dev, ret = sprintf(buf, "%d\n", phy->is_initialized); break; + case AD9081_POWER_DOWN: + ret = sprintf(buf, "%d\n", !phy->is_initialized); + break; default: ret = -EINVAL; } @@ -2589,6 +2668,11 @@ static IIO_DEVICE_ATTR(jesd204_fsm_ctrl, 0644, ad9081_phy_store, AD9081_JESD204_FSM_CTRL); +static IIO_DEVICE_ATTR(powerdown, 0644, + ad9081_phy_show, + ad9081_phy_store, + AD9081_POWER_DOWN); + static struct attribute *ad9081_phy_attributes[] = { &iio_dev_attr_loopback_mode.dev_attr.attr, &iio_const_attr_loopback_mode_available.dev_attr.attr, @@ -2603,6 +2687,7 @@ static struct attribute *ad9081_phy_attributes[] = { &iio_dev_attr_jesd204_fsm_paused.dev_attr.attr, &iio_dev_attr_jesd204_fsm_resume.dev_attr.attr, &iio_dev_attr_jesd204_fsm_ctrl.dev_attr.attr, + &iio_dev_attr_powerdown.dev_attr.attr, NULL, }; @@ -4433,6 +4518,11 @@ static irqreturn_t ad9081_irq_handler(int irq, void *p) return IRQ_HANDLED; } +static void ad9081_reg_disable(void *data) +{ + regulator_disable(data); +} + static int ad9081_probe(struct spi_device *spi) { struct axiadc_converter *conv; @@ -4571,6 +4661,23 @@ static int ad9081_probe(struct spi_device *spi) return -ENODEV; } + phy->supply_reg = devm_regulator_get(&spi->dev, "vdd"); + if (IS_ERR(phy->supply_reg)) + return dev_err_probe(&spi->dev, PTR_ERR(phy->supply_reg), + "failed to get the vdd supply regulator\n"); + + if (phy->supply_reg) { + ret = regulator_enable(phy->supply_reg); + if (ret) { + dev_err(&spi->dev, "Failed to enable vdd supply voltage!\n"); + return ret; + } + + ret = devm_add_action_or_reset(&spi->dev, ad9081_reg_disable, phy->supply_reg); + if (ret) + return ret; + } + ret = adi_ad9081_device_reset(&phy->ad9081, conv->reset_gpio ? AD9081_HARD_RESET_AND_INIT : AD9081_SOFT_RESET_AND_INIT); From 6b0d341edc733e5cb1a5f0f0ed7c751714dfa5f0 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 28 Jan 2022 10:18:01 +0100 Subject: [PATCH 144/407] iio: adc: ad9081: Fix missing conv->read_label initialization fixes: 06dfcb78a4f3 ("iio: adc: cf_axi_adc_core: Add read_label cb()") Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index bce5a9313d533c..2a85d8d69a4b4e 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -4754,6 +4754,7 @@ static int ad9081_probe(struct spi_device *spi) conv->reg_access = ad9081_reg_access; conv->write_raw = ad9081_write_raw; conv->read_raw = ad9081_read_raw; + conv->read_label = ad9081_read_label; #if 0 conv->read_event_value = ad9081_read_thresh, conv->write_event_value = ad9081_write_thresh, From 0792eac2172bc73dd7ba64721e4c5f7bbe462b21 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 28 Jan 2022 13:35:47 +0100 Subject: [PATCH 145/407] iio: adc: cf_axi_adc_core: Support for EXT SYNC This patch adds a new device attributes 'sync_start_enable' and 'sync_start_enable_available' reading the later returns the available modes which depend on HDL core synthesis parameters. The options are explained below. Reading 'sync_start_enable' returns either 'arm' while waiting for the external synchronization signal or 'disarm' otherwise. - arm: Setting this bit will arm the trigger mechanism sensitive to an external sync signal. Once the external sync signal goes high it synchronizes channels within a DAC, and across multiple instances. This bit has an effect only the EXT_SYNC synthesis parameter is set. This bit self clears. - disarm: Setting this bit will disarm the trigger mechanism sensitive to an external sync signal. This bit has an effect only the EXT_SYNC synthesis parameter is set. This bit self clears. - trigger_manual: Setting this bit will issue an external sync event if it is hooked up inside the fabric. This bit has an effect only the EXT_SYNC synthesis parameter is set. This bit self clears. Signed-off-by: Michael Hennerich --- drivers/iio/adc/cf_axi_adc.h | 9 ++++ drivers/iio/adc/cf_axi_adc_core.c | 78 ++++++++++++++++++++++++++----- 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/cf_axi_adc.h b/drivers/iio/adc/cf_axi_adc.h index 41aa81323872f1..0e145a677f44c3 100644 --- a/drivers/iio/adc/cf_axi_adc.h +++ b/drivers/iio/adc/cf_axi_adc.h @@ -26,6 +26,7 @@ #define ADI_CMOS_OR_LVDS_N (1 << 7) #define ADI_PPS_RECEIVER_ENABLE (1 << 8) #define ADI_SCALECORRECTION_ONLY (1 << 9) +#define ADI_EXT_SYNC (1 << 12) #define ADI_REG_RSTN 0x0040 #define ADI_RSTN (1 << 0) @@ -37,6 +38,11 @@ #define ADI_DDR_EDGESEL (1 << 1) #define ADI_PIN_MODE (1 << 0) +#define ADI_REG_CNTRL_2 0x0048 +#define ADI_EXT_SYNC_ARM (1 << 1) +#define ADI_EXT_SYNC_DISARM (1 << 2) +#define ADI_MANUAL_SYNC_REQUEST (1 << 8) + #define ADI_REG_CLK_FREQ 0x0054 #define ADI_CLK_FREQ(x) (((x) & 0xFFFFFFFF) << 0) #define ADI_TO_CLK_FREQ(x) (((x) >> 0) & 0xFFFFFFFF) @@ -65,6 +71,9 @@ #define ADI_DELAY_RDATA(x) (((x) & 0x1F) << 0) #define ADI_TO_DELAY_RDATA(x) (((x) >> 0) & 0x1F) +#define ADI_REG_SYNC_STATUS 0x0068 +#define ADI_ADC_SYNC_STATUS (1 << 0) + #define ADI_REG_DRP_CNTRL 0x0070 #define ADI_DRP_SEL (1 << 29) #define ADI_DRP_RWN (1 << 28) diff --git a/drivers/iio/adc/cf_axi_adc_core.c b/drivers/iio/adc/cf_axi_adc_core.c index 30d036d1790c8e..7f743ee54b9a5e 100644 --- a/drivers/iio/adc/cf_axi_adc_core.c +++ b/drivers/iio/adc/cf_axi_adc_core.c @@ -60,6 +60,7 @@ struct axiadc_state { unsigned int have_slave_channels; bool additional_channel; bool dp_disable; + bool ext_sync_avail; struct iio_chan_spec channels[AXIADC_MAX_CHANNEL]; }; @@ -400,35 +401,85 @@ static ssize_t axiadc_sampling_frequency_available(struct device *dev, return ret; } -static ssize_t axiadc_sync_start(struct device *dev, +static const char * const axiadc_sync_ctrls[] = { + "arm", "disarm", "trigger_manual", +}; + +static ssize_t axiadc_sync_start_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct axiadc_state *st = iio_priv(indio_dev); - bool state; - u32 reg; int ret; - ret = strtobool(buf, &state); + ret = sysfs_match_string(axiadc_sync_ctrls, buf); if (ret < 0) return ret; - if (state) { - mutex_lock(&indio_dev->mlock); + mutex_lock(&indio_dev->mlock); + if (st->ext_sync_avail) { + switch (ret) { + case 0: + axiadc_write(st, ADI_REG_CNTRL_2, ADI_EXT_SYNC_ARM); + break; + case 1: + axiadc_write(st, ADI_REG_CNTRL_2, ADI_EXT_SYNC_DISARM); + break; + case 2: + axiadc_write(st, ADI_REG_CNTRL_2, ADI_MANUAL_SYNC_REQUEST); + break; + default: + ret = -EINVAL; + } + } else if (ret == 0) { + u32 reg; + reg = axiadc_read(st, ADI_REG_CNTRL); axiadc_write(st, ADI_REG_CNTRL, reg | ADI_SYNC); - mutex_unlock(&indio_dev->mlock); } + mutex_unlock(&indio_dev->mlock); - return len; + return ret < 0 ? ret : len; } -static IIO_DEVICE_ATTR(sync_start_enable, 0200, - NULL, - axiadc_sync_start, +static ssize_t axiadc_sync_start_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct axiadc_state *st = iio_priv(indio_dev); + u32 reg; + + switch ((u32)this_attr->address) { + case 0: + reg = axiadc_read(st, ADI_REG_SYNC_STATUS); + + return sprintf(buf, "%s\n", reg & ADI_ADC_SYNC_STATUS ? + axiadc_sync_ctrls[0] : axiadc_sync_ctrls[1]); + case 1: + if (st->ext_sync_avail) + return sprintf(buf, "arm disarm trigger_manual\n"); + else + return sprintf(buf, "arm\n"); + default: + return -EINVAL; + } + + return -EINVAL; +} + +static IIO_DEVICE_ATTR(sync_start_enable, 0644, + axiadc_sync_start_show, + axiadc_sync_start_store, 0); +static IIO_DEVICE_ATTR(sync_start_enable_available, 0444, + axiadc_sync_start_show, + NULL, + 1); + static IIO_DEVICE_ATTR(in_voltage_sampling_frequency_available, S_IRUGO, axiadc_sampling_frequency_available, NULL, @@ -436,6 +487,7 @@ static IIO_DEVICE_ATTR(in_voltage_sampling_frequency_available, S_IRUGO, static struct attribute *axiadc_attributes[] = { &iio_dev_attr_sync_start_enable.dev_attr.attr, + &iio_dev_attr_sync_start_enable_available.dev_attr.attr, &iio_dev_attr_in_voltage_sampling_frequency_available.dev_attr.attr, NULL, }; @@ -1020,7 +1072,7 @@ static int axiadc_probe(struct platform_device *pdev) struct resource *mem; struct axiadc_spidev axiadc_spidev; struct axiadc_converter *conv; - unsigned int skip = 1; + unsigned int config, skip = 1; int ret; dev_dbg(&pdev->dev, "Device Tree Probing \'%s\'\n", @@ -1076,6 +1128,8 @@ static int axiadc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, indio_dev); + config = axiadc_read(st, ADI_REG_CONFIG); + st->ext_sync_avail = !!(config & ADI_EXT_SYNC); st->dp_disable = false; /* FIXME: resolve later which reg & bit to read for this */ conv = to_converter(st->dev_spi); From 9a09ba34d6c8650779da944bbf0578810b81f656 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 2 Feb 2022 09:13:29 +0100 Subject: [PATCH 146/407] iio: frequency: cf_axi_dds: Support for EXT SYNC This patch adds a new device attributes 'sync_start_enable' and 'sync_start_enable_available' reading the later returns the available modes which depend on HDL core synthesis parameters. The options are explained below. Reading 'sync_start_enable' returns either 'arm' while waiting for the external synchronization signal or 'disarm' otherwise. - arm: Setting this bit will arm the trigger mechanism sensitive to an external sync signal. Once the external sync signal goes high it synchronizes channels within a DAC, and across multiple instances. This bit has an effect only the EXT_SYNC synthesis parameter is set. This bit self clears. - disarm: Setting this bit will disarm the trigger mechanism sensitive to an external sync signal. This bit has an effect only the EXT_SYNC synthesis parameter is set. This bit self clears. - trigger_manual: Setting this bit will issue an external sync event if it is hooked up inside the fabric. This bit has an effect only the EXT_SYNC synthesis parameter is set. This bit self clears. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/cf_axi_dds.c | 80 ++++++++++++++++++++++++++---- drivers/iio/frequency/cf_axi_dds.h | 8 ++- 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/drivers/iio/frequency/cf_axi_dds.c b/drivers/iio/frequency/cf_axi_dds.c index c85c3962d5261b..84d953d7154a0f 100644 --- a/drivers/iio/frequency/cf_axi_dds.c +++ b/drivers/iio/frequency/cf_axi_dds.c @@ -114,6 +114,7 @@ struct cf_axi_dds_state { enum fifo_ctrl dma_fifo_ctrl_bypass; bool dma_fifo_ctrl_oneshot; bool issue_sync_en; + bool ext_sync_avail; struct iio_info iio_info; struct iio_dev *indio_dev; @@ -552,37 +553,91 @@ static ssize_t cf_axi_sampling_frequency_available(struct device *dev, return ret; } -static ssize_t cf_axi_sync_start(struct device *dev, + +static const char * const axidds_sync_ctrls[] = { + "arm", "disarm", "trigger_manual", +}; + +static ssize_t axidds_sync_start_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct cf_axi_dds_state *st = iio_priv(indio_dev); - bool state; int ret; - ret = strtobool(buf, &state); + ret = sysfs_match_string(axidds_sync_ctrls, buf); if (ret < 0) return ret; - if (state) + mutex_lock(&indio_dev->mlock); + if (st->ext_sync_avail) { + switch (ret) { + case 0: + dds_write(st, ADI_REG_CNTRL_1, ADI_EXT_SYNC_ARM); + break; + case 1: + dds_write(st, ADI_REG_CNTRL_1, ADI_EXT_SYNC_DISARM); + break; + case 2: + dds_write(st, ADI_REG_CNTRL_1, ADI_MANUAL_SYNC_REQUEST); + break; + default: + ret = -EINVAL; + } + } else if (ret == 0) { cf_axi_dds_start_sync(st, 0); + } + mutex_unlock(&indio_dev->mlock); - return len; + return ret < 0 ? ret : len; } -static IIO_DEVICE_ATTR(out_voltage_sampling_frequency_available, 0444, - cf_axi_sampling_frequency_available, - NULL, +static ssize_t axidds_sync_start_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct cf_axi_dds_state *st = iio_priv(indio_dev); + u32 reg; + + switch ((u32)this_attr->address) { + case 0: + reg = dds_read(st, ADI_REG_SYNC_STATUS); + + return sprintf(buf, "%s\n", reg & ADI_ADC_SYNC_STATUS ? + axidds_sync_ctrls[0] : axidds_sync_ctrls[1]); + case 1: + if (st->ext_sync_avail) + return sprintf(buf, "arm disarm trigger_manual\n"); + else + return sprintf(buf, "arm\n"); + default: + return -EINVAL; + } + + return -EINVAL; +} + +static IIO_DEVICE_ATTR(sync_start_enable, 0644, + axidds_sync_start_show, + axidds_sync_start_store, 0); -static IIO_DEVICE_ATTR(sync_start_enable, 0200, +static IIO_DEVICE_ATTR(sync_start_enable_available, 0444, + axidds_sync_start_show, + NULL, + 1); + +static IIO_DEVICE_ATTR(out_voltage_sampling_frequency_available, 0444, + cf_axi_sampling_frequency_available, NULL, - cf_axi_sync_start, 0); static struct attribute *cf_axi_attributes[] = { &iio_dev_attr_sync_start_enable.dev_attr.attr, + &iio_dev_attr_sync_start_enable_available.dev_attr.attr, &iio_dev_attr_out_voltage_sampling_frequency_available.dev_attr.attr, NULL, }; @@ -2082,7 +2137,7 @@ static int cf_axi_dds_probe(struct platform_device *pdev) struct cf_axi_dds_state *st; struct iio_dev *indio_dev; struct resource *res; - unsigned int ctrl_2; + unsigned int ctrl_2, config; unsigned int rate; unsigned int drp_status; int timeout = 100; @@ -2190,6 +2245,9 @@ static int cf_axi_dds_probe(struct platform_device *pdev) st->issue_sync_en = info->issue_sync_en; st->standalone = info->standalone; st->version = dds_read(st, ADI_AXI_REG_VERSION); + + config = dds_read(st, ADI_REG_CONFIG); + st->ext_sync_avail = !!(config & ADI_EXT_SYNC); st->dp_disable = false; /* FIXME: resolve later which reg & bit to read for this */ if (ADI_AXI_PCORE_VER_MAJOR(st->version) > diff --git a/drivers/iio/frequency/cf_axi_dds.h b/drivers/iio/frequency/cf_axi_dds.h index e144ec58545c9e..fbabbc22dd687c 100644 --- a/drivers/iio/frequency/cf_axi_dds.h +++ b/drivers/iio/frequency/cf_axi_dds.h @@ -25,6 +25,7 @@ #define ADI_PPS_RECEIVER_ENABLE (1 << 8) #define ADI_SCALECORRECTION_ONLY (1 << 9) #define ADI_XBAR_ENABLE (1 << 10) +#define ADI_EXT_SYNC (1 << 12) /* DAC COMMON */ @@ -33,8 +34,10 @@ #define ADI_MMCM_RSTN (1 << 1) #define ADI_REG_CNTRL_1 0x0044 -#define ADI_ENABLE (1 << 0) /* v7.0 */ #define ADI_SYNC (1 << 0) /* v8.0 */ +#define ADI_EXT_SYNC_ARM (1 << 1) +#define ADI_EXT_SYNC_DISARM (1 << 2) +#define ADI_MANUAL_SYNC_REQUEST (1 << 8) #define ADI_REG_CNTRL_2 0x0048 #define ADI_PAR_TYPE (1 << 7) @@ -78,6 +81,9 @@ enum dds_data_select { #define ADI_REG_STATUS 0x005C #define ADI_STATUS (1 << 0) +#define ADI_REG_SYNC_STATUS 0x0068 +#define ADI_ADC_SYNC_STATUS (1 << 0) + #define ADI_REG_DRP_CNTRL 0x0070 #define ADI_DRP_SEL (1 << 29) #define ADI_DRP_RWN (1 << 28) From c7fcca872f198784833612e2bc8502faf26e665a Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 2 Feb 2022 09:20:19 +0100 Subject: [PATCH 147/407] iio: frequency: cf_axi_dds: Sync DDSs after jesd204 link establishment In situations where device clocks are changed during jesd204-fsm state transitions. It might be required to re-sync the DDSs. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/cf_axi_dds.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/iio/frequency/cf_axi_dds.c b/drivers/iio/frequency/cf_axi_dds.c index 84d953d7154a0f..fb8679342ac791 100644 --- a/drivers/iio/frequency/cf_axi_dds.c +++ b/drivers/iio/frequency/cf_axi_dds.c @@ -1782,11 +1782,31 @@ static int cf_axi_dds_jesd204_link_supported(struct jesd204_dev *jdev, return JESD204_STATE_CHANGE_DONE; } +static int cf_axi_dds_jesd204_post_running_stage(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason) +{ + struct device *dev = jesd204_dev_to_device(jdev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct cf_axi_dds_state *st = iio_priv(indio_dev); + + if (reason == JESD204_STATE_OP_REASON_INIT) { + cf_axi_dds_start_sync(st, 0); + return JESD204_STATE_CHANGE_DONE; + } + + return JESD204_STATE_CHANGE_DONE; + +} + static const struct jesd204_dev_data jesd204_cf_axi_dds_init = { .state_ops = { [JESD204_OP_LINK_SUPPORTED] = { .per_link = cf_axi_dds_jesd204_link_supported, }, + [JESD204_OP_OPT_POST_RUNNING_STAGE] = { + .per_device = cf_axi_dds_jesd204_post_running_stage, + .mode = JESD204_STATE_OP_MODE_PER_DEVICE, + }, }, }; From 872cae2391d01712e79936b7a9f668f7d53c7582 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 2 Feb 2022 09:21:57 +0100 Subject: [PATCH 148/407] dts: zynqmp-zcu102-rev10-ad9081.dts: Enable axi-data-offload engine This HDL core is now by default in all our MxFE builds. So enable it. Signed-off-by: Michael Hennerich --- .../dts/xilinx/zynqmp-zcu102-rev10-ad9081.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081.dts index 7638ec8d7f5006..f984e4cb773619 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081.dts @@ -77,6 +77,7 @@ clock-names = "sampl_clk"; spibus-connected = <&trx0_ad9081>; //adi,axi-pl-fifo-enable; + adi,axi-data-offload-connected = <&axi_data_offload_tx>; jesd204-device; #jesd204-cells = <2>; @@ -162,6 +163,21 @@ compatible = "adi,axi-sysid-1.00.a"; reg = <0x85000000 0x10000>; }; + + axi_data_offload_tx: axi-data-offload-0@9c440000 { + compatible = "adi,axi-data-offload-1.0.a"; + reg = <0x9c440000 0x10000>; + // adi,bringup; + // adi,oneshot; + // adi,bypass; + // adi,sync-config = <2>; + // adi,transfer-length = /bits/ 64 <0x10000>; // 2**16 bytes + }; + + axi_data_offload_rx: axi-data-offload-1@9c450000 { + compatible = "adi,axi-data-offload-1.0.a"; + reg = <0x9c450000 0x10000>; + }; }; }; From c71fe7a0d7fd1211d9f74d9c782d78287ba5d211 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Fri, 4 Feb 2022 15:43:15 +0200 Subject: [PATCH 149/407] arch: arm64: dts: stingray: Configure CLKIN priority Set default clock priority to CLKIN1 -> CLKIN0 -> CLKIN2 -> CLKIN3. When an external reference clock is applied on CLKIN1 this will be used as reference for PLL1 otherwise the onboard CLKIN0 will be used. Signed-off-by: Cristian Pop --- arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts index e5e244c4cd674d..1c585a9bdd45fc 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts @@ -328,3 +328,7 @@ "pll0-clk-rf16", "pll0-clk-rf32"; }; }; + +&hmc7044 { + adi,pll1-ref-prio-ctrl = <0xE1>; /* prefer CLKIN1 -> CLKIN0 -> CLKIN2 -> CLKIN3 */ +}; From 14f2fa24501705177c49a1e2d5d36bb3b9d7031b Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Thu, 3 Feb 2022 16:29:56 +0200 Subject: [PATCH 150/407] iio: adc: ad9083: Don't ignore the EPROBE_DEFER requests ad9083_request_clks() will return EPROBE_DEFER if adc_ref_clk is not yet available. Don't treat this as an error, but ask for a probe defer. Signed-off-by: Dragos Bogdan --- drivers/iio/adc/ad9083.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad9083.c b/drivers/iio/adc/ad9083.c index 771126e492c6d3..e763a6cfd4e6a1 100644 --- a/drivers/iio/adc/ad9083.c +++ b/drivers/iio/adc/ad9083.c @@ -1049,7 +1049,7 @@ static int ad9083_probe(struct spi_device *spi) ret = ad9083_setup(conv); if (ret < 0) - return -ENODEV; + return ret; return jesd204_fsm_start(jdev, JESD204_LINKS_ALL); } From cd50d3b01cd16e96d2c8eabf69f4fb7b920f7ba1 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 3 Feb 2022 09:29:37 +0200 Subject: [PATCH 151/407] arch:arm:dts: fmcomms1: remove extra eeproms According to the schematic, there no eeprom device connected to the fmc I2C bus. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/adi-fmcomms1.dtsi | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/arm/boot/dts/adi-fmcomms1.dtsi b/arch/arm/boot/dts/adi-fmcomms1.dtsi index 971af3b607edca..638dee3682fe52 100644 --- a/arch/arm/boot/dts/adi-fmcomms1.dtsi +++ b/arch/arm/boot/dts/adi-fmcomms1.dtsi @@ -170,16 +170,5 @@ adi,output-power = <3>; adi,mute-till-lock-enable; }; - - }; - - eeprom@50 { - compatible = "at24,24c02"; - reg = <0x50>; - }; - - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; }; }; From b6d832f06a9b43d4a224403954ae6ec7a3cf98cb Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 3 Feb 2022 09:37:08 +0200 Subject: [PATCH 152/407] arch:arm:dts:fmcdaq3: remove extra eeprom According to the schematic, there is only one eeprom device connected to the fmc I2C bus. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3.dts index 502a3456722c96..4988e6a6294dc6 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcdaq3.dts @@ -25,11 +25,6 @@ reg = <0x50>; }; - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; - ad7291@2f { compatible = "adi,ad7291"; reg = <0x2f>; From a8bffd1a6bebca865084f5118e1d8c03ea9b106b Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 3 Feb 2022 10:13:25 +0200 Subject: [PATCH 153/407] arch:arm:dts:adrv9008-1: remove extra eeprom According to the schematic, there is only one eeprom device connected to fmc i2c bus. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-1.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-1.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-1.dts index 4e50acdcff5caf..b6913bb454b344 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-1.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-1.dts @@ -27,11 +27,6 @@ reg = <0x50>; }; - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; - ad7291@2f { compatible = "adi,ad7291"; reg = <0x2f>; From 8851d54c54593e49ff38403b4ec2f0edcd89ec69 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 3 Feb 2022 10:14:15 +0200 Subject: [PATCH 154/407] arch:arm:dts:adrv9008-2: remove extra eeprom According to the schematic, there is only one eeprom device connected to the fmc i2c bus. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-2.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-2.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-2.dts index 7735fc6a376eaa..04328fa4c72472 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-2.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-2.dts @@ -27,11 +27,6 @@ reg = <0x50>; }; - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; - ad7291@2f { compatible = "adi,ad7291"; reg = <0x2f>; From fc21f43ceb57557e81fbb4dc0e46ffec98dccb88 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 3 Feb 2022 10:15:13 +0200 Subject: [PATCH 155/407] arch:arm:dts:ad9136-fmc: remove extra eeprom According to the schematic, there is only one eeprom device connected to the fmc I2C bus. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-ad9136-fmc-ebz.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9136-fmc-ebz.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9136-fmc-ebz.dts index 7ec7829b29ccd8..2b3c991f35d46a 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9136-fmc-ebz.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9136-fmc-ebz.dts @@ -13,11 +13,6 @@ compatible = "at24,24c02"; reg = <0x50>; }; - - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; }; }; From 077edb38cf7929768821eeda3211eb44b09b650d Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 7 Feb 2022 10:25:06 +0200 Subject: [PATCH 156/407] arch:arm:dts:fmcomms11-RevA: remove extra eeprom According to the schematic, there is only one eeprom device connected to the fmc I2C bus. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-fmcomms11-RevA.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcomms11-RevA.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcomms11-RevA.dts index 05cf0e2ff5f13f..defbba412e0d67 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcomms11-RevA.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcomms11-RevA.dts @@ -15,11 +15,6 @@ reg = <0x50>; }; - eeprom@54 { - compatible = "at24,24c02"; - reg = <0x54>; - }; - ad7291@2f { compatible = "adi,ad7291"; reg = <0x2f>; From 0e85205f8e00923cc963778750d8ce4027874701 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 7 Feb 2022 10:26:35 +0200 Subject: [PATCH 157/407] arch:arm:dts:fmclidar1: remove extra eeprom According to the schematic, there is only one eeprom device connected to the fmc I2C bus, having the slave address 0x54. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts index 043aa76a70c150..ae6f9fa61ed4a6 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts @@ -20,11 +20,6 @@ #size-cells = <0>; reg = <5>; - eeprom@50 { - compatible = "at24,24c02"; - reg = <0x50>; - }; - eeprom@54 { compatible = "at24,24c02"; reg = <0x54>; From c0773e39305ef67595e970b0d872fe1ca71cc6f0 Mon Sep 17 00:00:00 2001 From: Andrei Drimbarean Date: Tue, 8 Feb 2022 14:33:43 +0200 Subject: [PATCH 158/407] arch:arm:boot:dts: update ad7768-1-evb device tree Update device tree according to board and HDL updates. Interrupt pin was changed to an unoccupied one since 55 is used by FMC AXI I2C and a clkgen IP was added to the spi-engine to generate the serial clock properly. Signed-off-by: Andrei Drimbarean --- .../arm/boot/dts/zynq-zed-adv7511-ad7768-1-evb.dts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zed-adv7511-ad7768-1-evb.dts b/arch/arm/boot/dts/zynq-zed-adv7511-ad7768-1-evb.dts index 68cf988de3e7a7..fa6123f3c11be1 100644 --- a/arch/arm/boot/dts/zynq-zed-adv7511-ad7768-1-evb.dts +++ b/arch/arm/boot/dts/zynq-zed-adv7511-ad7768-1-evb.dts @@ -56,12 +56,20 @@ }; }; + spi_clock: axi-clkgen@44a70000 { + compatible = "adi,axi-clkgen-2.00.a"; + reg = <0x44a70000 0x10000>; + #clock-cells = <0>; + clocks = <&clkc 15>, <&clkc 16>; + clock-names = "s_axi_aclk", "clkin1"; + }; + axi_spi_engine_0: spi@0x44a00000 { compatible = "adi,axi-spi-engine-1.00.a"; reg = <0x44a00000 0x1000>; interrupt-parent = <&intc>; - interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clkc 15 &clkc 15>; + interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 15 &spi_clock>; clock-names = "s_axi_aclk", "spi_clk"; num-cs = <1>; @@ -84,4 +92,4 @@ #io-channel-cells = <1>; }; }; -}; \ No newline at end of file +}; From 922fcbc3ece5f692576be2a8ad9090db431b4320 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 7 Feb 2022 12:52:48 +0100 Subject: [PATCH 159/407] iio: jesd204: adi-iio-fakedev: Generic IIO fake device driver This driver allows to link a list of device sysfs attributes from either a platform, spi or i2c device to an iio device. This driver should only be used for debug or test purposes. Signed-off-by: Michael Hennerich --- drivers/iio/Kconfig.adi | 1 + drivers/iio/jesd204/Kconfig | 10 ++ drivers/iio/jesd204/Makefile | 1 + drivers/iio/jesd204/adi-iio-fakedev.c | 141 ++++++++++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 drivers/iio/jesd204/adi-iio-fakedev.c diff --git a/drivers/iio/Kconfig.adi b/drivers/iio/Kconfig.adi index 7aa1082c4400bb..3f2624a7466daa 100644 --- a/drivers/iio/Kconfig.adi +++ b/drivers/iio/Kconfig.adi @@ -174,3 +174,4 @@ config IIO_ALL_ADI_DRIVERS select ADUX1020 select IIO_GEN_MUX select AD74413R + select ADI_IIO_FAKEDEV diff --git a/drivers/iio/jesd204/Kconfig b/drivers/iio/jesd204/Kconfig index 22112f8c680417..68c8e6b43250ef 100644 --- a/drivers/iio/jesd204/Kconfig +++ b/drivers/iio/jesd204/Kconfig @@ -28,5 +28,15 @@ config AXI_JESD204_RX config XILINX_TRANSCEIVER tristate +config ADI_IIO_FAKEDEV + tristate "Analog Devices Generic IIO fake device driver" + help + This driver allows to link a list of device sysfs attributes + from either a platform, spi or i2c device to an iio device. + This driver should only be used for debug or test purposes. + + To compile this driver as a module, choose M here: the + module will be called adi-iio-fakedev. + endif diff --git a/drivers/iio/jesd204/Makefile b/drivers/iio/jesd204/Makefile index abfc29fd7d7e34..ad98908c832d5c 100644 --- a/drivers/iio/jesd204/Makefile +++ b/drivers/iio/jesd204/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_AXI_JESD204_RX) += axi_jesd204_rx.o obj-$(CONFIG_AXI_JESD204_TX) += axi_jesd204_tx.o obj-$(CONFIG_XILINX_TRANSCEIVER) += xilinx_transceiver.o obj-$(CONFIG_ALTERA_ARRIA10_JESD204_PHY) += altera_adxcvr.o +obj-$(CONFIG_ADI_IIO_FAKEDEV) += adi-iio-fakedev.o diff --git a/drivers/iio/jesd204/adi-iio-fakedev.c b/drivers/iio/jesd204/adi-iio-fakedev.c new file mode 100644 index 00000000000000..cdefe4c86f899c --- /dev/null +++ b/drivers/iio/jesd204/adi-iio-fakedev.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices Generic IIO fake device driver + * + * Copyright 2022 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct adi_iio_fakedev { + struct device_node *np; + struct device *dev; +}; + +static int adi_iio_fakedev_attach_client(struct device *dev, void *data) +{ + struct adi_iio_fakedev *fdev = data; + + if ((fdev->np == dev->of_node) && dev->driver) { + fdev->dev = dev; + return 1; + } + + return 0; +} + +static void adi_iio_fakedev_cleanup(void *data) +{ + struct device *dev = data; + + put_device(dev); + module_put(dev->driver->owner); +} + +static void adi_iio_fakedev_cleanup_links(void *data) +{ + struct platform_device *pdev = data; + struct property *prop; + const char *name; + + of_property_for_each_string(pdev->dev.of_node, + "adi,attribute-names", prop, name) + sysfs_remove_link(&pdev->dev.kobj, name); +} + +static const struct iio_info adi_iio_fakedev_info = { +}; + +/* Match table for of_platform binding */ +static const struct of_device_id adi_iio_fakedev_of_match[] = { + { .compatible = "adi,iio-fake-platform-device", .data = &platform_bus_type}, + { .compatible = "adi,iio-fake-spi-device", .data = &spi_bus_type}, + { .compatible = "adi,iio-fake-i2c-device", .data = &i2c_bus_type}, + { /* end of list */ } +}; +MODULE_DEVICE_TABLE(of, adi_iio_fakedev_of_match); + +static int adi_iio_fakedev_probe(struct platform_device *pdev) +{ + struct iio_dev *indio_dev; + struct adi_iio_fakedev fdev; + const struct of_device_id *id; + struct bus_type *bus; + struct property *prop; + const char *name; + int ret, cnt = 0; + + id = of_match_device(adi_iio_fakedev_of_match, &pdev->dev); + if (!id || !id->data) + return -ENODEV; + + bus = (struct bus_type *) id->data; + + /* Defer driver probe until matching driver is registered */ + fdev.np = of_parse_phandle(pdev->dev.of_node, + "adi,faked-dev", 0); + if (!fdev.np) { + dev_err(&pdev->dev, "could not find spi node\n"); + return -ENODEV; + } + + ret = bus_for_each_dev(bus, NULL, &fdev, adi_iio_fakedev_attach_client); + if (ret == 0) + return -EPROBE_DEFER; + + if (!try_module_get(fdev.dev->driver->owner)) + return -ENODEV; + + get_device(fdev.dev); + + ret = devm_add_action_or_reset(&pdev->dev, adi_iio_fakedev_cleanup, fdev.dev); + if (ret) + return ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, 0); + if (indio_dev == NULL) + return -ENOMEM; + + indio_dev->name = "adi-iio-fakedev"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &adi_iio_fakedev_info; + + ret = devm_iio_device_register(&pdev->dev, indio_dev); + if (ret) + return ret; + + of_property_for_each_string(pdev->dev.of_node, "adi,attribute-names", prop, name) { + ret = compat_only_sysfs_link_entry_to_kobj(&indio_dev->dev.kobj, + &fdev.dev->kobj, name, NULL); + if (!ret) + cnt++; + } + + ret = devm_add_action_or_reset(&pdev->dev, adi_iio_fakedev_cleanup_links, pdev); + if (ret) + return ret; + + dev_info(&pdev->dev, "Faking %d attributes from %s", cnt, dev_name(fdev.dev)); + + return 0; +} + +static struct platform_driver adi_iio_fakedev_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = adi_iio_fakedev_of_match, + }, + .probe = adi_iio_fakedev_probe, +}; +module_platform_driver(adi_iio_fakedev_driver); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices Generic IIO fake device driver"); +MODULE_LICENSE("GPL v2"); From eacf1591b324eacd833ebb4e0e7b09812a3d9357 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 7 Feb 2022 12:55:57 +0100 Subject: [PATCH 160/407] Documentation: bindings: adi,iio-fakedev.yaml: Add Documentation Add dt bindings for the Generic IIO fake device driver This driver allows to link a list of device sysfs attributes from either a platform, spi or i2c device to an iio device. This driver should only be used for debug or test purposes. Signed-off-by: Michael Hennerich --- .../bindings/iio/jesd204/adi,iio-fakedev.yaml | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/jesd204/adi,iio-fakedev.yaml diff --git a/Documentation/devicetree/bindings/iio/jesd204/adi,iio-fakedev.yaml b/Documentation/devicetree/bindings/iio/jesd204/adi,iio-fakedev.yaml new file mode 100644 index 00000000000000..09f3ace1040fcf --- /dev/null +++ b/Documentation/devicetree/bindings/iio/jesd204/adi,iio-fakedev.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,axi-adc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices Generic IIO fake device driver + +maintainers: + - Michael Hennerich + +description: | + This driver allows to link a list of device sysfs attributes + from either a platform, spi or i2c device to an iio device. + This driver should only be used for debug or test purposes. + +properties: + compatible: + enum: + - adi,iio-fake-platform-device + - adi,iio-fake-spi-device" + - adi,iio-fake-i2c-device" + + adi,faked-dev: + $ref: /schemas/types.yaml#/definitions/phandle + description: + A reference (phandle) to a the actual device to which the fake device links attribues from. + + adi,attribute-names: + $ref: /schemas/types.yaml#/definitions/string-array + description: + List of device sysfs attribute strings. + +required: + - compatible + - adi,faked-dev + - adi,attribute-names + +additionalProperties: false + +examples: + - | + axi-jesd204-rx@0 { + compatible = "adi,iio-fake-platform-device"; + adi,faked-dev = <&axi_ad9081_rx_jesd>; + adi,attribute-names = + "status", "encoder", "lane0_info", "lane1_info", + "lane2_info", "lane3_info"; + label = "axi-jesd204-rx"; + }; + + axi-jesd204-rx@1 { + compatible = "adi,iio-fake-platform-device"; + adi,faked-dev = <&axi_ad9081_tx_jesd>; + adi,attribute-names = "status", "encoder"; + label = "axi-jesd204-rx"; + }; + + axi-adxcvr-rx@2 { + compatible = "adi,iio-fake-platform-device"; + adi,faked-dev = <&axi_ad9081_adxcvr_rx>; + adi,attribute-names = + "eyescan_info", "prbs_status", "prbs_counter_reset", + "prescale", "enable", "prbs_error_counters", "reg_access", + "eye_data", "prbs_select"; + label = "axi-adxcvr-rx"; + }; + + axi-adxcvr-tx@4 { + compatible = "adi,iio-fake-platform-device"; + adi,faked-dev = <&axi_ad9081_adxcvr_tx>; + adi,attribute-names = "prbs_select", "prbs_error_inject", "reg_access"; + label = "axi-adxcvr-tx"; + }; +... From 1e6cded1daae306e4060b1e7d78f63eb3ec527a9 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 8 Feb 2022 08:44:28 +0100 Subject: [PATCH 161/407] iio: adc: ad9081: Update API to Version 1.2.2 - Fix Oneshot sync may cause JTX links to fail in certain use cases. - Fix adi_adxxxx_dac_digital_logic_enable_set needed for all devices, not just those containing DAC side implementation. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081/adi_ad9081_config.h | 30 +++++++++++----------- drivers/iio/adc/ad9081/adi_ad9081_dac.c | 15 ----------- drivers/iio/adc/ad9081/adi_ad9081_device.c | 21 ++++++++++++--- drivers/iio/adc/ad9081/adi_ad9081_sync.c | 24 ++++++----------- 4 files changed, 41 insertions(+), 49 deletions(-) diff --git a/drivers/iio/adc/ad9081/adi_ad9081_config.h b/drivers/iio/adc/ad9081/adi_ad9081_config.h index 29d955686cfe31..9e91bef0eaaf96 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_config.h +++ b/drivers/iio/adc/ad9081/adi_ad9081_config.h @@ -40,7 +40,7 @@ #define __FUNCTION_NAME__ __FUNCTION__ #endif -#define AD9081_API_REV 0x00010200 +#define AD9081_API_REV 0x00010202 #define AD9081_API_HW_RESET_LOW 600000 #define AD9081_API_RESET_WAIT 500000 #define AD9081_PLL_LOCK_TRY 75 @@ -362,6 +362,20 @@ adi_ad9081_device_nco_sync_reset_via_sysref_set(adi_ad9081_device_t *device, */ int32_t adi_ad9081_device_nco_sync_trigger_set(adi_ad9081_device_t *device); +/** + * \brief Enables digital logic. + * + * This includes JESD digital, digital clock gen., digital data path. + * + * + * \param[in] device Pointer to device handler structure. + * \param[in] enable 1: enable digital logic. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ +int32_t adi_ad9081_device_digital_logic_enable_set(adi_ad9081_device_t *device, + uint8_t enable); + /** * \brief Enable dual SPI mode * @@ -396,20 +410,6 @@ int32_t adi_ad9081_dac_d2a_dual_spi_enable_set(adi_ad9081_device_t *device, */ int32_t adi_ad9081_dac_dll_startup(adi_ad9081_device_t *device, uint8_t dacs); -/** - * \brief Enables digital logic. - * - * This includes JESD digital, digital clock gen., digital data path. - * - * - * \param[in] device Pointer to device handler structure. - * \param[in] enable 1: enable digital logic. - * - * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. - */ -int32_t adi_ad9081_dac_digital_logic_enable_set(adi_ad9081_device_t *device, - uint8_t enable); - /** * \brief Sets frequency tuning word for specified DACs and channels. * diff --git a/drivers/iio/adc/ad9081/adi_ad9081_dac.c b/drivers/iio/adc/ad9081/adi_ad9081_dac.c index b98dfdb97ba189..c5760c8af7e0c9 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_dac.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_dac.c @@ -939,21 +939,6 @@ int32_t adi_ad9081_dac_spi_enable_set(adi_ad9081_device_t *device, return API_CMS_ERROR_OK; } -int32_t adi_ad9081_dac_digital_logic_enable_set(adi_ad9081_device_t *device, - uint8_t enable) -{ - int32_t err; - AD9081_NULL_POINTER_RETURN(device); - AD9081_LOG_FUNC(); - - /* enable digital logic, including jrx digital, digital clock gen., digital data path */ - err = adi_ad9081_hal_bf_set(device, REG_DIG_RESET_ADDR, - BF_DIG_RESET_INFO, !enable); /* not paged */ - AD9081_ERROR_RETURN(err); - - return API_CMS_ERROR_OK; -} - int32_t adi_ad9081_dac_dll_startup(adi_ad9081_device_t *device, uint8_t dacs) { int32_t err; diff --git a/drivers/iio/adc/ad9081/adi_ad9081_device.c b/drivers/iio/adc/ad9081/adi_ad9081_device.c index b5481e39da460e..1bf17a6f2dd5be 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_device.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_device.c @@ -221,6 +221,21 @@ int32_t adi_ad9081_device_boot_post_clock(adi_ad9081_device_t *device) return API_CMS_ERROR_OK; } +int32_t adi_ad9081_device_digital_logic_enable_set(adi_ad9081_device_t *device, + uint8_t enable) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + /* enable digital logic, digital clock gen., digital data path */ + err = adi_ad9081_hal_bf_set(device, REG_DIG_RESET_ADDR, + BF_DIG_RESET_INFO, !enable); /* not paged */ + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + int32_t adi_ad9081_device_clk_pll_lock_status_get(adi_ad9081_device_t *device, uint8_t *status) { @@ -556,8 +571,8 @@ int32_t adi_ad9081_device_clk_config_set(adi_ad9081_device_t *device, err = adi_ad9081_device_boot_pre_clock(device); AD9081_ERROR_RETURN(err); - /* enable dac digital logic */ - err = adi_ad9081_dac_digital_logic_enable_set(device, 1); + /* enable digital logic */ + err = adi_ad9081_device_digital_logic_enable_set(device, 1); AD9081_ERROR_RETURN(err); /* enable dac spi regs access */ @@ -841,7 +856,7 @@ int32_t adi_ad9081_device_init(adi_ad9081_device_t *device) "api v%d.%d.%d commit %s for ad%x ", (AD9081_API_REV & 0xff0000) >> 16, (AD9081_API_REV & 0xff00) >> 8, - (AD9081_API_REV & 0xff), "e1ac8d2", + (AD9081_API_REV & 0xff), "5b813df", AD9081_ID); AD9081_ERROR_RETURN(err); diff --git a/drivers/iio/adc/ad9081/adi_ad9081_sync.c b/drivers/iio/adc/ad9081/adi_ad9081_sync.c index b8009235d59906..d6398788a78b10 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_sync.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_sync.c @@ -92,12 +92,6 @@ int32_t adi_ad9081_jesd_oneshot_sync(adi_ad9081_device_t *device, AD9081_NULL_POINTER_RETURN(device); AD9081_LOG_FUNC(); - if (subclass == JESD_SUBCLASS_0) { - adi_ad9081_jesd_tx_force_digital_reset_set( - device, AD9081_LINK_ALL, - 1); /* FORCE_LINK_RESET if subclass 0 */ - } - err = adi_ad9081_hal_bf_get(device, REG_CLK_CTRL1_ADDR, 0x00000102, &pd_fdacby4, 1); /* not paged */ AD9081_ERROR_RETURN(err); @@ -108,9 +102,11 @@ int32_t adi_ad9081_jesd_oneshot_sync(adi_ad9081_device_t *device, BF_ROTATION_MODE_INFO, 1); /* not paged */ AD9081_ERROR_RETURN(err); - //d2a0, d2a1, anacenter - err = adi_ad9081_dac_d2a_dual_spi_enable_set(device, AD9081_LINK_ALL, - 1); + err = adi_ad9081_hal_bf_set(device, REG_SPI_ENABLE_DAC_ADDR, + BF_SPI_EN_D2A0_INFO, 1); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_SPI_ENABLE_DAC_ADDR, + BF_SPI_EN_D2A1_INFO, 1); AD9081_ERROR_RETURN(err); err = adi_ad9081_hal_bf_set(device, REG_SPI_ENABLE_DAC_ADDR, BF_SPI_EN_ANACENTER_INFO, 1); @@ -157,17 +153,13 @@ int32_t adi_ad9081_jesd_oneshot_sync(adi_ad9081_device_t *device, 0); /* not paged */ AD9081_ERROR_RETURN(err); } + err = adi_ad9081_hal_bf_set(device, REG_CLK_CTRL1_ADDR, 0x00000102, pd_fdacby4); /* not paged */ AD9081_ERROR_RETURN(err); - if (subclass == JESD_SUBCLASS_0) { - adi_ad9081_jesd_tx_force_digital_reset_set( - device, AD9081_LINK_ALL, - 0); /* FORCE_LINK_RESET if subclass 0 */ - if (sync_done != 1) { - return API_CMS_ERROR_JESD_SYNC_NOT_DONE; - } + if (sync_done != 1) { + return API_CMS_ERROR_JESD_SYNC_NOT_DONE; } return API_CMS_ERROR_OK; From 3e822d9333a516af21c339d958cee1e33c7ad895 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 9 Feb 2022 14:19:09 +0100 Subject: [PATCH 162/407] iio: jesd204: axi_adxcvr: Option to delay jesd204_fsm_start() This is particular useful in multi-topology setup, where one RX topology uses QPLL without access to it. So RX should be can be delayed, until TX has configured the QPLL. This is more a workaround than a real solution. The proper solution will be available after the all adxcvr core instances have full DRP access. Signed-off-by: Michael Hennerich --- drivers/iio/jesd204/axi_adxcvr.c | 23 ++++++++++++++++++++--- drivers/iio/jesd204/axi_adxcvr.h | 2 ++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/iio/jesd204/axi_adxcvr.c b/drivers/iio/jesd204/axi_adxcvr.c index 4d3ddc306caba8..9668ad6589ac41 100644 --- a/drivers/iio/jesd204/axi_adxcvr.c +++ b/drivers/iio/jesd204/axi_adxcvr.c @@ -910,6 +910,9 @@ static void adxcvr_parse_dt(struct adxcvr_state *st, struct device_node *np) st->cpll_enable = st->sys_clk_sel == XCVR_CPLL; + of_property_read_u32(np, "adi,jesd204-fsm-delayed-start-ms", + &st->fsm_enable_delay_ms); + adxcvr_parse_dt_vco_ranges(st, np); } @@ -989,6 +992,14 @@ static void adxcvr_device_remove_files(void *data) device_remove_file(st->dev, &dev_attr_reg_access); } +static void adxcvr_fsm_en_work(struct work_struct *work) +{ + struct adxcvr_state *st = + container_of(work, struct adxcvr_state, jesd_fsm_en_work.work); + + jesd204_fsm_start(st->jdev, JESD204_LINKS_ALL); +} + static int adxcvr_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1162,9 +1173,15 @@ static int adxcvr_probe(struct platform_device *pdev) devm_add_action_or_reset(st->dev, adxcvr_device_remove_files, st); - ret = jesd204_fsm_start(st->jdev, JESD204_LINKS_ALL); - if (ret) - goto unreg_eyescan; + if (st->fsm_enable_delay_ms) { + INIT_DELAYED_WORK(&st->jesd_fsm_en_work, adxcvr_fsm_en_work); + schedule_delayed_work(&st->jesd_fsm_en_work, + msecs_to_jiffies(st->fsm_enable_delay_ms)); + } else { + ret = jesd204_fsm_start(st->jdev, JESD204_LINKS_ALL); + if (ret) + goto unreg_eyescan; + } dev_info(&pdev->dev, "AXI-ADXCVR-%s (%d.%.2d.%c) using %s on %s at 0x%08llX. Number of lanes: %d.", st->tx_enable ? "TX" : "RX", diff --git a/drivers/iio/jesd204/axi_adxcvr.h b/drivers/iio/jesd204/axi_adxcvr.h index 9252b0d23a1e9c..52a319e39c093e 100644 --- a/drivers/iio/jesd204/axi_adxcvr.h +++ b/drivers/iio/jesd204/axi_adxcvr.h @@ -70,12 +70,14 @@ struct adxcvr_state { struct clk_hw lane_clk_hw; struct clk_hw qpll_clk_hw; struct work_struct work; + struct delayed_work jesd_fsm_en_work; struct mutex mutex; unsigned long lane_rate; bool tx_enable; bool qpll_enable; u32 sys_clk_sel; u32 out_clk_sel; + u32 fsm_enable_delay_ms; struct clk *clks[3]; struct clk_onecell_data clk_lookup; From 23c862fb5bea40d9363da2658b4b993d3c12c89a Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 14 Feb 2022 10:32:52 +0100 Subject: [PATCH 163/407] iio: adc: ad9371: jesd204-fsm enable framers in clk_enable state This will allow the SERDES transceiver to better lock their CDR. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9371.c | 41 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/drivers/iio/adc/ad9371.c b/drivers/iio/adc/ad9371.c index adad04e0b11e80..1505f556e326f9 100644 --- a/drivers/iio/adc/ad9371.c +++ b/drivers/iio/adc/ad9371.c @@ -4530,7 +4530,8 @@ static int ad9371_jesd204_clks_enable(struct jesd204_dev *jdev, if (reason != JESD204_STATE_OP_REASON_INIT) return JESD204_STATE_CHANGE_DONE; - dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, lnk->link_id, jesd204_state_op_reason_str(reason)); + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, + lnk->link_id, jesd204_state_op_reason_str(reason)); if (!lnk->num_converters) return JESD204_STATE_CHANGE_DONE; @@ -4557,6 +4558,12 @@ static int ad9371_jesd204_clks_enable(struct jesd204_dev *jdev, getMykonosErrorMessage(ret), ret); return -EFAULT; } + ret = MYKONOS_enableSysrefToRxFramer(mykDevice, 1); + if (ret) { + dev_err(&phy->spi->dev, "%s (%d)", + getMykonosErrorMessage(ret), ret); + return -EFAULT; + } break; case FRAMER_LINK_ORX: ret = MYKONOS_enableSysrefToObsRxFramer(mykDevice, 0); @@ -4565,6 +4572,12 @@ static int ad9371_jesd204_clks_enable(struct jesd204_dev *jdev, getMykonosErrorMessage(ret), ret); return -EFAULT; } + ret = MYKONOS_enableSysrefToObsRxFramer(mykDevice, 1); + if (ret) { + dev_err(&phy->spi->dev, "%s (%d)", + getMykonosErrorMessage(ret), ret); + return -EFAULT; + } break; default: return -EINVAL; @@ -4586,38 +4599,19 @@ static int ad9371_jesd204_link_enable(struct jesd204_dev *jdev, if (reason != JESD204_STATE_OP_REASON_INIT) return JESD204_STATE_CHANGE_DONE; - dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, lnk->link_id, jesd204_state_op_reason_str(reason)); + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, + lnk->link_id, jesd204_state_op_reason_str(reason)); if (!lnk->num_converters) return JESD204_STATE_CHANGE_DONE; - switch (lnk->link_id) { - case DEFRAMER_LINK_TX: + if (lnk->link_id == DEFRAMER_LINK_TX) { ret = MYKONOS_enableSysrefToDeframer(mykDevice, 1); if (ret) { dev_err(&phy->spi->dev, "%s (%d)", getMykonosErrorMessage(ret), ret); return -EFAULT; } - break; - case FRAMER_LINK_RX: - ret = MYKONOS_enableSysrefToRxFramer(mykDevice, 1); - if (ret) { - dev_err(&phy->spi->dev, "%s (%d)", - getMykonosErrorMessage(ret), ret); - return -EFAULT; - } - break; - case FRAMER_LINK_ORX: - ret = MYKONOS_enableSysrefToObsRxFramer(mykDevice, 1); - if (ret) { - dev_err(&phy->spi->dev, "%s (%d)", - getMykonosErrorMessage(ret), ret); - return -EFAULT; - } - break; - default: - return -EINVAL; } return JESD204_STATE_CHANGE_DONE; @@ -4791,6 +4785,7 @@ static const struct jesd204_dev_data jesd204_ad9371_init = { }, [JESD204_OP_CLOCKS_ENABLE] = { .per_link = ad9371_jesd204_clks_enable, + .post_state_sysref = true, }, [JESD204_OP_LINK_ENABLE] = { .per_link = ad9371_jesd204_link_enable, From 924781bc687dbd5091e91ca2292d3b943a8c833c Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 14 Feb 2022 10:34:36 +0100 Subject: [PATCH 164/407] iio: adc: ad9371: On remove tear down the jesd204-fsm This will allow a clean probe, in case the device is bound again. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9371.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/adc/ad9371.c b/drivers/iio/adc/ad9371.c index 1505f556e326f9..bbce6f23706079 100644 --- a/drivers/iio/adc/ad9371.c +++ b/drivers/iio/adc/ad9371.c @@ -5026,6 +5026,8 @@ static int ad9371_remove(struct spi_device *spi) { struct ad9371_rf_phy *phy = ad9371_spi_to_phy(spi); + jesd204_fsm_stop(phy->jdev, JESD204_LINKS_ALL); + jesd204_fsm_clear_errors(phy->jdev, JESD204_LINKS_ALL); release_firmware(phy->fw); sysfs_remove_bin_file(&phy->indio_dev->dev.kobj, &phy->bin); sysfs_remove_bin_file(&phy->indio_dev->dev.kobj, &phy->bin_gt); From fb6539f67a6a3b15a4c229c60562e28fb36e6cec Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 14 Feb 2022 12:27:55 +0100 Subject: [PATCH 165/407] iio: adc: ad9208: Support for logical lane mapping via devicetree This patch adds support for setting the physical->logical lane mapping via devicetree attribute 'adi,logic-lanes-mapping' Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9208.c | 25 ++++- drivers/iio/adc/ad9208/ad9208_jesd_api.c | 118 +++++++++++++++-------- 2 files changed, 101 insertions(+), 42 deletions(-) diff --git a/drivers/iio/adc/ad9208.c b/drivers/iio/adc/ad9208.c index 57d1842e812c17..070c9f474d4878 100644 --- a/drivers/iio/adc/ad9208.c +++ b/drivers/iio/adc/ad9208.c @@ -101,6 +101,8 @@ struct ad9208_phy { u32 sysref_pos_window_skew; u32 sysref_mode; u32 sysref_count; + u8 logical_lane_mapping[8]; + struct ad9208_ddc ddc[4]; }; @@ -765,7 +767,7 @@ static int ad9208_setup(struct spi_device *spi) struct ad9208_phy *phy = conv->phy; uint64_t lane_rate_kbps; - u8 pll_stat, dcm; + u8 pll_stat, dcm, lanes; int ret, timeout, i; u64 sample_rate; ad9208_adc_data_frmt_t input_fmt, output_fmt; @@ -911,6 +913,27 @@ static int ad9208_setup(struct spi_device *spi) } } + if (phy->ad9208.model == 0x9680) + lanes = ARRAY_SIZE(phy->logical_lane_mapping) / 2; + else + lanes = ARRAY_SIZE(phy->logical_lane_mapping); + + ret = of_property_read_u8_array(spi->dev.of_node, + "adi,logic-lanes-mapping", + phy->logical_lane_mapping, lanes); + if (!ret) { + for (i = 0; i < lanes; i++) { + ret = ad9208_jesd_set_lane_xbar(&phy->ad9208, i, + phy->logical_lane_mapping[i]); + if (ret) { + dev_err(&spi->dev, + "Failed to set jesd204 logical lane mapping %d, %u\n", + i, phy->logical_lane_mapping[i]); + return ret; + } + } + } + ret = ad9208_jesd_syref_lmfc_offset_set(&phy->ad9208, phy->sysref_lmfc_offset); diff --git a/drivers/iio/adc/ad9208/ad9208_jesd_api.c b/drivers/iio/adc/ad9208/ad9208_jesd_api.c index 0c30a7f9002ea0..3eb5b82b2fb0bb 100644 --- a/drivers/iio/adc/ad9208/ad9208_jesd_api.c +++ b/drivers/iio/adc/ad9208/ad9208_jesd_api.c @@ -365,43 +365,72 @@ int ad9208_jesd_set_lane_xbar(ad9208_handle_t *h, if ((physical_lane > (LANE_MAX - 1)) || (logical_lane > LANE_MAX - 1)) return API_ERROR_INVALID_PARAM; - switch (physical_lane) { - case 0: - case 1: - tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG; - break; - case 2: - case 3: - tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG + 1; - break; - case 4: - case 5: - tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG + 3; - break; - case 6: - case 7: - tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG + 4; - break; - default: - return API_ERROR_INVALID_PARAM; - } + if (h->model == 0x9680) { + if (logical_lane > 3) + return API_ERROR_INVALID_PARAM; - tmp_nibble = (physical_lane % 2) ? 1 : 0; + switch (physical_lane) { + case 0: + tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG; + break; + case 1: + tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG + 1; + break; + case 2: + tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG + 3; + break; + case 3: + tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG + 4; + break; + default: + return API_ERROR_INVALID_PARAM; + } - err = ad9208_register_read(h, tmp_reg_addr, &tmp_reg_val); - if (err != API_ERROR_OK) - return err; - if (tmp_nibble == 0) { - tmp_reg_val &= (~AD9208_JESD_XBAR_LN_EVEN(ALL)); - tmp_reg_val |= AD9208_JESD_XBAR_LN_EVEN(logical_lane); + err = ad9208_register_write(h, tmp_reg_addr, logical_lane); + if (err != API_ERROR_OK) + return err; } else { - tmp_reg_val &= (~AD9208_JESD_XBAR_LN_ODD(ALL)); - tmp_reg_val |= AD9208_JESD_XBAR_LN_ODD(logical_lane); - } - err = ad9208_register_write(h, tmp_reg_addr, tmp_reg_val); - if (err != API_ERROR_OK) - return err; + if ((physical_lane > (LANE_MAX - 1)) || (logical_lane > LANE_MAX - 1)) + return API_ERROR_INVALID_PARAM; + + switch (physical_lane) { + case 0: + case 1: + tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG; + break; + case 2: + case 3: + tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG + 1; + break; + case 4: + case 5: + tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG + 3; + break; + case 6: + case 7: + tmp_reg_addr = AD9208_JESD_XBAR_CFG_REG + 4; + break; + default: + return API_ERROR_INVALID_PARAM; + } + + tmp_nibble = (physical_lane % 2) ? 1 : 0; + + err = ad9208_register_read(h, tmp_reg_addr, &tmp_reg_val); + if (err != API_ERROR_OK) + return err; + if (tmp_nibble == 0) { + tmp_reg_val &= (~AD9208_JESD_XBAR_LN_EVEN(ALL)); + tmp_reg_val |= AD9208_JESD_XBAR_LN_EVEN(logical_lane); + } else { + tmp_reg_val &= (~AD9208_JESD_XBAR_LN_ODD(ALL)); + tmp_reg_val |= AD9208_JESD_XBAR_LN_ODD(logical_lane); + } + err = ad9208_register_write(h, tmp_reg_addr, tmp_reg_val); + if (err != API_ERROR_OK) + return err; + } return API_ERROR_OK; } @@ -423,14 +452,21 @@ int ad9208_jesd_get_lane_xbar(ad9208_handle_t *h, uint8_t *phy_log_map) if (err != API_ERROR_OK) return err; } - phy_log_map[0] = tmp_reg[0] & AD9208_JESD_XBAR_LN_EVEN(ALL); - phy_log_map[1] = (tmp_reg[0] & AD9208_JESD_XBAR_LN_ODD(ALL)) >> 4; - phy_log_map[2] = tmp_reg[1] & AD9208_JESD_XBAR_LN_EVEN(ALL); - phy_log_map[3] = (tmp_reg[1] & AD9208_JESD_XBAR_LN_ODD(ALL)) >> 4; - phy_log_map[4] = tmp_reg[3] & AD9208_JESD_XBAR_LN_EVEN(ALL); - phy_log_map[5] = (tmp_reg[3] & AD9208_JESD_XBAR_LN_ODD(ALL)) >> 4; - phy_log_map[6] = tmp_reg[4] & AD9208_JESD_XBAR_LN_EVEN(ALL); - phy_log_map[7] = (tmp_reg[4] & AD9208_JESD_XBAR_LN_ODD(ALL)) >> 4; + if (h->model == 0x9680) { + phy_log_map[0] = tmp_reg[0] & AD9208_JESD_XBAR_LN_EVEN(ALL); + phy_log_map[1] = tmp_reg[1] & AD9208_JESD_XBAR_LN_EVEN(ALL); + phy_log_map[2] = tmp_reg[3] & AD9208_JESD_XBAR_LN_EVEN(ALL); + phy_log_map[3] = tmp_reg[4] & AD9208_JESD_XBAR_LN_EVEN(ALL); + } else { + phy_log_map[0] = tmp_reg[0] & AD9208_JESD_XBAR_LN_EVEN(ALL); + phy_log_map[1] = (tmp_reg[0] & AD9208_JESD_XBAR_LN_ODD(ALL)) >> 4; + phy_log_map[2] = tmp_reg[1] & AD9208_JESD_XBAR_LN_EVEN(ALL); + phy_log_map[3] = (tmp_reg[1] & AD9208_JESD_XBAR_LN_ODD(ALL)) >> 4; + phy_log_map[4] = tmp_reg[3] & AD9208_JESD_XBAR_LN_EVEN(ALL); + phy_log_map[5] = (tmp_reg[3] & AD9208_JESD_XBAR_LN_ODD(ALL)) >> 4; + phy_log_map[6] = tmp_reg[4] & AD9208_JESD_XBAR_LN_EVEN(ALL); + phy_log_map[7] = (tmp_reg[4] & AD9208_JESD_XBAR_LN_ODD(ALL)) >> 4; + } return API_ERROR_OK; } From 479d9850a3cc4e776a34047b2766f83fca3917be Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 14 Feb 2022 12:31:13 +0100 Subject: [PATCH 166/407] iio: adc: ad9208: On remove tear down the jesd204-fsm This will allow a clean probe, in case the device is bound again. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9208.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad9208.c b/drivers/iio/adc/ad9208.c index 070c9f474d4878..b481d74942c945 100644 --- a/drivers/iio/adc/ad9208.c +++ b/drivers/iio/adc/ad9208.c @@ -1620,12 +1620,15 @@ static int ad9208_remove(struct spi_device *spi) struct axiadc_converter *conv = spi_get_drvdata(spi); struct ad9208_phy *phy = conv->phy; + jesd204_fsm_stop(phy->jdev, JESD204_LINKS_ALL); + jesd204_fsm_clear_errors(phy->jdev, JESD204_LINKS_ALL); clk_disable_unprepare(conv->clk); if (!IS_ERR_OR_NULL(conv->sysref_clk)) clk_disable_unprepare(conv->sysref_clk); - clk_disable_unprepare(conv->lane_clk); + if (!IS_ERR_OR_NULL(conv->lane_clk)) + clk_disable_unprepare(conv->lane_clk); ad9208_deinit(&phy->ad9208); From 7d9bd62e372cea6f6b8ecb6a4c29f29661e43270 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 14 Feb 2022 12:39:07 +0100 Subject: [PATCH 167/407] dts: zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-sc1: SC1 example New use case with JESD204 Subclass 1 support. Signed-off-by: Michael Hennerich --- ...ev10-ad9082-204c-txmode22-rxmode23-sc1.dts | 374 ++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-sc1.dts diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-sc1.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-sc1.dts new file mode 100644 index 00000000000000..f6df26372141d5 --- /dev/null +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-sc1.dts @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD9082-FMC-EBZ + * https://wiki.analog.com/resources/eval/user-guides/quadmxfe/quick-start + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2022 Analog Devices Inc. + */ + +// ad9081_204b_txmode_0_rxmode_1: 204C use case with Subclass 0, +// Med. lane rate, using gearbox and PRGOGDIV +// * 1Txs / 1Rxs per MxFE +// * DAC_CLK = 11.52GSPS +// * ADC_CLK = 3.84GSPS +// * Tx I/Q Rate: 960 MSPS (Interpolation of 12x1) +// * Rx I/Q Rate: 960 MSPS (Decimation of 4x1) +// * DAC JESD204B: Mode 22, L=2, M=2, N=N'=12 +// * ADC JESD204B: Mode 23, L=2, M=2, N=N'=12 +// * DAC-Side JESD204B Lane Rate: 11.88Gbps +// * ADC-Side JESD204B Lane Rate: 11.88Gbps + +// HDL Synthesis Parameters: +// JESD_MODE=64B66B \ +// RX_RATE=12 \ +// RX_PLL_SEL=2 \ +// TX_RATE=12 \ +// TX_PLL_SEL=2 \ +// REF_CLK_RATE=180 \ +// RX_JESD_M=2 \ +// RX_JESD_L=2 \ +// RX_JESD_S=4 \ +// RX_JESD_NP=12 \ +// TX_JESD_M=2 \ +// TX_JESD_L=2 \ +// TX_JESD_S=2 \ +// TX_JESD_NP=12 + +#include "zynqmp-zcu102-rev10-ad9081.dts" + +/ { + axi-jesd204-rx@0 { + compatible = "adi,iio-fake-platform-device"; + adi,faked-dev = <&axi_ad9081_rx_jesd>; + adi,attribute-names = + "status", "encoder", "lane0_info", "lane1_info", + "lane2_info", "lane3_info"; + label = "axi-jesd204-rx"; + }; + + axi-jesd204-rx@1 { + compatible = "adi,iio-fake-platform-device"; + adi,faked-dev = <&axi_ad9081_tx_jesd>; + adi,attribute-names = "status", "encoder"; + label = "axi-jesd204-rx"; + }; + + axi-adxcvr-rx@2 { + compatible = "adi,iio-fake-platform-device"; + adi,faked-dev = <&axi_ad9081_adxcvr_rx>; + adi,attribute-names = + "eyescan_info", "prbs_status", "prbs_counter_reset", + "prescale", "enable", "prbs_error_counters", "reg_access", + "eye_data", "prbs_select"; + label = "axi-adxcvr-rx"; + }; + + axi-adxcvr-tx@4 { + compatible = "adi,iio-fake-platform-device"; + adi,faked-dev = <&axi_ad9081_adxcvr_tx>; + adi,attribute-names = "prbs_select", "prbs_error_inject", "reg_access"; + label = "axi-adxcvr-tx"; + }; +}; + +&axi_ad9081_rx_jesd { + clocks = <&zynqmp_clk 71>, <&hmc7044 10>, <&axi_ad9081_adxcvr_rx 1>, <&axi_ad9081_adxcvr_rx 0>; + clock-names = "s_axi_aclk", "device_clk", "link_clk", "lane_clk"; +}; + +&axi_ad9081_tx_jesd { + clocks = <&zynqmp_clk 71>, <&hmc7044 6>, <&axi_ad9081_adxcvr_tx 1>, <&axi_ad9081_adxcvr_tx 0>; + clock-names = "s_axi_aclk", "device_clk", "link_clk", "lane_clk"; +}; + +&axi_ad9081_adxcvr_rx { + adi,sys-clk-select = ; + adi,out-clk-select = ; +}; + +&axi_ad9081_adxcvr_tx { + adi,sys-clk-select = ; + adi,out-clk-select = ; +}; + +&spi1 { + status = "okay"; + + /delete-node/ hmc7044@0; + + hmc7044: hmc7044@0 { + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + compatible = "adi,hmc7044"; + reg = <0>; + spi-max-frequency = <1000000>; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-sysref-provider; + + adi,jesd204-max-sysref-frequency-hz = <2000000>; /* 2 MHz */ + + /* + * There are different versions of the AD9081-FMCA-EBZ & AD9082-FMCA-EBZ + * VCXO = 122.880 MHz, XO = 122.880MHz (AD9081-FMC-EBZ & AD9082-FMC-EBZ) + * VCXO = 100.000 MHz, XO = 100.000MHz (AD9081-FMC-EBZ-A2 & AD9082-FMC-EBZ-A2) + * To determine which board is which, read the freqency printed on the VCXO + * or use the fru-dump utility: + * #fru-dump -b /sys/bus/i2c/devices/15-0050/eeprom + */ + + //adi,pll1-clkin-frequencies = <122880000 30720000 0 0>; + //adi,vcxo-frequency = <122880000>; + + adi,pll1-clkin-frequencies = <100000000 10000000 0 0>; + adi,vcxo-frequency = <100000000>; + + adi,pll1-loop-bandwidth-hz = <200>; + + adi,pll2-output-frequency = <2880000000>; + + adi,sysref-timer-divider = <1024>; + adi,pulse-generator-mode = <0>; + + adi,clkin0-buffer-mode = <0x07>; + adi,clkin1-buffer-mode = <0x07>; + adi,oscin-buffer-mode = <0x15>; + + adi,gpi-controls = <0x00 0x00 0x00 0x00>; + adi,gpo-controls = <0x37 0x33 0x00 0x00>; + + clock-output-names = + "hmc7044_out0", "hmc7044_out1", "hmc7044_out2", + "hmc7044_out3", "hmc7044_out4", "hmc7044_out5", + "hmc7044_out6", "hmc7044_out7", "hmc7044_out8", + "hmc7044_out9", "hmc7044_out10", "hmc7044_out11", + "hmc7044_out12", "hmc7044_out13"; + + hmc7044_c0: channel@0 { + reg = <0>; + adi,extended-name = "CORE_CLK_RX"; + adi,divider = <48>; + adi,driver-mode = ; + + }; + hmc7044_c2: channel@2 { + reg = <2>; + adi,extended-name = "DEV_REFCLK"; + adi,divider = <4>; /* 720 MHz */ + adi,driver-mode = ; + }; + + hmc7044_c3: channel@3 { + reg = <3>; + adi,extended-name = "DEV_SYSREF"; + adi,divider = <768>; + adi,driver-mode = ; + adi,jesd204-sysref-chan; + //adi,disable; /* Completely disable channel */ + }; + + hmc7044_c6: channel@6 { + reg = <6>; + adi,extended-name = "CORE_CLK_TX"; + adi,divider = <24>; + adi,driver-mode = ; + }; + + hmc7044_c8: channel@8 { + reg = <8>; + adi,extended-name = "FPGA_REFCLK1"; + adi,divider = <64>; + adi,driver-mode = ; + }; + + hmc7044_c10: channel@10 { + reg = <10>; + adi,extended-name = "CORE_CLK_RX_ALT"; + adi,divider = <48>; + adi,driver-mode = ; + }; + + hmc7044_c12: channel@12 { + reg = <12>; + adi,extended-name = "FPGA_REFCLK2"; + adi,divider = <8>; + adi,driver-mode = ; + }; + + hmc7044_c13: channel@13 { + reg = <13>; + adi,extended-name = "FPGA_SYSREF"; + adi,divider = <768>; + adi,driver-mode = ; + adi,jesd204-sysref-chan; + //adi,disable; /* Completely disable channel */ + }; + }; +}; + +&fmc_spi { + /delete-node/ ad9081@0; + + trx0_ad9081: ad9082@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,ad9081"; + reg = <0>; + spi-max-frequency = <5000000>; + + reset-gpios = <&gpio 133 0>; + + /* Clocks */ + clocks = <&hmc7044 2>; + clock-names = "dev_clk"; + + clock-output-names = "rx_sampl_clk", "tx_sampl_clk"; + #clock-cells = <1>; + + jesd204-device; + #jesd204-cells = <2>; + jesd204-top-device = <0>; /* This is the TOP device */ + jesd204-link-ids = ; + + jesd204-inputs = + <&axi_ad9081_core_rx 0 FRAMER_LINK0_RX>, + <&axi_ad9081_core_tx 0 DEFRAMER_LINK0_TX>; + + adi,continuous-sysref-mode-disable; + + adi,tx-dacs { + #size-cells = <0>; + #address-cells = <1>; + + adi,dac-frequency-hz = /bits/ 64 <11520000000>; + + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + + adi,interpolation = <12>; + + ad9081_dac0: dac@0 { + reg = <0>; + adi,crossbar-select = <&ad9081_tx_fddc_chan0>; + adi,nco-frequency-shift-hz = /bits/ 64 <1000000000>; /* 1000 MHz */ + }; + }; + + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = <1>; + + ad9081_tx_fddc_chan0: channel@0 { + reg = <0>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + }; + + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + + ad9081_tx_jesd_l0: link@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + adi,logical-lane-mapping = /bits/ 8 <0 2 7 7 1 7 7 3>; + + adi,link-mode = <22>; /* JESD Quick Configuration Mode */ + adi,subclass = <1>; /* JESD SUBCLASS 0,1,2 */ + adi,version = <2>; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + + adi,converters-per-device = <2>; /* JESD M */ + adi,octets-per-frame = <3>; /* JESD F */ + + adi,frames-per-multiframe = <256>; /* JESD K */ + adi,converter-resolution = <12>; /* JESD N */ + adi,bits-per-sample = <12>; /* JESD NP' */ + adi,control-bits-per-sample = <0>; /* JESD CS */ + adi,lanes-per-device = <2>; /* JESD L */ + adi,samples-per-converter-per-frame = <2>; /* JESD S */ + adi,high-density = <0>; /* JESD HD */ + + adi,tpl-phase-adjust = <25>; + }; + }; + }; + + adi,rx-adcs { + #size-cells = <0>; + #address-cells = <1>; + + adi,adc-frequency-hz = /bits/ 64 <3840000000>; + + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + + ad9081_adc0: adc@0 { + reg = <0>; + adi,decimation = <4>; + adi,nco-frequency-shift-hz = /bits/ 64 <400000000>; + adi,nco-mixer-mode = ; + }; + }; + + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + + ad9081_rx_fddc_chan0: channel@0 { + reg = <0>; + adi,decimation = <1>; + adi,gain = <2048>; /* 2048 * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 <0>; + + }; + }; + + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + + ad9081_rx_jesd_l0: link@0 { + reg = <0>; + adi,converter-select = + <&ad9081_rx_fddc_chan0 FDDC_I>, <&ad9081_rx_fddc_chan0 FDDC_Q>; + + adi,logical-lane-mapping = /bits/ 8 <2 0 7 7 7 7 3 1>; + + adi,link-mode = <23>; /* JESD Quick Configuration Mode */ + adi,subclass = <1>; /* JESD SUBCLASS 0,1,2 */ + adi,version = <2>; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + + adi,converters-per-device = <2>; /* JESD M */ + adi,octets-per-frame = <6>; /* JESD F */ + + adi,frames-per-multiframe = <128>; /* JESD K */ + adi,converter-resolution = <12>; /* JESD N */ + adi,bits-per-sample = <12>; /* JESD NP' */ + adi,control-bits-per-sample = <0>; /* JESD CS */ + adi,lanes-per-device = <2>; /* JESD L */ + adi,samples-per-converter-per-frame = <4>; /* JESD S */ + adi,high-density = <0>; /* JESD HD */ + }; + }; + }; + }; +}; + +&axi_ad9081_core_tx { + single-shot-output-gpios = <&gpio 139 0>; +}; From eafba17d5d798cd836768641e9b558e578472c6a Mon Sep 17 00:00:00 2001 From: Dan Hotoleanu Date: Tue, 10 Aug 2021 12:50:24 +0100 Subject: [PATCH 168/407] drivers/iio/adc/ad9467: AD9250 Update fmcjesdadc1 based on hdl update Updated the project as a consequence of the HDl project update. The current modification takes into consideration the fact that the data path for the ADC data has changed. The modification is that there is now a single instance of the JESD TPL, the cpack and the ADC data dma. Signed-off-by: Dan Hotoleanu Signed-off-by: Cristian Pop --- arch/arm/boot/dts/adi-fmcjesdadc1.dtsi | 4 +- .../dts/zynq-zc706-adv7511-fmcjesdadc1.dts | 41 +++---------------- arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi | 4 +- drivers/iio/adc/ad9467.c | 15 +++++++ 4 files changed, 25 insertions(+), 39 deletions(-) diff --git a/arch/arm/boot/dts/adi-fmcjesdadc1.dtsi b/arch/arm/boot/dts/adi-fmcjesdadc1.dtsi index 9efab2409e9345..54371538c342c9 100644 --- a/arch/arm/boot/dts/adi-fmcjesdadc1.dtsi +++ b/arch/arm/boot/dts/adi-fmcjesdadc1.dtsi @@ -44,7 +44,7 @@ }; adc0_ad9250: ad9250-0@0 { - compatible = "adi,ad9250"; + compatible = "adi,ad9250_2"; reg = <2>; spi-max-frequency = <10000000>; @@ -54,7 +54,7 @@ }; adc1_ad9250: ad9250-1@1 { - compatible = "adi,ad9250"; + compatible = "adi,ad9250_2"; reg = <3>; spi-max-frequency = <10000000>; diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts index 629fd1b1ad19ef..e4ef4bb1294d31 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmcjesdadc1.dts @@ -33,7 +33,7 @@ }; &fpga_axi { - rx_dma0: rx-dmac@7c420000 { + rx_dma: rx-dmac@7c420000 { compatible = "adi,axi-dmac-1.00.a"; reg = <0x7c420000 0x10000>; #dma-cells = <1>; @@ -46,53 +46,23 @@ dma-channel@0 { reg = <0>; - adi,source-bus-width = <64>; + adi,source-bus-width = <128>; adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; + adi,destination-bus-width = <128>; adi,destination-bus-type = <0>; }; }; }; - rx_dma1: rx-dmac@7c430000 { - compatible = "adi,axi-dmac-1.00.a"; - reg = <0x7c430000 0x10000>; - #dma-cells = <1>; - interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clkc 16>; - - adi,channels { - #address-cells = <1>; - #size-cells = <0>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; - }; - - axi_ad9250_core0: axi-ad9250-hpc-0@44a10000 { + axi_ad9250_core: axi-ad9250-hpc-0@44a10000 { compatible = "xlnx,axi-ad9250-1.00.a"; reg = <0x44a10000 0x10000>; - dmas = <&rx_dma0 0>; + dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&adc0_ad9250>; }; - axi_ad9250_core1: axi-ad9250-hpc-1@44a20000 { - compatible = "xlnx,axi-ad9250-1.00.a"; - reg = <0x44a20000 0x10000>; - dmas = <&rx_dma1 0>; - dma-names = "rx"; - - spibus-connected = <&adc1_ad9250>; - }; - axi_jesd: axi-jesd204-rx@44aa0000 { compatible = "adi,axi-jesd204-rx-1.0"; reg = <0x44aa0000 0x1000>; @@ -121,6 +91,7 @@ adi,sys-clk-select = ; adi,out-clk-select = ; + adi,use-cpll-enable; }; }; diff --git a/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi b/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi index 9714c7b0396313..53cfd73043a289 100644 --- a/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi +++ b/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi @@ -36,7 +36,7 @@ }; adc0_ad9250: ad9250-0@0 { - compatible = "adi,ad9250"; + compatible = "adi,ad9250_2"; reg = <2>; spi-max-frequency = <10000000>; clocks = <&axi_jesd>, <&clk_ad9517 0>; @@ -44,7 +44,7 @@ }; adc1_ad9250: ad9250-1@1 { - compatible = "adi,ad9250"; + compatible = "adi,ad9250_2"; reg = <3>; spi-max-frequency = <10000000>; clocks = <&axi_jesd>, <&clk_ad9517 1>; diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index 94e629a3720d75..85cd6d60cda8b6 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -159,6 +159,7 @@ enum { ID_AD9467, ID_AD9643, ID_AD9250, + ID_AD9250_2, ID_AD9265, ID_AD9683, ID_AD9625, @@ -754,6 +755,19 @@ static const struct axiadc_chip_info ad9467_chip_tbl[] = { .channel[0] = AIM_CHAN_NOCALIB(0, 0, 14, 'S', 0), .channel[1] = AIM_CHAN_NOCALIB(1, 1, 14, 'S', 0), }, + [ID_AD9250_2] = { + .name = "AD9250_2", + .id = CHIPID_AD9250, + .max_rate = 250000000UL, + .scale_table = ad9643_scale_table, + .num_scales = ARRAY_SIZE(ad9643_scale_table), + .max_testmode = AN877_ADC_TESTMODE_RAMP, + .num_channels = 4, + .channel[0] = AIM_CHAN_NOCALIB(0, 0, 14, 'S', 0), + .channel[1] = AIM_CHAN_NOCALIB(1, 1, 14, 'S', 0), + .channel[2] = AIM_CHAN_NOCALIB(2, 2, 14, 'S', 0), + .channel[3] = AIM_CHAN_NOCALIB(3, 3, 14, 'S', 0), + }, [ID_AD9683] = { .name = "AD9683", .id = CHIPID_AD9683, @@ -1268,6 +1282,7 @@ static const struct of_device_id ad9467_of_match[] = { { .compatible = "adi,ad9467", .data = &ad9467_chip_tbl[ID_AD9467], }, { .compatible = "adi,ad9643", .data = &ad9467_chip_tbl[ID_AD9643], }, { .compatible = "adi,ad9250", .data = &ad9467_chip_tbl[ID_AD9250], }, + { .compatible = "adi,ad9250_2", .data = &ad9467_chip_tbl[ID_AD9250_2], }, { .compatible = "adi,ad9265", .data = &ad9467_chip_tbl[ID_AD9265], }, { .compatible = "adi,ad9683", .data = &ad9467_chip_tbl[ID_AD9683], }, { .compatible = "adi,ad9434", .data = &ad9467_chip_tbl[ID_AD9434], }, From 962ab3a83947bbefbdc5774053dfcaa65e435873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 11 Oct 2021 15:27:43 +0200 Subject: [PATCH 169/407] hwmon: (adt7x10) Make adt7x10_remove() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up to now adt7x10_remove() returns zero unconditionally. Make it return void instead which makes it easier to see in the callers that there is no error to handle. Also the return value of i2c and spi remove callbacks is ignored anyway. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20211011132754.2479853-3-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck (cherry picked from commit beee7890c36320fe08d9cce82afa1db848360bfb) --- drivers/hwmon/adt7310.c | 3 ++- drivers/hwmon/adt7410.c | 3 ++- drivers/hwmon/adt7x10.c | 3 +-- drivers/hwmon/adt7x10.h | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c index 9fad01191620c5..c40cac16af6838 100644 --- a/drivers/hwmon/adt7310.c +++ b/drivers/hwmon/adt7310.c @@ -90,7 +90,8 @@ static int adt7310_spi_probe(struct spi_device *spi) static int adt7310_spi_remove(struct spi_device *spi) { - return adt7x10_remove(&spi->dev, spi->irq); + adt7x10_remove(&spi->dev, spi->irq); + return 0; } static const struct spi_device_id adt7310_id[] = { diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index 3c294ba86028dd..013fcbef3e3ab1 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -50,7 +50,8 @@ static int adt7410_i2c_probe(struct i2c_client *client) static int adt7410_i2c_remove(struct i2c_client *client) { - return adt7x10_remove(&client->dev, client->irq); + adt7x10_remove(&client->dev, client->irq); + return 0; } static const struct i2c_device_id adt7410_ids[] = { diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c index 3f03b4cf585858..e9d33aa78a1937 100644 --- a/drivers/hwmon/adt7x10.c +++ b/drivers/hwmon/adt7x10.c @@ -444,7 +444,7 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, } EXPORT_SYMBOL_GPL(adt7x10_probe); -int adt7x10_remove(struct device *dev, int irq) +void adt7x10_remove(struct device *dev, int irq) { struct adt7x10_data *data = dev_get_drvdata(dev); @@ -457,7 +457,6 @@ int adt7x10_remove(struct device *dev, int irq) sysfs_remove_group(&dev->kobj, &adt7x10_group); if (data->oldconfig != data->config) adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig); - return 0; } EXPORT_SYMBOL_GPL(adt7x10_remove); diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h index 21ad15ce316370..a1ae682eb32e6b 100644 --- a/drivers/hwmon/adt7x10.h +++ b/drivers/hwmon/adt7x10.h @@ -26,7 +26,7 @@ struct adt7x10_ops { int adt7x10_probe(struct device *dev, const char *name, int irq, const struct adt7x10_ops *ops); -int adt7x10_remove(struct device *dev, int irq); +void adt7x10_remove(struct device *dev, int irq); #ifdef CONFIG_PM_SLEEP extern const struct dev_pm_ops adt7x10_dev_pm_ops; From 3cfcd084172f952e6bbd94e82ecfe29f8969bf04 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 23 Dec 2021 10:32:05 -0800 Subject: [PATCH 170/407] hwmon: (adt7x10) Convert to use regmap Using regmap lets us use the regmap subsystem for SPI vs. I2C register accesses. It lets us hide access differences in backend code and lets the common code just access registers without knowing their size. We can also use regmap for register caching. Tested-by: Cosmin Tanislav Reviewed-by: Cosmin Tanislav Signed-off-by: Guenter Roeck (cherry picked from commit e1116026e296685a42a1751980a0815a14f91a80) --- drivers/hwmon/Kconfig | 1 + drivers/hwmon/adt7310.c | 88 +++++++++++++--- drivers/hwmon/adt7410.c | 77 ++++++++++---- drivers/hwmon/adt7x10.c | 225 +++++++++++++++------------------------- drivers/hwmon/adt7x10.h | 10 +- 5 files changed, 213 insertions(+), 188 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index f86cc35f454f30..88b72411703d38 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -187,6 +187,7 @@ config SENSORS_ADM9240 config SENSORS_ADT7X10 tristate + select REGMAP help This module contains common code shared by the ADT7310/ADT7320 and ADT7410/ADT7420/ADT7422 temperature monitoring chip drivers. diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c index c40cac16af6838..a83092470bce4a 100644 --- a/drivers/hwmon/adt7310.c +++ b/drivers/hwmon/adt7310.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -38,16 +39,13 @@ static const u8 adt7310_reg_table[] = { #define AD7310_COMMAND(reg) (adt7310_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET) -static int adt7310_spi_read_word(struct device *dev, u8 reg) +static int adt7310_spi_read_word(struct spi_device *spi, u8 reg) { - struct spi_device *spi = to_spi_device(dev); - return spi_w8r16be(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ); } -static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data) +static int adt7310_spi_write_word(struct spi_device *spi, u8 reg, u16 data) { - struct spi_device *spi = to_spi_device(dev); u8 buf[3]; buf[0] = AD7310_COMMAND(reg); @@ -56,17 +54,13 @@ static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data) return spi_write(spi, buf, sizeof(buf)); } -static int adt7310_spi_read_byte(struct device *dev, u8 reg) +static int adt7310_spi_read_byte(struct spi_device *spi, u8 reg) { - struct spi_device *spi = to_spi_device(dev); - return spi_w8r8(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ); } -static int adt7310_spi_write_byte(struct device *dev, u8 reg, - u8 data) +static int adt7310_spi_write_byte(struct spi_device *spi, u8 reg, u8 data) { - struct spi_device *spi = to_spi_device(dev); u8 buf[2]; buf[0] = AD7310_COMMAND(reg); @@ -75,17 +69,77 @@ static int adt7310_spi_write_byte(struct device *dev, u8 reg, return spi_write(spi, buf, sizeof(buf)); } -static const struct adt7x10_ops adt7310_spi_ops = { - .read_word = adt7310_spi_read_word, - .write_word = adt7310_spi_write_word, - .read_byte = adt7310_spi_read_byte, - .write_byte = adt7310_spi_write_byte, +static bool adt7310_regmap_is_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADT7X10_TEMPERATURE: + case ADT7X10_STATUS: + return true; + default: + return false; + } +} + +static int adt7310_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct spi_device *spi = context; + int regval; + + switch (reg) { + case ADT7X10_TEMPERATURE: + case ADT7X10_T_ALARM_HIGH: + case ADT7X10_T_ALARM_LOW: + case ADT7X10_T_CRIT: + regval = adt7310_spi_read_word(spi, reg); + break; + default: + regval = adt7310_spi_read_byte(spi, reg); + break; + } + if (regval < 0) + return regval; + *val = regval; + return 0; +} + +static int adt7310_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct spi_device *spi = context; + int ret; + + switch (reg) { + case ADT7X10_TEMPERATURE: + case ADT7X10_T_ALARM_HIGH: + case ADT7X10_T_ALARM_LOW: + case ADT7X10_T_CRIT: + ret = adt7310_spi_write_word(spi, reg, val); + break; + default: + ret = adt7310_spi_write_byte(spi, reg, val); + break; + } + return ret; +} + +static const struct regmap_config adt7310_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = adt7310_regmap_is_volatile, + .reg_read = adt7310_reg_read, + .reg_write = adt7310_reg_write, }; static int adt7310_spi_probe(struct spi_device *spi) { + struct regmap *regmap; + + regmap = devm_regmap_init(&spi->dev, NULL, spi, &adt7310_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + return adt7x10_probe(&spi->dev, spi_get_device_id(spi)->name, spi->irq, - &adt7310_spi_ops); + regmap); } static int adt7310_spi_remove(struct spi_device *spi) diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index 013fcbef3e3ab1..59b32ef0433165 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -9,43 +9,82 @@ #include #include #include +#include #include "adt7x10.h" -static int adt7410_i2c_read_word(struct device *dev, u8 reg) +static bool adt7410_regmap_is_volatile(struct device *dev, unsigned int reg) { - return i2c_smbus_read_word_swapped(to_i2c_client(dev), reg); + switch (reg) { + case ADT7X10_TEMPERATURE: + case ADT7X10_STATUS: + return true; + default: + return false; + } } -static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data) +static int adt7410_reg_read(void *context, unsigned int reg, unsigned int *val) { - return i2c_smbus_write_word_swapped(to_i2c_client(dev), reg, data); -} + struct i2c_client *client = context; + int regval; -static int adt7410_i2c_read_byte(struct device *dev, u8 reg) -{ - return i2c_smbus_read_byte_data(to_i2c_client(dev), reg); + switch (reg) { + case ADT7X10_TEMPERATURE: + case ADT7X10_T_ALARM_HIGH: + case ADT7X10_T_ALARM_LOW: + case ADT7X10_T_CRIT: + regval = i2c_smbus_read_word_swapped(client, reg); + break; + default: + regval = i2c_smbus_read_byte_data(client, reg); + break; + } + if (regval < 0) + return regval; + *val = regval; + return 0; } -static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data) +static int adt7410_reg_write(void *context, unsigned int reg, unsigned int val) { - return i2c_smbus_write_byte_data(to_i2c_client(dev), reg, data); + struct i2c_client *client = context; + int ret; + + switch (reg) { + case ADT7X10_TEMPERATURE: + case ADT7X10_T_ALARM_HIGH: + case ADT7X10_T_ALARM_LOW: + case ADT7X10_T_CRIT: + ret = i2c_smbus_write_word_swapped(client, reg, val); + break; + default: + ret = i2c_smbus_write_byte_data(client, reg, val); + break; + } + return ret; } -static const struct adt7x10_ops adt7410_i2c_ops = { - .read_word = adt7410_i2c_read_word, - .write_word = adt7410_i2c_write_word, - .read_byte = adt7410_i2c_read_byte, - .write_byte = adt7410_i2c_write_byte, +static const struct regmap_config adt7410_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = ADT7X10_ID, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = adt7410_regmap_is_volatile, + .reg_read = adt7410_reg_read, + .reg_write = adt7410_reg_write, }; static int adt7410_i2c_probe(struct i2c_client *client) { - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) - return -ENODEV; + struct regmap *regmap; + + regmap = devm_regmap_init(&client->dev, NULL, client, + &adt7410_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - return adt7x10_probe(&client->dev, NULL, client->irq, &adt7410_i2c_ops); + return adt7x10_probe(&client->dev, NULL, client->irq, regmap); } static int adt7410_i2c_remove(struct i2c_client *client) diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c index e9d33aa78a1937..05dd48b707b443 100644 --- a/drivers/hwmon/adt7x10.c +++ b/drivers/hwmon/adt7x10.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "adt7x10.h" @@ -53,46 +54,15 @@ /* Each client has this additional data */ struct adt7x10_data { - const struct adt7x10_ops *ops; + struct regmap *regmap; const char *name; struct device *hwmon_dev; struct mutex update_lock; u8 config; u8 oldconfig; - bool valid; /* true if registers valid */ - unsigned long last_updated; /* In jiffies */ - s16 temp[4]; /* Register values, - 0 = input - 1 = high - 2 = low - 3 = critical */ - u8 hyst; /* hysteresis offset */ + bool valid; /* true if temperature valid */ }; -static int adt7x10_read_byte(struct device *dev, u8 reg) -{ - struct adt7x10_data *d = dev_get_drvdata(dev); - return d->ops->read_byte(dev, reg); -} - -static int adt7x10_write_byte(struct device *dev, u8 reg, u8 data) -{ - struct adt7x10_data *d = dev_get_drvdata(dev); - return d->ops->write_byte(dev, reg, data); -} - -static int adt7x10_read_word(struct device *dev, u8 reg) -{ - struct adt7x10_data *d = dev_get_drvdata(dev); - return d->ops->read_word(dev, reg); -} - -static int adt7x10_write_word(struct device *dev, u8 reg, u16 data) -{ - struct adt7x10_data *d = dev_get_drvdata(dev); - return d->ops->write_word(dev, reg, data); -} - static const u8 ADT7X10_REG_TEMP[4] = { ADT7X10_TEMPERATURE, /* input */ ADT7X10_T_ALARM_HIGH, /* high */ @@ -103,10 +73,12 @@ static const u8 ADT7X10_REG_TEMP[4] = { static irqreturn_t adt7x10_irq_handler(int irq, void *private) { struct device *dev = private; - int status; + struct adt7x10_data *d = dev_get_drvdata(dev); + unsigned int status; + int ret; - status = adt7x10_read_byte(dev, ADT7X10_STATUS); - if (status < 0) + ret = regmap_read(d->regmap, ADT7X10_STATUS, &status); + if (ret < 0) return IRQ_HANDLED; if (status & ADT7X10_STAT_T_HIGH) @@ -119,14 +91,15 @@ static irqreturn_t adt7x10_irq_handler(int irq, void *private) return IRQ_HANDLED; } -static int adt7x10_temp_ready(struct device *dev) +static int adt7x10_temp_ready(struct regmap *regmap) { - int i, status; + unsigned int status; + int i, ret; for (i = 0; i < 6; i++) { - status = adt7x10_read_byte(dev, ADT7X10_STATUS); - if (status < 0) - return status; + ret = regmap_read(regmap, ADT7X10_STATUS, &status); + if (ret < 0) + return ret; if (!(status & ADT7X10_STAT_NOT_RDY)) return 0; msleep(60); @@ -134,71 +107,10 @@ static int adt7x10_temp_ready(struct device *dev) return -ETIMEDOUT; } -static int adt7x10_update_temp(struct device *dev) -{ - struct adt7x10_data *data = dev_get_drvdata(dev); - int ret = 0; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - int temp; - - dev_dbg(dev, "Starting update\n"); - - ret = adt7x10_temp_ready(dev); /* check for new value */ - if (ret) - goto abort; - - temp = adt7x10_read_word(dev, ADT7X10_REG_TEMP[0]); - if (temp < 0) { - ret = temp; - dev_dbg(dev, "Failed to read value: reg %d, error %d\n", - ADT7X10_REG_TEMP[0], ret); - goto abort; - } - data->temp[0] = temp; - data->last_updated = jiffies; - data->valid = true; - } - -abort: - mutex_unlock(&data->update_lock); - return ret; -} - -static int adt7x10_fill_cache(struct device *dev) -{ - struct adt7x10_data *data = dev_get_drvdata(dev); - int ret; - int i; - - for (i = 1; i < ARRAY_SIZE(data->temp); i++) { - ret = adt7x10_read_word(dev, ADT7X10_REG_TEMP[i]); - if (ret < 0) { - dev_dbg(dev, "Failed to read value: reg %d, error %d\n", - ADT7X10_REG_TEMP[i], ret); - return ret; - } - data->temp[i] = ret; - } - - ret = adt7x10_read_byte(dev, ADT7X10_T_HYST); - if (ret < 0) { - dev_dbg(dev, "Failed to read value: reg %d, error %d\n", - ADT7X10_T_HYST, ret); - return ret; - } - data->hyst = ret; - - return 0; -} - static s16 ADT7X10_TEMP_TO_REG(long temp) { return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7X10_TEMP_MIN, - ADT7X10_TEMP_MAX) * 128, 1000); + ADT7X10_TEMP_MAX) * 128, 1000); } static int ADT7X10_REG_TO_TEMP(struct adt7x10_data *data, s16 reg) @@ -222,18 +134,26 @@ static ssize_t adt7x10_temp_show(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct adt7x10_data *data = dev_get_drvdata(dev); + unsigned int val; + int ret; - - if (attr->index == 0) { - int ret; - - ret = adt7x10_update_temp(dev); - if (ret) + mutex_lock(&data->update_lock); + if (attr->index == 0 && !data->valid) { + /* wait for valid temperature */ + ret = adt7x10_temp_ready(data->regmap); + if (ret) { + mutex_unlock(&data->update_lock); return ret; + } + data->valid = true; } + mutex_unlock(&data->update_lock); - return sprintf(buf, "%d\n", ADT7X10_REG_TO_TEMP(data, - data->temp[attr->index])); + ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[attr->index], &val); + if (ret) + return ret; + + return sprintf(buf, "%d\n", ADT7X10_REG_TO_TEMP(data, val)); } static ssize_t adt7x10_temp_store(struct device *dev, @@ -251,12 +171,10 @@ static ssize_t adt7x10_temp_store(struct device *dev, return ret; mutex_lock(&data->update_lock); - data->temp[nr] = ADT7X10_TEMP_TO_REG(temp); - ret = adt7x10_write_word(dev, ADT7X10_REG_TEMP[nr], data->temp[nr]); - if (ret) - count = ret; + ret = regmap_write(data->regmap, ADT7X10_REG_TEMP[nr], + ADT7X10_TEMP_TO_REG(temp)); mutex_unlock(&data->update_lock); - return count; + return ret ? : count; } static ssize_t adt7x10_t_hyst_show(struct device *dev, @@ -265,9 +183,21 @@ static ssize_t adt7x10_t_hyst_show(struct device *dev, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct adt7x10_data *data = dev_get_drvdata(dev); int nr = attr->index; - int hyst; + int hyst, temp, ret; + + mutex_lock(&data->update_lock); + ret = regmap_read(data->regmap, ADT7X10_T_HYST, &hyst); + if (ret) { + mutex_unlock(&data->update_lock); + return ret; + } + + ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[nr], &temp); + mutex_unlock(&data->update_lock); + if (ret) + return ret; - hyst = (data->hyst & ADT7X10_T_HYST_MASK) * 1000; + hyst = (hyst & ADT7X10_T_HYST_MASK) * 1000; /* * hysteresis is stored as a 4 bit offset in the device, convert it @@ -275,8 +205,8 @@ static ssize_t adt7x10_t_hyst_show(struct device *dev, */ if (nr == 2) /* min has positive offset, others have negative */ hyst = -hyst; - return sprintf(buf, "%d\n", - ADT7X10_REG_TO_TEMP(data, data->temp[nr]) - hyst); + + return sprintf(buf, "%d\n", ADT7X10_REG_TO_TEMP(data, temp) - hyst); } static ssize_t adt7x10_t_hyst_store(struct device *dev, @@ -284,35 +214,45 @@ static ssize_t adt7x10_t_hyst_store(struct device *dev, const char *buf, size_t count) { struct adt7x10_data *data = dev_get_drvdata(dev); + unsigned int regval; int limit, ret; long hyst; ret = kstrtol(buf, 10, &hyst); if (ret) return ret; + + mutex_lock(&data->update_lock); + /* convert absolute hysteresis value to a 4 bit delta value */ - limit = ADT7X10_REG_TO_TEMP(data, data->temp[1]); - hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX); - data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), - 0, ADT7X10_T_HYST_MASK); - ret = adt7x10_write_byte(dev, ADT7X10_T_HYST, data->hyst); - if (ret) - return ret; + ret = regmap_read(data->regmap, ADT7X10_T_ALARM_HIGH, ®val); + if (ret < 0) + goto abort; - return count; + limit = ADT7X10_REG_TO_TEMP(data, regval); + + hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX); + regval = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0, + ADT7X10_T_HYST_MASK); + ret = regmap_write(data->regmap, ADT7X10_T_HYST, regval); +abort: + mutex_unlock(&data->update_lock); + return ret ? : count; } static ssize_t adt7x10_alarm_show(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct adt7x10_data *data = dev_get_drvdata(dev); + unsigned int status; int ret; - ret = adt7x10_read_byte(dev, ADT7X10_STATUS); + ret = regmap_read(data->regmap, ADT7X10_STATUS, &status); if (ret < 0) return ret; - return sprintf(buf, "%d\n", !!(ret & attr->index)); + return sprintf(buf, "%d\n", !!(status & attr->index)); } static ssize_t name_show(struct device *dev, struct device_attribute *da, @@ -357,28 +297,29 @@ static const struct attribute_group adt7x10_group = { }; int adt7x10_probe(struct device *dev, const char *name, int irq, - const struct adt7x10_ops *ops) + struct regmap *regmap) { struct adt7x10_data *data; + unsigned int config; int ret; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - data->ops = ops; + data->regmap = regmap; data->name = name; dev_set_drvdata(dev, data); mutex_init(&data->update_lock); /* configure as specified */ - ret = adt7x10_read_byte(dev, ADT7X10_CONFIG); + ret = regmap_read(regmap, ADT7X10_CONFIG, &config); if (ret < 0) { dev_dbg(dev, "Can't read config? %d\n", ret); return ret; } - data->oldconfig = ret; + data->oldconfig = config; /* * Set to 16 bit resolution, continous conversion and comparator mode. @@ -389,16 +330,12 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, data->config |= ADT7X10_FULL | ADT7X10_RESOLUTION | ADT7X10_EVENT_MODE; if (data->config != data->oldconfig) { - ret = adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config); + ret = regmap_write(regmap, ADT7X10_CONFIG, data->config); if (ret) return ret; } dev_dbg(dev, "Config %02x\n", data->config); - ret = adt7x10_fill_cache(dev); - if (ret) - goto exit_restore; - /* Register sysfs hooks */ ret = sysfs_create_group(&dev->kobj, &adt7x10_group); if (ret) @@ -439,7 +376,7 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, exit_remove: sysfs_remove_group(&dev->kobj, &adt7x10_group); exit_restore: - adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig); + regmap_write(regmap, ADT7X10_CONFIG, data->oldconfig); return ret; } EXPORT_SYMBOL_GPL(adt7x10_probe); @@ -456,7 +393,7 @@ void adt7x10_remove(struct device *dev, int irq) device_remove_file(dev, &dev_attr_name); sysfs_remove_group(&dev->kobj, &adt7x10_group); if (data->oldconfig != data->config) - adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig); + regmap_write(data->regmap, ADT7X10_CONFIG, data->oldconfig); } EXPORT_SYMBOL_GPL(adt7x10_remove); @@ -466,15 +403,15 @@ static int adt7x10_suspend(struct device *dev) { struct adt7x10_data *data = dev_get_drvdata(dev); - return adt7x10_write_byte(dev, ADT7X10_CONFIG, - data->config | ADT7X10_PD); + return regmap_write(data->regmap, ADT7X10_CONFIG, + data->config | ADT7X10_PD); } static int adt7x10_resume(struct device *dev) { struct adt7x10_data *data = dev_get_drvdata(dev); - return adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config); + return regmap_write(data->regmap, ADT7X10_CONFIG, data->config); } SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume); diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h index a1ae682eb32e6b..55ff08bfe94623 100644 --- a/drivers/hwmon/adt7x10.h +++ b/drivers/hwmon/adt7x10.h @@ -17,15 +17,9 @@ struct device; -struct adt7x10_ops { - int (*read_byte)(struct device *, u8 reg); - int (*write_byte)(struct device *, u8 reg, u8 data); - int (*read_word)(struct device *, u8 reg); - int (*write_word)(struct device *, u8 reg, u16 data); -}; - int adt7x10_probe(struct device *dev, const char *name, int irq, - const struct adt7x10_ops *ops); + struct regmap *regmap); + void adt7x10_remove(struct device *dev, int irq); #ifdef CONFIG_PM_SLEEP From 4ff6945275dc0e884049570ee8544ddc6e0902b5 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Tue, 21 Dec 2021 23:58:36 +0200 Subject: [PATCH 171/407] hwmon: (adt7x10) Add device managed action for restoring config To simplify the core driver remove function. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20211221215841.2641417-3-demonsingur@gmail.com [groeck: Adjust to use regmap; only register restore function if needed] Tested-by: Cosmin Tanislav Reviewed-by: Cosmin Tanislav Signed-off-by: Guenter Roeck (cherry picked from commit 07003ac3ed93b274d07f37dc229c916005dfb038) --- drivers/hwmon/adt7x10.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c index 05dd48b707b443..47ce1a88a03faa 100644 --- a/drivers/hwmon/adt7x10.c +++ b/drivers/hwmon/adt7x10.c @@ -296,6 +296,13 @@ static const struct attribute_group adt7x10_group = { .attrs = adt7x10_attributes, }; +static void adt7x10_restore_config(void *private) +{ + struct adt7x10_data *data = private; + + regmap_write(data->regmap, ADT7X10_CONFIG, data->oldconfig); +} + int adt7x10_probe(struct device *dev, const char *name, int irq, struct regmap *regmap) { @@ -333,13 +340,16 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, ret = regmap_write(regmap, ADT7X10_CONFIG, data->config); if (ret) return ret; + ret = devm_add_action_or_reset(dev, adt7x10_restore_config, data); + if (ret) + return ret; } dev_dbg(dev, "Config %02x\n", data->config); /* Register sysfs hooks */ ret = sysfs_create_group(&dev->kobj, &adt7x10_group); if (ret) - goto exit_restore; + return ret; /* * The I2C device will already have it's own 'name' attribute, but for @@ -375,8 +385,6 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, device_remove_file(dev, &dev_attr_name); exit_remove: sysfs_remove_group(&dev->kobj, &adt7x10_group); -exit_restore: - regmap_write(regmap, ADT7X10_CONFIG, data->oldconfig); return ret; } EXPORT_SYMBOL_GPL(adt7x10_probe); @@ -392,8 +400,6 @@ void adt7x10_remove(struct device *dev, int irq) if (data->name) device_remove_file(dev, &dev_attr_name); sysfs_remove_group(&dev->kobj, &adt7x10_group); - if (data->oldconfig != data->config) - regmap_write(data->regmap, ADT7X10_CONFIG, data->oldconfig); } EXPORT_SYMBOL_GPL(adt7x10_remove); From 4011ba5d8f659544c6960058a92a67e79eb2b13a Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Tue, 21 Dec 2021 23:58:37 +0200 Subject: [PATCH 172/407] hwmon: (adt7x10) Use devm_hwmon_device_register_with_info Describe the only available channel, implement read, write and is_visible callbacks. Also, pass name to core driver for the i2c device so that it can be used to register hwmon device. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20211221215841.2641417-4-demonsingur@gmail.com [groeck: Adjusted to use regmap] Tested-by: Cosmin Tanislav Reviewed-by: Cosmin Tanislav Signed-off-by: Guenter Roeck (cherry picked from commit a7bad77467fb521a0eb12b08109e8f8b63e109a0) --- drivers/hwmon/adt7410.c | 2 +- drivers/hwmon/adt7x10.c | 249 ++++++++++++++++++++-------------------- 2 files changed, 125 insertions(+), 126 deletions(-) diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index 59b32ef0433165..a284bee8373f10 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -84,7 +84,7 @@ static int adt7410_i2c_probe(struct i2c_client *client) if (IS_ERR(regmap)) return PTR_ERR(regmap); - return adt7x10_probe(&client->dev, NULL, client->irq, regmap); + return adt7x10_probe(&client->dev, client->name, client->irq, regmap); } static int adt7410_i2c_remove(struct i2c_client *client) diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c index 47ce1a88a03faa..9482fd8fff41f2 100644 --- a/drivers/hwmon/adt7x10.c +++ b/drivers/hwmon/adt7x10.c @@ -8,12 +8,12 @@ * and adt7410.c from iio-staging by Sonic Zhang */ +#include #include #include #include #include #include -#include #include #include #include @@ -55,19 +55,24 @@ /* Each client has this additional data */ struct adt7x10_data { struct regmap *regmap; - const char *name; - struct device *hwmon_dev; struct mutex update_lock; u8 config; u8 oldconfig; bool valid; /* true if temperature valid */ }; -static const u8 ADT7X10_REG_TEMP[4] = { - ADT7X10_TEMPERATURE, /* input */ - ADT7X10_T_ALARM_HIGH, /* high */ - ADT7X10_T_ALARM_LOW, /* low */ - ADT7X10_T_CRIT, /* critical */ +enum { + adt7x10_temperature = 0, + adt7x10_t_alarm_high, + adt7x10_t_alarm_low, + adt7x10_t_crit, +}; + +static const u8 ADT7X10_REG_TEMP[] = { + [adt7x10_temperature] = ADT7X10_TEMPERATURE, /* input */ + [adt7x10_t_alarm_high] = ADT7X10_T_ALARM_HIGH, /* high */ + [adt7x10_t_alarm_low] = ADT7X10_T_ALARM_LOW, /* low */ + [adt7x10_t_crit] = ADT7X10_T_CRIT, /* critical */ }; static irqreturn_t adt7x10_irq_handler(int irq, void *private) @@ -127,18 +132,13 @@ static int ADT7X10_REG_TO_TEMP(struct adt7x10_data *data, s16 reg) /*-----------------------------------------------------------------------*/ -/* sysfs attributes for hwmon */ - -static ssize_t adt7x10_temp_show(struct device *dev, - struct device_attribute *da, char *buf) +static int adt7x10_temp_read(struct adt7x10_data *data, int index, long *val) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct adt7x10_data *data = dev_get_drvdata(dev); - unsigned int val; + unsigned int regval; int ret; mutex_lock(&data->update_lock); - if (attr->index == 0 && !data->valid) { + if (index == adt7x10_temperature && !data->valid) { /* wait for valid temperature */ ret = adt7x10_temp_ready(data->regmap); if (ret) { @@ -149,40 +149,27 @@ static ssize_t adt7x10_temp_show(struct device *dev, } mutex_unlock(&data->update_lock); - ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[attr->index], &val); + ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], ®val); if (ret) return ret; - return sprintf(buf, "%d\n", ADT7X10_REG_TO_TEMP(data, val)); + *val = ADT7X10_REG_TO_TEMP(data, regval); + return 0; } -static ssize_t adt7x10_temp_store(struct device *dev, - struct device_attribute *da, - const char *buf, size_t count) +static int adt7x10_temp_write(struct adt7x10_data *data, int index, long temp) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct adt7x10_data *data = dev_get_drvdata(dev); - int nr = attr->index; - long temp; int ret; - ret = kstrtol(buf, 10, &temp); - if (ret) - return ret; - mutex_lock(&data->update_lock); - ret = regmap_write(data->regmap, ADT7X10_REG_TEMP[nr], + ret = regmap_write(data->regmap, ADT7X10_REG_TEMP[index], ADT7X10_TEMP_TO_REG(temp)); mutex_unlock(&data->update_lock); - return ret ? : count; + return ret; } -static ssize_t adt7x10_t_hyst_show(struct device *dev, - struct device_attribute *da, char *buf) +static int adt7x10_hyst_read(struct adt7x10_data *data, int index, long *val) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct adt7x10_data *data = dev_get_drvdata(dev); - int nr = attr->index; int hyst, temp, ret; mutex_lock(&data->update_lock); @@ -192,7 +179,7 @@ static ssize_t adt7x10_t_hyst_show(struct device *dev, return ret; } - ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[nr], &temp); + ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], &temp); mutex_unlock(&data->update_lock); if (ret) return ret; @@ -203,24 +190,18 @@ static ssize_t adt7x10_t_hyst_show(struct device *dev, * hysteresis is stored as a 4 bit offset in the device, convert it * to an absolute value */ - if (nr == 2) /* min has positive offset, others have negative */ + /* min has positive offset, others have negative */ + if (index == adt7x10_t_alarm_low) hyst = -hyst; - return sprintf(buf, "%d\n", ADT7X10_REG_TO_TEMP(data, temp) - hyst); + *val = ADT7X10_REG_TO_TEMP(data, temp) - hyst; + return 0; } -static ssize_t adt7x10_t_hyst_store(struct device *dev, - struct device_attribute *da, - const char *buf, size_t count) +static int adt7x10_hyst_write(struct adt7x10_data *data, long hyst) { - struct adt7x10_data *data = dev_get_drvdata(dev); unsigned int regval; int limit, ret; - long hyst; - - ret = kstrtol(buf, 10, &hyst); - if (ret) - return ret; mutex_lock(&data->update_lock); @@ -237,14 +218,11 @@ static ssize_t adt7x10_t_hyst_store(struct device *dev, ret = regmap_write(data->regmap, ADT7X10_T_HYST, regval); abort: mutex_unlock(&data->update_lock); - return ret ? : count; + return ret; } -static ssize_t adt7x10_alarm_show(struct device *dev, - struct device_attribute *da, char *buf) +static int adt7x10_alarm_read(struct adt7x10_data *data, int index, long *val) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct adt7x10_data *data = dev_get_drvdata(dev); unsigned int status; int ret; @@ -252,48 +230,102 @@ static ssize_t adt7x10_alarm_show(struct device *dev, if (ret < 0) return ret; - return sprintf(buf, "%d\n", !!(status & attr->index)); + *val = !!(status & index); + + return 0; } -static ssize_t name_show(struct device *dev, struct device_attribute *da, - char *buf) +static umode_t adt7x10_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (attr) { + case hwmon_temp_max: + case hwmon_temp_min: + case hwmon_temp_crit: + case hwmon_temp_max_hyst: + return 0644; + case hwmon_temp_input: + case hwmon_temp_min_alarm: + case hwmon_temp_max_alarm: + case hwmon_temp_crit_alarm: + case hwmon_temp_min_hyst: + case hwmon_temp_crit_hyst: + return 0444; + default: + break; + } + + return 0; +} + +static int adt7x10_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) { struct adt7x10_data *data = dev_get_drvdata(dev); - return sprintf(buf, "%s\n", data->name); + switch (attr) { + case hwmon_temp_input: + return adt7x10_temp_read(data, adt7x10_temperature, val); + case hwmon_temp_max: + return adt7x10_temp_read(data, adt7x10_t_alarm_high, val); + case hwmon_temp_min: + return adt7x10_temp_read(data, adt7x10_t_alarm_low, val); + case hwmon_temp_crit: + return adt7x10_temp_read(data, adt7x10_t_crit, val); + case hwmon_temp_max_hyst: + return adt7x10_hyst_read(data, adt7x10_t_alarm_high, val); + case hwmon_temp_min_hyst: + return adt7x10_hyst_read(data, adt7x10_t_alarm_low, val); + case hwmon_temp_crit_hyst: + return adt7x10_hyst_read(data, adt7x10_t_crit, val); + case hwmon_temp_min_alarm: + return adt7x10_alarm_read(data, ADT7X10_STAT_T_LOW, val); + case hwmon_temp_max_alarm: + return adt7x10_alarm_read(data, ADT7X10_STAT_T_HIGH, val); + case hwmon_temp_crit_alarm: + return adt7x10_alarm_read(data, ADT7X10_STAT_T_CRIT, val); + default: + return -EOPNOTSUPP; + } } -static SENSOR_DEVICE_ATTR_RO(temp1_input, adt7x10_temp, 0); -static SENSOR_DEVICE_ATTR_RW(temp1_max, adt7x10_temp, 1); -static SENSOR_DEVICE_ATTR_RW(temp1_min, adt7x10_temp, 2); -static SENSOR_DEVICE_ATTR_RW(temp1_crit, adt7x10_temp, 3); -static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, adt7x10_t_hyst, 1); -static SENSOR_DEVICE_ATTR_RO(temp1_min_hyst, adt7x10_t_hyst, 2); -static SENSOR_DEVICE_ATTR_RO(temp1_crit_hyst, adt7x10_t_hyst, 3); -static SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, adt7x10_alarm, - ADT7X10_STAT_T_LOW); -static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, adt7x10_alarm, - ADT7X10_STAT_T_HIGH); -static SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, adt7x10_alarm, - ADT7X10_STAT_T_CRIT); -static DEVICE_ATTR_RO(name); - -static struct attribute *adt7x10_attributes[] = { - &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp1_max.dev_attr.attr, - &sensor_dev_attr_temp1_min.dev_attr.attr, - &sensor_dev_attr_temp1_crit.dev_attr.attr, - &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, - &sensor_dev_attr_temp1_min_hyst.dev_attr.attr, - &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, - &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, - &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, - &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, - NULL +static int adt7x10_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct adt7x10_data *data = dev_get_drvdata(dev); + + switch (attr) { + case hwmon_temp_max: + return adt7x10_temp_write(data, adt7x10_t_alarm_high, val); + case hwmon_temp_min: + return adt7x10_temp_write(data, adt7x10_t_alarm_low, val); + case hwmon_temp_crit: + return adt7x10_temp_write(data, adt7x10_t_crit, val); + case hwmon_temp_max_hyst: + return adt7x10_hyst_write(data, val); + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_channel_info *adt7x10_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | + HWMON_T_CRIT | HWMON_T_MAX_HYST | HWMON_T_MIN_HYST | + HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM | + HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM), + NULL, +}; + +static const struct hwmon_ops adt7x10_hwmon_ops = { + .is_visible = adt7x10_is_visible, + .read = adt7x10_read, + .write = adt7x10_write, }; -static const struct attribute_group adt7x10_group = { - .attrs = adt7x10_attributes, +static const struct hwmon_chip_info adt7x10_chip_info = { + .ops = &adt7x10_hwmon_ops, + .info = adt7x10_info, }; static void adt7x10_restore_config(void *private) @@ -308,6 +340,7 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, { struct adt7x10_data *data; unsigned int config; + struct device *hdev; int ret; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); @@ -315,7 +348,6 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, return -ENOMEM; data->regmap = regmap; - data->name = name; dev_set_drvdata(dev, data); mutex_init(&data->update_lock); @@ -346,60 +378,27 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, } dev_dbg(dev, "Config %02x\n", data->config); - /* Register sysfs hooks */ - ret = sysfs_create_group(&dev->kobj, &adt7x10_group); - if (ret) - return ret; - - /* - * The I2C device will already have it's own 'name' attribute, but for - * the SPI device we need to register it. name will only be non NULL if - * the device doesn't register the 'name' attribute on its own. - */ - if (name) { - ret = device_create_file(dev, &dev_attr_name); - if (ret) - goto exit_remove; - } - - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) { - ret = PTR_ERR(data->hwmon_dev); - goto exit_remove_name; - } + hdev = devm_hwmon_device_register_with_info(dev, name, data, + &adt7x10_chip_info, NULL); + if (IS_ERR(hdev)) + return PTR_ERR(hdev); if (irq > 0) { ret = request_threaded_irq(irq, NULL, adt7x10_irq_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name(dev), dev); if (ret) - goto exit_hwmon_device_unregister; + return ret; } return 0; - -exit_hwmon_device_unregister: - hwmon_device_unregister(data->hwmon_dev); -exit_remove_name: - if (name) - device_remove_file(dev, &dev_attr_name); -exit_remove: - sysfs_remove_group(&dev->kobj, &adt7x10_group); - return ret; } EXPORT_SYMBOL_GPL(adt7x10_probe); void adt7x10_remove(struct device *dev, int irq) { - struct adt7x10_data *data = dev_get_drvdata(dev); - if (irq > 0) free_irq(irq, dev); - - hwmon_device_unregister(data->hwmon_dev); - if (data->name) - device_remove_file(dev, &dev_attr_name); - sysfs_remove_group(&dev->kobj, &adt7x10_group); } EXPORT_SYMBOL_GPL(adt7x10_remove); From 552a28488d1cbb72f48248ac549b79451ec1e492 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Tue, 21 Dec 2021 23:58:38 +0200 Subject: [PATCH 173/407] hwmon: (adt7x10) Use devm_request_threaded_irq To simplify the core driver remove function. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20211221215841.2641417-5-demonsingur@gmail.com Tested-by: Cosmin Tanislav Reviewed-by: Cosmin Tanislav Signed-off-by: Guenter Roeck (cherry picked from commit 0577cbaf554135c994411ef65925383c4db230ef) --- drivers/hwmon/adt7x10.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c index 9482fd8fff41f2..147c28b241675b 100644 --- a/drivers/hwmon/adt7x10.c +++ b/drivers/hwmon/adt7x10.c @@ -384,9 +384,11 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, return PTR_ERR(hdev); if (irq > 0) { - ret = request_threaded_irq(irq, NULL, adt7x10_irq_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(dev), dev); + ret = devm_request_threaded_irq(dev, irq, NULL, + adt7x10_irq_handler, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + dev_name(dev), dev); if (ret) return ret; } @@ -397,8 +399,6 @@ EXPORT_SYMBOL_GPL(adt7x10_probe); void adt7x10_remove(struct device *dev, int irq) { - if (irq > 0) - free_irq(irq, dev); } EXPORT_SYMBOL_GPL(adt7x10_remove); From 6231a22cec224625e869c8b473e515d4e2788651 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Tue, 21 Dec 2021 23:58:39 +0200 Subject: [PATCH 174/407] hwmon: (adt7x10) Remove empty driver removal callback Not used to do anything anymore. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20211221215841.2641417-6-demonsingur@gmail.com Tested-by: Cosmin Tanislav Reviewed-by: Cosmin Tanislav Signed-off-by: Guenter Roeck (cherry picked from commit 0812e9c333bc6953c55011cb9a3c07b0a15114aa) --- drivers/hwmon/adt7310.c | 7 ------- drivers/hwmon/adt7410.c | 7 ------- drivers/hwmon/adt7x10.c | 5 ----- drivers/hwmon/adt7x10.h | 2 -- 4 files changed, 21 deletions(-) diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c index a83092470bce4a..1efc0bdcceabdc 100644 --- a/drivers/hwmon/adt7310.c +++ b/drivers/hwmon/adt7310.c @@ -142,12 +142,6 @@ static int adt7310_spi_probe(struct spi_device *spi) regmap); } -static int adt7310_spi_remove(struct spi_device *spi) -{ - adt7x10_remove(&spi->dev, spi->irq); - return 0; -} - static const struct spi_device_id adt7310_id[] = { { "adt7310", 0 }, { "adt7320", 0 }, @@ -161,7 +155,6 @@ static struct spi_driver adt7310_driver = { .pm = ADT7X10_DEV_PM_OPS, }, .probe = adt7310_spi_probe, - .remove = adt7310_spi_remove, .id_table = adt7310_id, }; module_spi_driver(adt7310_driver); diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index a284bee8373f10..31d2d3cb705215 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -87,12 +87,6 @@ static int adt7410_i2c_probe(struct i2c_client *client) return adt7x10_probe(&client->dev, client->name, client->irq, regmap); } -static int adt7410_i2c_remove(struct i2c_client *client) -{ - adt7x10_remove(&client->dev, client->irq); - return 0; -} - static const struct i2c_device_id adt7410_ids[] = { { "adt7410", 0 }, { "adt7420", 0 }, @@ -108,7 +102,6 @@ static struct i2c_driver adt7410_driver = { .pm = ADT7X10_DEV_PM_OPS, }, .probe_new = adt7410_i2c_probe, - .remove = adt7410_i2c_remove, .id_table = adt7410_ids, .address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b), }; diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c index 147c28b241675b..ea8cd918bc2261 100644 --- a/drivers/hwmon/adt7x10.c +++ b/drivers/hwmon/adt7x10.c @@ -397,11 +397,6 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, } EXPORT_SYMBOL_GPL(adt7x10_probe); -void adt7x10_remove(struct device *dev, int irq) -{ -} -EXPORT_SYMBOL_GPL(adt7x10_remove); - #ifdef CONFIG_PM_SLEEP static int adt7x10_suspend(struct device *dev) diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h index 55ff08bfe94623..ba22c32c83552b 100644 --- a/drivers/hwmon/adt7x10.h +++ b/drivers/hwmon/adt7x10.h @@ -20,8 +20,6 @@ struct device; int adt7x10_probe(struct device *dev, const char *name, int irq, struct regmap *regmap); -void adt7x10_remove(struct device *dev, int irq); - #ifdef CONFIG_PM_SLEEP extern const struct dev_pm_ops adt7x10_dev_pm_ops; #define ADT7X10_DEV_PM_OPS (&adt7x10_dev_pm_ops) From 68fa0569dd95474550d6648c85373c3d99128dd8 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Tue, 21 Dec 2021 23:58:41 +0200 Subject: [PATCH 175/407] hwmon: (adt7x10) Use hwmon_notify_event The hwmon subsystem provides means of notifying userspace about events. Use it. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20211221215841.2641417-8-demonsingur@gmail.com [groeck: Pass hwmon device to interrupt handler] Tested-by: Cosmin Tanislav Reviewed-by: Cosmin Tanislav Signed-off-by: Guenter Roeck (cherry picked from commit fad02286893cf4cfd4ed7db15cdd872553c51193) --- drivers/hwmon/adt7x10.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c index ea8cd918bc2261..ce54bffab2ec2c 100644 --- a/drivers/hwmon/adt7x10.c +++ b/drivers/hwmon/adt7x10.c @@ -87,11 +87,11 @@ static irqreturn_t adt7x10_irq_handler(int irq, void *private) return IRQ_HANDLED; if (status & ADT7X10_STAT_T_HIGH) - sysfs_notify(&dev->kobj, NULL, "temp1_max_alarm"); + hwmon_notify_event(dev, hwmon_temp, hwmon_temp_max_alarm, 0); if (status & ADT7X10_STAT_T_LOW) - sysfs_notify(&dev->kobj, NULL, "temp1_min_alarm"); + hwmon_notify_event(dev, hwmon_temp, hwmon_temp_min_alarm, 0); if (status & ADT7X10_STAT_T_CRIT) - sysfs_notify(&dev->kobj, NULL, "temp1_crit_alarm"); + hwmon_notify_event(dev, hwmon_temp, hwmon_temp_crit_alarm, 0); return IRQ_HANDLED; } @@ -388,7 +388,7 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, adt7x10_irq_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(dev), dev); + dev_name(dev), hdev); if (ret) return ret; } From 8aed647981a8db2b20baa38f5a7c083345af5d1f Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 16 Feb 2022 13:46:11 +0100 Subject: [PATCH 176/407] dts: vcu118_ad9082_204c_txmode_18_rxmode_19_lr_24_75Gbps: New use case New full bandwidth/bypass mode use case. This use cases implements TXMode 18 and RXMode 19. Using M=2, L=8 for both RX and TX. ADCs and DACs are running at 6GHZ, with a lane rate of 24.75G. Signed-off-by: Michael Hennerich --- ..._204c_txmode_18_rxmode_19_lr_24_75Gbps.dts | 362 ++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 arch/microblaze/boot/dts/vcu118_ad9082_204c_txmode_18_rxmode_19_lr_24_75Gbps.dts diff --git a/arch/microblaze/boot/dts/vcu118_ad9082_204c_txmode_18_rxmode_19_lr_24_75Gbps.dts b/arch/microblaze/boot/dts/vcu118_ad9082_204c_txmode_18_rxmode_19_lr_24_75Gbps.dts new file mode 100644 index 00000000000000..8066f42287feee --- /dev/null +++ b/arch/microblaze/boot/dts/vcu118_ad9082_204c_txmode_18_rxmode_19_lr_24_75Gbps.dts @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD9082-FMC-EBZ + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 + * https://wiki.analog.com/resources/eval/user-guides/ad9081_fmca_ebz/ad9081_fmca_ebz_hdl + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2022 Analog Devices Inc. + */ + +#include "vcu118_ad9081.dts" + +// {'clock': {'n2': 30, +// 'out_dividers': [5, 256, 256, 16, 16], +// 'output_clocks': {'AD9081_ref_clk': {'divider': 5, +// 'rate': 600000000.0}, +// 'adc_fpga_ref_clk': {'divider': 16, +// 'rate': 187500000.0}, +// 'adc_sysref': {'divider': 256, 'rate': 11718750.0}, +// 'dac_fpga_ref_clk': {'divider': 16, +// 'rate': 187500000.0}, +// 'dac_sysref': {'divider': 256, +// 'rate': 11718750.0}}, +// 'r2': 1, +// 'vco': 3000000000.0, +// 'vcxo': 100000000.0, +// 'vcxo_doubler': 1}, +// 'converter': {'clocking_option': 'integrated_pll', +// 'pll_config': {'d': 1, 'm_vco': 5, 'n_vco': 2, 'r': 1}}, +// 'datapath_adc': {'cddc': {'decimations': [1, 1, 1, 1], +// 'enabled': [True, True, True, True], +// 'nco_frequencies': [0, 0, 0, 0], +// 'nco_phases': [0, 0, 0, 0]}, +// 'fddc': {'decimations': [1, 1, 1, 1, 1, 1, 1, 1], +// 'enabled': [False, +// False, +// False, +// False, +// False, +// False, +// False, +// False], +// 'nco_frequencies': [0, 0, 0, 0, 0, 0, 0, 0], +// 'nco_phases': [0, 0, 0, 0, 0, 0, 0, 0], +// 'source': [1, 1, 2, 2, 3, 3, 4, 4]}}, +// 'datapath_dac': {'cduc': {'enabled': [True, True, True, True], +// 'interpolation': 1, +// 'nco_frequencies': [0, 0, 0, 0], +// 'nco_phases': [0, 0, 0, 0], +// 'sources': [[1], [1], [3], [3]]}, +// 'fduc': {'enabled': [False, +// False, +// False, +// False, +// False, +// False, +// False, +// False], +// 'interpolation': 1, +// 'nco_frequencies': [0, 0, 0, 0, 0, 0, 0, 0], +// 'nco_phases': [0, 0, 0, 0, 0, 0, 0, 0]}}, +// 'fpga_adc': {'band': 0, +// 'd': 1, +// 'm': 1, +// 'n': 66, +// 'qty4_full_rate_enabled': 1, +// 'type': 'qpll', +// 'vco': 12375000000.0}, +// 'fpga_dac': {'band': 0, +// 'd': 1, +// 'm': 1, +// 'n': 66, +// 'qty4_full_rate_enabled': 1, +// 'type': 'qpll', +// 'vco': 12375000000.0}, +// 'jesd_adc': {'F': 1, +// 'HD': 1, +// 'K': 256, +// 'L': 8, +// 'M': 2, +// 'Np': 16, +// 'S': 2, +// 'bit_clock': 24750000000.0, +// 'converter_clock': 6000000000.0, +// 'jesd_class': 'jesd204c', +// 'jesd_mode': '19.0', +// 'multiframe_clock': 11718750.0, +// 'sample_clock': 6000000000.0}, +// 'jesd_dac': {'F': 1, +// 'HD': 0, +// 'K': 256, +// 'L': 8, +// 'M': 2, +// 'Np': 16, +// 'S': 2, +// 'bit_clock': 24750000000.0, +// 'converter_clock': 6000000000.0, +// 'jesd_class': 'jesd204c', +// 'jesd_mode': '18', +// 'multiframe_clock': 11718750.0, +// 'sample_clock': 6000000000.0}} + +// HDL Synthesis Parameter: +// make JESD_MODE=64B66B RX_RATE=24.75 RX_JESD_M=2 RX_JESD_L=8 RX_JESD_S=2 RX_JESD_NP=16 +// TX_RATE=24.75 TX_JESD_M=2 TX_JESD_L=8 TX_JESD_S=2 TX_JESD_NP=16 + +#define HMC7044_FPGA_XCVR_CLKDIV 8 +#define HMC7044_FPGA_LINK_CLKDIV_TX 8 +#define HMC7044_FPGA_LINK_CLKDIV_RX 8 +#define HMC7044_SYSREF_CLKDIV 256 + + /* TX path */ +#define AD9081_DAC_FREQUENCY 6000000000 +#define AD9081_TX_MAIN_INTERPOLATION 1 +#define AD9081_TX_CHAN_INTERPOLATION 1 +#define AD9081_TX_MAIN_NCO_SHIFT 0 +#define AD9081_TX_CHAN_NCO_SHIFT 0 + +#define AD9081_GAIN 1024 + +#define AD9081_TX_JESD_MODE 18 +#define AD9081_TX_JESD_SUBCLASS 1 +#define AD9081_TX_JESD_VERSION 2 +#define AD9081_TX_JESD_M 2 +#define AD9081_TX_JESD_F 1 +#define AD9081_TX_JESD_K 256 +#define AD9081_TX_JESD_N 16 +#define AD9081_TX_JESD_NP 16 +#define AD9081_TX_JESD_CS 0 +#define AD9081_TX_JESD_L 8 +#define AD9081_TX_JESD_S 2 +#define AD9081_TX_JESD_HD 1 + +#define AD9081_JRX_TPL_PHASE_ADJUST 15 + +/* RX path */ +#define AD9081_ADC_FREQUENCY 6000000000 +#define AD9081_RX_MAIN_DECIMATION 1 +#define AD9081_RX_CHAN_DECIMATION 1 +#define AD9081_RX_MAIN_NCO_SHIFT 0 +#define AD9081_RX_CHAN_NCO_SHIFT 0 + +#define AD9081_RX_JESD_MODE 19 +#define AD9081_RX_JESD_SUBCLASS 1 +#define AD9081_RX_JESD_VERSION 2 +#define AD9081_RX_JESD_M 2 +#define AD9081_RX_JESD_F 1 +#define AD9081_RX_JESD_K 256 +#define AD9081_RX_JESD_N 16 +#define AD9081_RX_JESD_NP 16 +#define AD9081_RX_JESD_CS 0 +#define AD9081_RX_JESD_L 8 +#define AD9081_RX_JESD_S 2 +#define AD9081_RX_JESD_HD 1 + +&axi_ad9081_adxcvr_rx { + adi,sys-clk-select = ; + adi,out-clk-select = ; +}; + +&axi_ad9081_adxcvr_tx { + adi,sys-clk-select = ; + adi,out-clk-select = ; +}; + +&axi_ad9081_core_tx { + compatible = "adi,axi-ad9081-tx-1.0-real"; + sampl_clk-clock-scales = <1 10>; +}; + +&hmc7044 { + + adi,pll2-output-frequency = <3000000000>; + + hmc7044_c2: channel@2 { + reg = <2>; + adi,extended-name = "DEV_REFCLK"; + adi,divider = <5>; // 600 + adi,driver-mode = ; // LVDS + }; + + hmc7044_c3: channel@3 { + reg = <3>; + adi,extended-name = "DEV_SYSREF"; + adi,divider = ; // + adi,driver-mode = ; // LVDS + adi,jesd204-sysref-chan; + }; + + hmc7044_c6: channel@6 { + reg = <6>; + adi,extended-name = "CORE_CLK_TX"; + adi,divider = ; // 375 + adi,driver-mode = ; // LVDS + }; + + hmc7044_c8: channel@8 { + reg = <8>; + adi,extended-name = "CORE_CLK_RX"; + adi,divider = ; // 375 + adi,driver-mode = ; // LVDS + }; + + hmc7044_c12: channel@12 { + reg = <12>; + adi,extended-name = "FPGA_REFCLK"; + adi,divider = ; // 375 + adi,driver-mode = ; // LVDS + }; + + hmc7044_c13: channel@13 { + reg = <13>; + adi,extended-name = "FPGA_SYSREF"; + adi,divider = ; // + adi,driver-mode = ; // LVDS + adi,jesd204-sysref-chan; + }; +}; + +&trx0_ad9081 { + + compatible = "adi,ad9082"; + + rx_sampl_clk-clock-scales = <1 10>; + tx_sampl_clk-clock-scales = <1 10>; + + /delete-node/ adi,tx-dacs; + /delete-node/ adi,rx-adcs; + + adi,tx-dacs { + #size-cells = <0>; + #address-cells = <1>; + adi,dac-frequency-hz = /bits/ 64 ; + + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = ; + trx0_ad9081_dac0: dac@0 { + reg = <0>; + adi,crossbar-select = <&trx0_ad9081_tx_fddc_chan0>; + adi,nco-frequency-shift-hz = /bits/ 64 ; /* 100 MHz */ + }; + trx0_ad9081_dac1: dac@1 { + reg = <1>; + adi,crossbar-select = <&trx0_ad9081_tx_fddc_chan1>; + adi,nco-frequency-shift-hz = /bits/ 64 ; /* 100 MHz */ + }; + }; + + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = ; + trx0_ad9081_tx_fddc_chan0: channel@0 { + reg = <0>; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + trx0_ad9081_tx_fddc_chan1: channel@1 { + reg = <1>; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + }; + + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + trx0_ad9081_tx_jesd_l0: link@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + adi,tpl-phase-adjust = ; + adi,logical-lane-mapping = /bits/ 8 <0 2 7 6 1 5 4 3>; + adi,link-mode = ; /* JESD Quick Configuration Mode */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ + adi,version = ; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,converters-per-device = ; /* JESD M */ + adi,octets-per-frame = ; /* JESD F */ + adi,frames-per-multiframe = ; /* JESD K */ + adi,converter-resolution = ; /* JESD N */ + adi,bits-per-sample = ; /* JESD NP' */ + adi,control-bits-per-sample = ; /* JESD CS */ + adi,lanes-per-device = ; /* JESD L */ + adi,samples-per-converter-per-frame = ; /* JESD S */ + adi,high-density = ; /* JESD HD */ + + adi,tpl-phase-adjust = <0x3>; + }; + }; + }; + + adi,rx-adcs { + #size-cells = <0>; + #address-cells = <1>; + adi,adc-frequency-hz = /bits/ 64 ; + adi,nyquist-zone = ; + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + trx0_ad9081_adc0: adc@0 { + reg = <0>; + adi,decimation = ; + adi,nco-frequency-shift-hz = /bits/ 64 ; + adi,nco-mixer-mode = ; + //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ + }; + trx0_ad9081_adc1: adc@1 { + reg = <1>; + adi,decimation = ; + adi,nco-frequency-shift-hz = /bits/ 64 ; + adi,nco-mixer-mode = ; + //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ + }; + }; + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + trx0_ad9081_rx_fddc_chan0: channel@0 { + reg = <0>; + adi,decimation = ; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + trx0_ad9081_rx_fddc_chan1: channel@1 { + reg = <1>; + adi,decimation = ; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + }; + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + trx0_ad9081_rx_jesd_l0: link@0 { + reg = <0>; + adi,converter-select = + <&trx0_ad9081_rx_fddc_chan0 FDDC_I>, <&trx0_ad9081_rx_fddc_chan1 FDDC_I>; + + adi,logical-lane-mapping = /bits/ 8 <2 0 7 6 5 4 3 1>; + adi,link-mode = ; /* JESD Quick Configuration Mode */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ + adi,version = ; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,device-id = <3>; + adi,converters-per-device = ; /* JESD M */ + adi,octets-per-frame = ; /* JESD F */ + adi,frames-per-multiframe = ; /* JESD K */ + adi,converter-resolution = ; /* JESD N */ + adi,bits-per-sample = ; /* JESD NP' */ + adi,control-bits-per-sample = ; /* JESD CS */ + adi,lanes-per-device = ; /* JESD L */ + adi,samples-per-converter-per-frame = ; /* JESD S */ + adi,high-density = ; /* JESD HD */ + }; + }; + }; +}; From 11ae9fad56eba5e08ee7906ad732f94b872fb3a3 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 18 Feb 2022 13:44:33 +0100 Subject: [PATCH 177/407] iio: jesd204: xilinx_transceiver: Fix PROGDIV for gty4 For GTY4 the DRP encoding for PROGDIV is indentical to the GTH4 Fixes: f1dba7854b98 ("iio: jesd204: axi_adxcvr: Add TX|RX_PROGDIV support") Signed-off-by: Michael Hennerich --- drivers/iio/jesd204/xilinx_transceiver.c | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/iio/jesd204/xilinx_transceiver.c b/drivers/iio/jesd204/xilinx_transceiver.c index ceb85a12029a3f..1d75c30a44122b 100644 --- a/drivers/iio/jesd204/xilinx_transceiver.c +++ b/drivers/iio/jesd204/xilinx_transceiver.c @@ -1279,7 +1279,7 @@ int xilinx_xcvr_write_out_div(struct xilinx_xcvr *xcvr, unsigned int drp_port, } EXPORT_SYMBOL_GPL(xilinx_xcvr_write_out_div); -static unsigned int xilinx_xcvr_gth4_prog_div_to_val(unsigned int div) +static unsigned int xilinx_xcvr_gty4_gth4_prog_div_to_val(unsigned int div) { switch (div) { case 0: @@ -1321,7 +1321,7 @@ static unsigned int xilinx_xcvr_gth4_prog_div_to_val(unsigned int div) } } -static unsigned int xilinx_xcvr_gty4_gth3_prog_div_to_val(unsigned int div) +static unsigned int xilinx_xcvr_gty3_gth3_prog_div_to_val(unsigned int div) { switch (div) { case 0: @@ -1359,22 +1359,20 @@ static unsigned int xilinx_xcvr_gty4_gth3_prog_div_to_val(unsigned int div) } } -static int xilinx_xcvr_gth3_gty4_write_progdiv_div(struct xilinx_xcvr *xcvr, +static int xilinx_xcvr_gth3_gty3_write_progdiv_div(struct xilinx_xcvr *xcvr, unsigned int drp_port, int rx_prog_div, int tx_prog_div) { int ret; if (rx_prog_div >= 0) { ret = xilinx_xcvr_drp_update(xcvr, drp_port, 0xC6, 0xFFFF, - xilinx_xcvr_gty4_gth3_prog_div_to_val(rx_prog_div)); + xilinx_xcvr_gty3_gth3_prog_div_to_val(rx_prog_div)); if (ret) return ret; } if (tx_prog_div >= 0) { - ret = xilinx_xcvr_drp_update(xcvr, drp_port, - (xcvr->type == XILINX_XCVR_TYPE_US_GTY4) ? 0x57 : 0x3E, - 0xFFFF, - xilinx_xcvr_gty4_gth3_prog_div_to_val(tx_prog_div)); + ret = xilinx_xcvr_drp_update(xcvr, drp_port, 0x3E, 0xFFFF, + xilinx_xcvr_gty3_gth3_prog_div_to_val(tx_prog_div)); if (ret) return ret; } @@ -1382,20 +1380,22 @@ static int xilinx_xcvr_gth3_gty4_write_progdiv_div(struct xilinx_xcvr *xcvr, return 0; } -static int xilinx_xcvr_gth4_write_progdiv_div(struct xilinx_xcvr *xcvr, +static int xilinx_xcvr_gth4_gty4_write_progdiv_div(struct xilinx_xcvr *xcvr, unsigned int drp_port, int rx_prog_div, int tx_prog_div) { int ret; if (rx_prog_div >= 0) { ret = xilinx_xcvr_drp_update(xcvr, drp_port, 0xC6, 0xFFFF, - xilinx_xcvr_gth4_prog_div_to_val(rx_prog_div)); + xilinx_xcvr_gty4_gth4_prog_div_to_val(rx_prog_div)); if (ret) return ret; } if (tx_prog_div >= 0) { - ret = xilinx_xcvr_drp_update(xcvr, drp_port, 0x3E, 0xFFFF, - xilinx_xcvr_gth4_prog_div_to_val(tx_prog_div)); + ret = xilinx_xcvr_drp_update(xcvr, drp_port, + (xcvr->type == XILINX_XCVR_TYPE_US_GTY4) ? 0x57 : 0x3E, + 0xFFFF, + xilinx_xcvr_gty4_gth4_prog_div_to_val(tx_prog_div)); if (ret) return ret; } @@ -1408,11 +1408,11 @@ int xilinx_xcvr_write_prog_div(struct xilinx_xcvr *xcvr, unsigned int drp_port, { switch (xcvr->type) { case XILINX_XCVR_TYPE_US_GTH3: - case XILINX_XCVR_TYPE_US_GTY4: - return xilinx_xcvr_gth3_gty4_write_progdiv_div(xcvr, drp_port, + return xilinx_xcvr_gth3_gty3_write_progdiv_div(xcvr, drp_port, rx_prog_div, tx_prog_div); + case XILINX_XCVR_TYPE_US_GTY4: case XILINX_XCVR_TYPE_US_GTH4: - return xilinx_xcvr_gth4_write_progdiv_div(xcvr, drp_port, + return xilinx_xcvr_gth4_gty4_write_progdiv_div(xcvr, drp_port, rx_prog_div, tx_prog_div); default: return -EINVAL; From 005ab9ade5817867095ba47bfd4b6d43c1be7701 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 18 Feb 2022 13:51:44 +0100 Subject: [PATCH 178/407] iio: core: Introduce IIO_VAL_INT_64. Introduce IIO_VAL_INT_64 to read 64-bit value for channel attribute. Val is used as lower 32 bits. Signed-off-by: Andriy Tryshnivskyy Link: https://lore.kernel.org/r/20211024091627.28031-2-andriy.tryshnivskyy@opensynergy.com Signed-off-by: Jonathan Cameron Signed-off-by: Michael Hennerich --- drivers/iio/industrialio-core.c | 3 +++ include/linux/iio/types.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index f25c71d1aec695..aca67be1663a9e 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -652,6 +652,9 @@ static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type, } case IIO_VAL_CHAR: return scnprintf(buf, len, "%c", (char)vals[0]); + case IIO_VAL_INT_64: + tmp2 = (s64)((((u64)vals[1]) << 32) | (u32)vals[0]); + return scnprintf(buf, len, "%lld", tmp2); default: return 0; } diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 6297ebf2743b9f..f6b96a99ceddcb 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -23,6 +23,7 @@ enum iio_event_info { #define IIO_VAL_INT_PLUS_NANO 3 #define IIO_VAL_INT_PLUS_MICRO_DB 4 #define IIO_VAL_INT_MULTIPLE 5 +#define IIO_VAL_INT_64 6 /* 64-bit data, val is lower 32 bits */ #define IIO_VAL_FRACTIONAL 10 #define IIO_VAL_FRACTIONAL_LOG2 11 #define IIO_VAL_CHAR 12 From e655ce5d7e56439373da5f5372863aa4f06849ee Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 18 Feb 2022 13:45:05 +0100 Subject: [PATCH 179/407] iio: adc: ad9081: Use scaled clocks to support sample rates > 4.29GHz AD9082 ADC can sample up to 6GHz. In full bandwidth/bypass mode our sample rate would be > 3^32. We therefore need support for 64-bit. This patch introduces support for optional scaled clocks. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 2a85d8d69a4b4e..8d146155645e8a 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -160,6 +160,7 @@ struct ad9081_phy { struct regulator *supply_reg; struct clk *clks[NUM_AD9081_CLKS]; + struct clock_scale clkscale[NUM_AD9081_CLKS]; struct ad9081_clock clk_priv[NUM_AD9081_CLKS]; struct clk_onecell_data clk_data; @@ -577,6 +578,9 @@ static int ad9081_clk_register(struct ad9081_phy *phy, const char *name, return -EINVAL; } + of_clk_get_scale(phy->spi->dev.of_node, &name[1], + &phy->clkscale[source]); + clk = devm_clk_register(&phy->spi->dev, &clk_priv->hw); phy->clks[source] = clk; @@ -1799,7 +1803,8 @@ static int ad9081_setup_tx(struct spi_device *spi) sample_rate = DIV_ROUND_CLOSEST_ULL(phy->dac_frequency_hz, phy->tx_main_interp * phy->tx_chan_interp); - clk_set_rate(phy->clks[TX_SAMPL_CLK], sample_rate); + clk_set_rate_scaled(phy->clks[TX_SAMPL_CLK], sample_rate, + &phy->clkscale[TX_SAMPL_CLK]); for (i = 0; i < ARRAY_SIZE(phy->tx_dac_fsc); i++) { if (phy->tx_dac_fsc[i]) { @@ -1947,11 +1952,14 @@ static int ad9081_setup_rx(struct spi_device *spi) } sample_rate = DIV_ROUND_CLOSEST_ULL(phy->adc_frequency_hz, phy->adc_dcm[0]); - clk_set_rate(phy->clks[RX_SAMPL_CLK], sample_rate); + clk_set_rate_scaled(phy->clks[RX_SAMPL_CLK], sample_rate, + &phy->clkscale[RX_SAMPL_CLK]); + if (ad9081_link_is_dual(phy->jtx_link_rx)) { sample_rate = DIV_ROUND_CLOSEST_ULL(phy->adc_frequency_hz, phy->adc_dcm[1]); - clk_set_rate(phy->clks[RX_SAMPL_CLK_LINK2], sample_rate); + clk_set_rate_scaled(phy->clks[RX_SAMPL_CLK_LINK2], sample_rate, + &phy->clkscale[RX_SAMPL_CLK_LINK2]); } return 0; @@ -2077,6 +2085,7 @@ static int ad9081_read_raw(struct iio_dev *indio_dev, struct ad9081_phy *phy = conv->phy; u8 msb, lsb; u8 cddc_num, cddc_mask, fddc_num, fddc_mask; + u64 freq; ad9081_iiochan_to_fddc_cddc(phy, chan, &fddc_num, &fddc_mask, &cddc_num, &cddc_mask); @@ -2086,9 +2095,13 @@ static int ad9081_read_raw(struct iio_dev *indio_dev, if (!conv->clk) return -ENODEV; - *val = conv->adc_clk = - clk_get_rate_scaled(conv->clk, &conv->adc_clkscale); - return IIO_VAL_INT; + freq = clk_get_rate_scaled(conv->clk, + &phy->clkscale[RX_SAMPL_CLK]); + + *val = (u32)freq; + *val2 = (u32)(freq >> 32); + + return IIO_VAL_INT_64; case IIO_CHAN_INFO_ENABLE: if (chan->output) { *val = phy->dac_cache.enable[fddc_num]; From ef012d7faa68f83ec1cd1cf804e5c2a8159ec822 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 21 Feb 2022 10:18:09 +0100 Subject: [PATCH 180/407] iio: adc: ad9081: Full bandwidth/bypass mode support In full bandwidth/bypass mode, channels are no longer complex IQ modified. Since DDC/DUC and their NCOs are bypassed. This path adds support for this, but temporarily disables this detection until the tools are updated to handle the revised channel naming for this case. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 8d146155645e8a..c29f4486e0c04e 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -4025,7 +4025,7 @@ static char* ad9081_lable_writer(struct ad9081_phy *phy, const struct iio_chan_s } static int ad9081_setup_chip_info_tbl(struct ad9081_phy *phy, - bool complex, bool buffer_capable) + bool complex_rx, bool complex_tx, bool buffer_capable) { int i, c, m; @@ -4056,8 +4056,8 @@ static int ad9081_setup_chip_info_tbl(struct ad9081_phy *phy, phy->chip_info.channel[c].type = IIO_VOLTAGE; phy->chip_info.channel[c].output = 0; phy->chip_info.channel[c].indexed = 1; - phy->chip_info.channel[c].modified = complex ? 1 : 0; - phy->chip_info.channel[c].channel = complex ? i / 2 : i; + phy->chip_info.channel[c].modified = complex_rx ? 1 : 0; + phy->chip_info.channel[c].channel = complex_rx ? i / 2 : i; phy->chip_info.channel[c].channel2 = (i & 1) ? IIO_MOD_Q : IIO_MOD_I; @@ -4099,8 +4099,8 @@ static int ad9081_setup_chip_info_tbl(struct ad9081_phy *phy, phy->chip_info.channel[c].type = IIO_VOLTAGE; phy->chip_info.channel[c].output = 1; phy->chip_info.channel[c].indexed = 1; - phy->chip_info.channel[c].modified = complex ? 1 : 0; - phy->chip_info.channel[c].channel = complex ? i / 2 : i; + phy->chip_info.channel[c].modified = complex_tx ? 1 : 0; + phy->chip_info.channel[c].channel = complex_tx ? i / 2 : i; phy->chip_info.channel[c].channel2 = (i & 1) ? IIO_MOD_Q : IIO_MOD_I; phy->chip_info.channel[c].scan_index = -1; @@ -4747,7 +4747,9 @@ static int ad9081_probe(struct spi_device *spi) if (ret) break; conv->chip_info = &phy->chip_info; - ret = ad9081_setup_chip_info_tbl(phy, true, + ret = ad9081_setup_chip_info_tbl(phy, true, true, + // (phy->adc_dcm[0] == 1) ? false : true, + // (phy->tx_main_interp == 1) ? false : true, jesd204_dev_is_top(jdev)); if (ret) break; From dced6c9ccd312e25ca06b2a69484f3345f3bc396 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 21 Feb 2022 10:26:32 +0100 Subject: [PATCH 181/407] iio: adc: cf_axi_adc_core: Support for 64-bit IIO_CHAN_INFO_SAMP_FREQ This patch adds support for 64-bit sample rates. Signed-off-by: Michael Hennerich --- drivers/iio/adc/cf_axi_adc_core.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/cf_axi_adc_core.c b/drivers/iio/adc/cf_axi_adc_core.c index 7f743ee54b9a5e..147caeec9c8ad8 100644 --- a/drivers/iio/adc/cf_axi_adc_core.c +++ b/drivers/iio/adc/cf_axi_adc_core.c @@ -568,26 +568,30 @@ static int axiadc_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: + *val2 = 0; ret = conv->read_raw(indio_dev, chan, val, val2, m); - if (ret < 0 || !*val) { + llval = (u64)*val2 << 32 | *val; + if (ret < 0 || !llval) { tmp = ADI_TO_CLK_FREQ(axiadc_read(st, ADI_REG_CLK_FREQ)); llval = tmp * 100000000ULL /* FIXME */ * ADI_TO_CLK_RATIO(axiadc_read(st, ADI_REG_CLK_RATIO)); - *val = llval >> 16; + llval = llval >> 16; } - if (chan->extend_name) { + if (!strcmp(chan->extend_name, "user_logic")) { tmp = axiadc_read(st, ADI_REG_CHAN_USR_CNTRL_2(channel)); llval = ADI_TO_USR_DECIMATION_M(tmp) * conv->adc_clk; do_div(llval, ADI_TO_USR_DECIMATION_N(tmp)); - *val = llval; } if (st->decimation_factor) - *val /= st->decimation_factor; + do_div(llval, st->decimation_factor); - return IIO_VAL_INT; + *val = lower_32_bits(llval); + *val2 = upper_32_bits(llval); + + return IIO_VAL_INT_64; default: return conv->read_raw(indio_dev, chan, val, val2, m); From ae2c9ca5dbc7a1bfaae59a388d382c9b1b0c98ef Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 21 Feb 2022 10:29:02 +0100 Subject: [PATCH 182/407] iio: frequency: cf_axi_dds.c: Support for 64-bit IIO_CHAN_INFO_SAMP_FREQ This patch adds support for scaled sampl_clk, and 64-bit sample rates. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/cf_axi_dds.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/iio/frequency/cf_axi_dds.c b/drivers/iio/frequency/cf_axi_dds.c index fb8679342ac791..5bc460f7fe686e 100644 --- a/drivers/iio/frequency/cf_axi_dds.c +++ b/drivers/iio/frequency/cf_axi_dds.c @@ -102,6 +102,7 @@ struct cf_axi_dds_state { struct device *dev_spi; struct axi_data_offload_state *data_offload; struct clk *clk; + struct clock_scale clkscale; struct cf_axi_dds_chip_info *chip_info; struct gpio_desc *plddrbypass_gpio; struct gpio_desc *interpolation_gpio; @@ -284,12 +285,12 @@ int cf_axi_dds_pl_ddr_fifo_ctrl(struct cf_axi_dds_state *st, bool enable) } static int cf_axi_get_parent_sampling_frequency(struct cf_axi_dds_state *st, - unsigned long *freq) + u64 *freq) { struct cf_axi_converter *conv; if (st->standalone) { - *freq = st->dac_clk = clk_get_rate(st->clk); + *freq = st->dac_clk = clk_get_rate_scaled(st->clk, &st->clkscale); } else { conv = to_converter(st->dev_spi); if (!conv->get_data_clk) @@ -501,7 +502,8 @@ static int cf_axi_interpolation_set(struct cf_axi_dds_state *st, static ssize_t cf_axi_interpolation_store(struct cf_axi_dds_state *st, unsigned long frequency) { - unsigned long parent, val; + unsigned long val; + u64 parent; int i, ret; if (!frequency) @@ -511,7 +513,7 @@ static ssize_t cf_axi_interpolation_store(struct cf_axi_dds_state *st, if (ret < 0) return ret; - val = DIV_ROUND_CLOSEST(parent, frequency); + val = DIV_ROUND_CLOSEST_ULL(parent, frequency); for (i = 0; i < ARRAY_SIZE(interpolation_factors_available); i++) { if (val == interpolation_factors_available[i]) { @@ -529,7 +531,7 @@ static ssize_t cf_axi_sampling_frequency_available(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct cf_axi_dds_state *st = iio_priv(indio_dev); - unsigned long freq; + u64 freq; int i, ret; if (!st->interpolation_factor) @@ -543,8 +545,8 @@ static ssize_t cf_axi_sampling_frequency_available(struct device *dev, } for (i = 0, ret = 0; i < ARRAY_SIZE(interpolation_factors_available); i++) - ret += snprintf(buf + ret, PAGE_SIZE - ret, "%ld ", - freq / interpolation_factors_available[i]); + ret += snprintf(buf + ret, PAGE_SIZE - ret, "%lld ", + div_u64(freq, interpolation_factors_available[i])); ret += snprintf(&buf[ret], PAGE_SIZE - ret, "\n"); @@ -669,8 +671,7 @@ static int cf_axi_dds_read_raw(struct iio_dev *indio_dev, { struct cf_axi_dds_state *st = iio_priv(indio_dev); struct cf_axi_converter *conv; - unsigned long long val64; - unsigned long freq; + unsigned long long val64, freq; unsigned int reg, channel, phase = 0; int ret; @@ -722,12 +723,13 @@ static int cf_axi_dds_read_raw(struct iio_dev *indio_dev, break; if (chan->type == IIO_VOLTAGE && st->interpolation_factor) - freq /= st->interpolation_factor; + do_div(freq, st->interpolation_factor); - *val = freq; + *val = lower_32_bits(freq); + *val2 = upper_32_bits(freq); mutex_unlock(&indio_dev->mlock); - return IIO_VAL_INT; + return IIO_VAL_INT_64; case IIO_CHAN_INFO_CALIBPHASE: phase = 1; /* fall-through */ @@ -2198,11 +2200,13 @@ static int cf_axi_dds_probe(struct platform_device *pdev) if (IS_ERR(st->clk)) return PTR_ERR(st->clk); + of_clk_get_scale(np, "sampl_clk", &st->clkscale); + ret = clk_prepare_enable(st->clk); if (ret < 0) return ret; - st->dac_clk = clk_get_rate(st->clk); + st->dac_clk = clk_get_rate_scaled(st->clk, &st->clkscale); st->clk_nb.notifier_call = cf_axi_dds_rate_change; clk_notifier_register(st->clk, &st->clk_nb); From 8e59ec4c25a208ef31d44c7e0f71418317d80ec4 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 21 Feb 2022 10:31:00 +0100 Subject: [PATCH 183/407] iio: frequency: cf_axi_dds: New real variant of adi,axi-ad9081-tx-1.0 This patch adds a new compatible "adi,axi-ad9081-tx-1.0-real" used whenever samples are not complex IQ modified. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/cf_axi_dds.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/iio/frequency/cf_axi_dds.c b/drivers/iio/frequency/cf_axi_dds.c index 5bc460f7fe686e..0cde78a8369095 100644 --- a/drivers/iio/frequency/cf_axi_dds.c +++ b/drivers/iio/frequency/cf_axi_dds.c @@ -2023,6 +2023,13 @@ static const struct axidds_core_info ad9081_1_00_a_info = { .complex_modified = true, }; +static const struct axidds_core_info ad9081_1_00_a_real_info = { + .version = ADI_AXI_PCORE_VER(9, 1, 'b'), + .name = "AD9081", + .standalone = true, + .complex_modified = false, +}; + static const struct axidds_core_info ad9172_1_00_a_info = { .version = ADI_AXI_PCORE_VER(9, 1, 'b'), .name = "AD917x", @@ -2084,6 +2091,9 @@ static const struct of_device_id cf_axi_dds_of_match[] = { }, { .compatible = "adi,axi-ad9081-tx-1.0", .data = &ad9081_1_00_a_info, + }, { + .compatible = "adi,axi-ad9081-tx-1.0-real", + .data = &ad9081_1_00_a_real_info, }, { .compatible = "adi,axi-adrv9002-tx-1.0", .data = &adrv9002_9_01_b_info From 12a4e479395ac3518266b35936015cd587a21e97 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 21 Feb 2022 15:04:52 +0100 Subject: [PATCH 184/407] iio: adc: cf_axi_adc_core: Fix NULL pointer dereference in axiadc_read_raw Make sure extend_name exist before accessing it. Fixes: dced6c9ccd31( "iio: adc: cf_axi_adc_core: Support for 64-bit") Signed-off-by: Michael Hennerich --- drivers/iio/adc/cf_axi_adc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/cf_axi_adc_core.c b/drivers/iio/adc/cf_axi_adc_core.c index 147caeec9c8ad8..3ccddfaadc6631 100644 --- a/drivers/iio/adc/cf_axi_adc_core.c +++ b/drivers/iio/adc/cf_axi_adc_core.c @@ -577,7 +577,7 @@ static int axiadc_read_raw(struct iio_dev *indio_dev, llval = llval >> 16; } - if (!strcmp(chan->extend_name, "user_logic")) { + if (chan->extend_name && !strcmp(chan->extend_name, "user_logic")) { tmp = axiadc_read(st, ADI_REG_CHAN_USR_CNTRL_2(channel)); From b613d58ee08a3d85719559dd190b4c12deec00dc Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Wed, 22 Dec 2021 03:27:30 +0200 Subject: [PATCH 185/407] bindings: clock: ad9545: document use of zero delay DT bindings for use of zero-delay mode for AD9545. Signed-off-by: Alexandru Tachici --- .../devicetree/bindings/clock/clk-ad9545.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/clk-ad9545.yaml b/Documentation/devicetree/bindings/clock/clk-ad9545.yaml index ca7fad68d3d02a..84a27e1a11449e 100644 --- a/Documentation/devicetree/bindings/clock/clk-ad9545.yaml +++ b/Documentation/devicetree/bindings/clock/clk-ad9545.yaml @@ -267,6 +267,22 @@ patternProperties: '#size-cells': const: 0 + adi,pll-internal-zero-delay: + description: | + Rate of the output that will be used as a feedback path for this PLL bloc. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 200000000 + + adi,pll-internal-zero-delay-feedback: + description: | + Internal zero delay feedback path. Choose one from the possible outputs depending + on the parent PLL. If parrent PLL is PLL0 choose from [0, 5] otherweise [6, 9]. + Mentioning an output for the feedback path here, will cause the respective clock's + rate to become imutable. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + adi,fast-acq-trigger-mode: description: | If this is not specified Fast Acquisition will be used every time. See reg 0x2106 From e51ed899e04717dd8d53794222a0e6b35293ae75 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Thu, 6 Jan 2022 18:45:09 +0200 Subject: [PATCH 186/407] clk: clk-conf: allow user to setup an n-shot from DT Allow the user to setup an N-shot directly from DT by specifying the number of continuous pulses same as setting the clock rate. Signed-off-by: Alexandru Tachici --- drivers/clk/clk-conf.c | 55 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c index 2ef819606c4170..a44ef7cfb13ef8 100644 --- a/drivers/clk/clk-conf.c +++ b/drivers/clk/clk-conf.c @@ -116,6 +116,55 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) return 0; } +static int __set_clk_nshot(struct device_node *node, bool clk_supplier) +{ + struct of_phandle_args clkspec; + struct property *prop; + const __be32 *cur; + int rc, index = 0; + struct clk *clk; + u32 nshot; + + of_property_for_each_u32(node, "assigned-clock-nshot", prop, cur, nshot) { + if (nshot) { + rc = of_parse_phandle_with_args(node, "assigned-clocks", + "#clock-cells", index, &clkspec); + if (rc < 0) { + /* skip empty (null) phandles */ + if (rc == -ENOENT) + continue; + + return rc; + } + + if (clkspec.np == node && !clk_supplier) { + of_node_put(clkspec.np); + return 0; + } + + clk = of_clk_get_from_provider(&clkspec); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + pr_err("clk: couldn't get clock %d for %pOF\n", index, + node); + of_node_put(clkspec.np); + return PTR_ERR(clk); + } + + rc = clk_set_nshot(clk, nshot); + if (rc < 0) + pr_warn("clk: couldn't set %s clk nshot to %u (%d), current nshot: %u\n", + __clk_get_name(clk), nshot, rc, clk_get_nshot(clk)); + + clk_put(clk); + of_node_put(clkspec.np); + } + index++; + } + + return 0; +} + /** * of_clk_set_defaults() - parse and set assigned clocks configuration * @node: device node to apply clock settings for @@ -139,6 +188,10 @@ int of_clk_set_defaults(struct device_node *node, bool clk_supplier) if (rc < 0) return rc; - return __set_clk_rates(node, clk_supplier); + rc = __set_clk_rates(node, clk_supplier); + if (rc < 0) + return rc; + + return __set_clk_nshot(node, clk_supplier); } EXPORT_SYMBOL_GPL(of_clk_set_defaults); From 2d34810df5d3ebe0f7063304fd4070e2f098e75f Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Thu, 20 Jan 2022 20:03:48 +0200 Subject: [PATCH 187/407] blindings: clock: ad9545: document use of slew rate For certain phase sources, the DPLL provides a phase slew rate limiting function that places an upper bound on the rate of change of phase passed along to the loop filter. The phase slew rate limiter mitigates the adverse effects of injecting a large phase step into the loop by converting it to a phase ramp with the maximum slope set by the user. Signed-off-by: Alexandru Tachici --- Documentation/devicetree/bindings/clock/clk-ad9545.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/clk-ad9545.yaml b/Documentation/devicetree/bindings/clock/clk-ad9545.yaml index 84a27e1a11449e..822e12c48097e3 100644 --- a/Documentation/devicetree/bindings/clock/clk-ad9545.yaml +++ b/Documentation/devicetree/bindings/clock/clk-ad9545.yaml @@ -283,6 +283,13 @@ patternProperties: $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + adi,pll-slew-rate-limit-ps: + description: | + DPLL0 phase slew limit rate (in picoseconds/second). + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 4000000000 + adi,fast-acq-trigger-mode: description: | If this is not specified Fast Acquisition will be used every time. See reg 0x2106 From 64af96d2ea6f650a29b36b7571d6eacfc2e58a81 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Thu, 20 Jan 2022 20:05:34 +0200 Subject: [PATCH 188/407] clk: ad9545: add zero delay support Introduce support for the internal zero-delay mode of ad9545. Internal zero delay mode is a hitless mode (rather than phase buildout operating mode), in which the AD9545 gradually changes the output phase as it realigns to the phase of the new reference. Signed-off-by: Alexandru Tachici --- drivers/clk/adi/clk-ad9545.c | 354 +++++++++++++++++++++++++++++++++-- 1 file changed, 339 insertions(+), 15 deletions(-) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index 1d8d321a58e2c3..2508023eb6df6d 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -48,6 +48,13 @@ #define AD9545_FREQ_LOCK_FILL_RATE 0x0808 #define AD9545_FREQ_LOCK_DRAIN_RATE 0x0809 #define AD9545_DPLL0_FTW 0x1000 +#define AD9545_DPLL0_SLEW_RATE 0x1011 +#define AD9545_MODULATION_COUNTER_A0 0x10C2 +#define AD9545_MODULATION_COUNTER_B0 0x10C6 +#define AD9545_MODULATION_COUNTER_C0 0x10CA +#define AD9545_MODULATOR_A0 0x10CF +#define AD9545_MODULATOR_B0 0x10D0 +#define AD9545_MODULATOR_C0 0x10D1 #define AD9545_NSHOT_REQ_CH0 0x10D3 #define AD9545_NSHOT_EN_AB0 0x10D4 #define AD9545_NSHOT_EN_C0 0x10D5 @@ -59,12 +66,19 @@ #define AD9545_Q0A_PHASE_CONF 0x1108 #define AD9545_DPLL0_EN 0x1200 #define AD9545_DPLL0_SOURCE 0x1201 +#define AD9545_DPLL0_ZERO_DELAY_FB 0x1202 +#define AD9545_DPLL0_FB_MODE 0x1203 #define AD9545_DPLL0_LOOP_BW 0x1204 +#define AD9545_DPLL0_HITLESS_N 0x1208 #define AD9545_DPLL0_N_DIV 0x120C #define AD9545_DPLL0_FRAC 0x1210 #define AD9545_DPLL0_MOD 0x1213 #define AD9545_DPLL0_FAST_L1 0x1216 #define AD9545_DPLL0_FAST_L2 0x1217 +#define AD9545_MODULATION_COUNTER_A1 0x14C2 +#define AD9545_MODULATION_COUNTER_B1 0x14C6 +#define AD9545_MODULATOR_A1 0x14CF +#define AD9545_MODULATOR_B1 0x14D0 #define AD9545_NSHOT_EN_AB1 0x14D4 #define AD9545_DRIVER_1A_CONF 0x14D7 #define AD9545_Q1A_DIV 0x1500 @@ -140,9 +154,13 @@ #define AD9545_NSHOT_REQ_CH(x) (AD9545_NSHOT_REQ_CH0 + ((x) * 0x400)) #define AD9545_DPLLX_FTW(x) (AD9545_DPLL0_FTW + ((x) * 0x400)) +#define AD9545_DPLLX_SLEW_RATE(x) (AD9545_DPLL0_SLEW_RATE + ((x) * 0x400)) #define AD9545_DPLLX_EN(x, y) (AD9545_DPLL0_EN + ((x) * 0x400) + ((y) * 0x20)) #define AD9545_DPLLX_SOURCE(x, y) (AD9545_DPLL0_SOURCE + ((x) * 0x400) + ((y) * 0x20)) +#define AD9545_DPLLX_FB_PATH(x, y) (AD9545_DPLL0_ZERO_DELAY_FB + ((x) * 0x400) + ((y) * 0x20)) +#define AD9545_DPLLX_FB_MODE(x, y) (AD9545_DPLL0_FB_MODE + ((x) * 0x400) + ((y) * 0x20)) #define AD9545_DPLLX_LOOP_BW(x, y) (AD9545_DPLL0_LOOP_BW + ((x) * 0x400) + ((y) * 0x20)) +#define AD9545_DPLLX_HITLESS_N(x, y) (AD9545_DPLL0_HITLESS_N + ((x) * 0x400) + ((y) * 0x20)) #define AD9545_DPLLX_N_DIV(x, y) (AD9545_DPLL0_N_DIV + ((x) * 0x400) + ((y) * 0x20)) #define AD9545_DPLLX_FRAC_DIV(x, y) (AD9545_DPLL0_FRAC + ((x) * 0x400) + ((y) * 0x20)) #define AD9545_DPLLX_MOD_DIV(x, y) (AD9545_DPLL0_MOD + ((x) * 0x400) + ((y) * 0x20)) @@ -188,6 +206,11 @@ #define AD9545_EN_PROFILE_MSK BIT(0) #define AD9545_SEL_PRIORITY_MSK GENMASK(5, 1) +/* define AD9545_DPLLX_FB_MODE bitfields */ +#define AD9545_EN_HITLESS_MSK BIT(0) +#define AD9545_TAG_MODE_MSK GENMASK(4, 2) +#define AD9545_BASE_FILTER_MSK BIT(7) + /* AD9545_PWR_CALIB_CHX bitfields */ #define AD9545_PWR_DOWN_CH BIT(0) #define AD9545_CALIB_APLL BIT(1) @@ -204,6 +227,9 @@ #define AD9545_DIV_OPS_MUTE_A_MSK BIT(2) #define AD9545_DIV_OPS_MUTE_AA_MSK BIT(3) +/* AD9545 Modulator bitfields */ +#define AD9545_MODULATOR_EN BIT(0) + /* AD9545_NSHOT_REQ_CH bitfields */ #define AD9545_NSHOT_NR_MSK GENMASK(5, 0) @@ -241,6 +267,10 @@ #define AD9545_APLL_LOCKED(x) ((x) & BIT(3)) +/* AD9545 tagging modes */ +#define AD9545_NO_TAGGING 0 +#define AD9545_FB_PATH_TAG 2 + #define AD9545_SYS_CLK_STABILITY_MS 50 #define AD9545_R_DIV_MAX 0x40000000 @@ -259,6 +289,7 @@ #define AD9545_MAX_NSHOT_PULSES 63 #define AD9545_NCO_MAX_FREQ 65535 +#define AD9545_MAX_ZERO_DELAY_RATE 200000000 static const unsigned int ad9545_apll_rate_ranges_hz[2][2] = { {2400000000U, 3200000000U}, {3200000000U, 4000000000U} @@ -355,48 +386,70 @@ enum ad9545_output_mode { }; struct ad9545_outputs_regs { + u16 modulator_reg; + u16 modulation_counter_reg; u16 nshot_en_reg; u8 nshot_en_msk; }; static const struct ad9545_outputs_regs ad9545_out_regs[] = { { + .modulator_reg = AD9545_MODULATOR_A0, + .modulation_counter_reg = AD9545_MODULATION_COUNTER_A0, .nshot_en_reg = AD9545_NSHOT_EN_AB0, .nshot_en_msk = BIT(0), }, { + .modulator_reg = AD9545_MODULATOR_A0, + .modulation_counter_reg = AD9545_MODULATION_COUNTER_A0, .nshot_en_reg = AD9545_NSHOT_EN_AB0, .nshot_en_msk = BIT(2), }, { + .modulator_reg = AD9545_MODULATOR_B0, + .modulation_counter_reg = AD9545_MODULATION_COUNTER_B0, .nshot_en_reg = AD9545_NSHOT_EN_AB0, .nshot_en_msk = BIT(4), }, { + .modulator_reg = AD9545_MODULATOR_B0, + .modulation_counter_reg = AD9545_MODULATION_COUNTER_B0, .nshot_en_reg = AD9545_NSHOT_EN_AB0, .nshot_en_msk = BIT(6), }, { + .modulator_reg = AD9545_MODULATOR_C0, + .modulation_counter_reg = AD9545_MODULATION_COUNTER_C0, .nshot_en_reg = AD9545_NSHOT_EN_C0, .nshot_en_msk = BIT(0), }, { + .modulator_reg = AD9545_MODULATOR_C0, + .modulation_counter_reg = AD9545_MODULATION_COUNTER_C0, .nshot_en_reg = AD9545_NSHOT_EN_C0, .nshot_en_msk = BIT(2), }, { + .modulator_reg = AD9545_MODULATOR_A1, + .modulation_counter_reg = AD9545_MODULATION_COUNTER_A1, .nshot_en_reg = AD9545_NSHOT_EN_AB1, .nshot_en_msk = BIT(0), }, { + .modulator_reg = AD9545_MODULATOR_A1, + .modulation_counter_reg = AD9545_MODULATION_COUNTER_A1, .nshot_en_reg = AD9545_NSHOT_EN_AB1, .nshot_en_msk = BIT(2), }, { + .modulator_reg = AD9545_MODULATOR_B1, + .modulation_counter_reg = AD9545_MODULATION_COUNTER_B1, .nshot_en_reg = AD9545_NSHOT_EN_AB1, .nshot_en_msk = BIT(4), }, { + .modulator_reg = AD9545_MODULATOR_B1, + .modulation_counter_reg = AD9545_MODULATION_COUNTER_B1, .nshot_en_reg = AD9545_NSHOT_EN_AB1, .nshot_en_msk = BIT(6), }, @@ -410,6 +463,7 @@ struct ad9545_out_clk { u32 source_ua; struct clk_hw hw; unsigned int address; + unsigned long rate_requested_hz; }; struct ad9545_dpll_profile { @@ -422,6 +476,7 @@ struct ad9545_dpll_profile { unsigned int fast_acq_settle_ms; bool en; u8 tdc_source; + bool fb_tagging; }; struct ad9545_pll_clk { @@ -434,6 +489,11 @@ struct ad9545_pll_clk { struct ad9545_dpll_profile profiles[AD9545_MAX_DPLL_PROFILES]; unsigned int free_run_freq; unsigned int fast_acq_trigger_mode; + unsigned long rate_requested_hz; + bool internal_zero_delay; + u8 internal_zero_delay_source; + unsigned long internal_zero_delay_source_rate_hz; + u32 slew_rate_limit_ps; }; struct ad9545_ref_in_clk { @@ -679,6 +739,33 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) if (!ret) st->pll_clks[addr].fast_acq_trigger_mode = val; + ret = fwnode_property_read_u32(child, "adi,pll-slew-rate-limit-ps", &val); + if (!ret) + st->pll_clks[addr].slew_rate_limit_ps = val; + + prop_found = fwnode_property_present(child, "adi,pll-internal-zero-delay-feedback"); + st->pll_clks[addr].internal_zero_delay = prop_found; + + ret = fwnode_property_read_u32(child, "adi,pll-internal-zero-delay-feedback", &val); + if (prop_found && !ret) { + if (val >= ARRAY_SIZE(ad9545_out_clk_names)) { + dev_err(st->dev, "Invalid zero-delay fb path: %u.", val); + return -EINVAL; + } + + st->pll_clks[addr].internal_zero_delay_source = val; + } + + ret = fwnode_property_read_u32(child, "adi,pll-internal-zero-delay", &val); + if (prop_found && !ret) { + if (val >= AD9545_MAX_ZERO_DELAY_RATE) { + dev_err(st->dev, "Invalid zero-delay output rate: %u.", val); + return -EINVAL; + } + + st->pll_clks[addr].internal_zero_delay_source_rate_hz = val; + } + /* parse DPLL profiles */ fwnode_for_each_available_child_node(child, profile_node) { ret = fwnode_property_read_u32(profile_node, "reg", &profile_addr); @@ -1241,7 +1328,7 @@ static unsigned long ad95452_out_clk_recalc_rate(struct clk_hw *hw, unsigned lon static long ad9545_out_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { - u32 out_rate; + unsigned long out_rate; u32 qdiv; qdiv = div64_u64(*parent_rate, rate); @@ -1571,15 +1658,33 @@ static int ad9545_outputs_setup(struct ad9545_state *st) st->clks[AD9545_CLK_OUT][i] = st->out_clks[i].hw.clk; } - /* set to autosync to trigger on DPLL freq lock */ for (i = 0; i < ARRAY_SIZE(st->pll_clks); i++) { - reg = FIELD_PREP(AD9545_SYNC_CTRL_MODE_MSK, 3); + reg = 0; + + /* For hitless mode, wait for DPLL reference in order to sync outputs */ + if (st->pll_clks[i].internal_zero_delay) { + reg = FIELD_PREP(AD9545_SYNC_CTRL_DPLL_REF_MSK, 1); + + ret = regmap_write(st->regmap, AD9545_SYNC_CTRLX(i), reg); + if (ret < 0) + return ret; + + ret = ad9545_io_update(st); + if (ret < 0) + return ret; + } + + reg |= FIELD_PREP(AD9545_SYNC_CTRL_MODE_MSK, 1); ret = regmap_write(st->regmap, AD9545_SYNC_CTRLX(i), reg); if (ret < 0) return ret; + + ret = ad9545_io_update(st); + if (ret < 0) + return ret; } - return ad9545_io_update(st); + return 0; } static int ad9545_set_r_div(struct ad9545_state *st, u32 div, int addr) @@ -1806,6 +1911,9 @@ static int ad9545_set_freerun_freq(struct ad9545_pll_clk *clk, u32 freq) u64 ftw; int ret; + if (!freq) + return 0; + ret = ad9545_calc_ftw(clk, freq, &ftw); if (ret < 0) return ret; @@ -1834,9 +1942,63 @@ static u32 ad9545_calc_m_div(unsigned long rate) return m_div; } +/* + * Zero delay mode forbids use of the Fractional + * part of DPLL in calculation, turning + * the Digital PLL part in an Integer-N PLL. + * The configuration turns into two cascaded Integer N PLLs. + */ +static u64 ad9545_calc_pll_zero_delay_params(struct ad9545_pll_clk *clk, unsigned long rate, + unsigned long parent_rate, u32 *m, u32 *n, + int profile_nr) +{ + unsigned long out_rate_hz; + u32 m_div, n_div, q_div; + int output_nr; + + output_nr = clk->internal_zero_delay_source; + out_rate_hz = clk->internal_zero_delay_source_rate_hz; + + if (!out_rate_hz || !parent_rate) + return rate; + + /* + * The frequency translation factor for internal zero delay mode: + * f_out_x = N * f_ref_div_x + */ + n_div = DIV_ROUND_CLOSEST(out_rate_hz, parent_rate); + if (!n_div) + return rate; + + /* set q-div beforehand */ + q_div = DIV_ROUND_UP_ULL(rate, out_rate_hz); + ad9545_set_q_div(clk->st, output_nr, q_div); + + /* half divider at output requires APLL to generate twice the frequency demanded */ + rate *= 2; + + /* Find a suitable M divider */ + for (m_div = AD9545_APLL_M_DIV_MIN; m_div < AD9545_APLL_M_DIV_MAX; m_div++) { + unsigned long dpll_rate; + + if (rate % m_div != 0) + continue; + + dpll_rate = DIV_ROUND_UP_ULL(rate, m_div); + if (dpll_rate >= ad9545_apll_pfd_rate_ranges_hz[0] && + dpll_rate <= ad9545_apll_pfd_rate_ranges_hz[1]) + break; + } + + *m = m_div; + *n = n_div; + + return q_div * out_rate_hz; +} + static u64 ad9545_calc_pll_params(struct ad9545_pll_clk *clk, unsigned long rate, - unsigned long parent_rate, u32 *m, u32 *n, - unsigned long *frac, unsigned long *mod) + unsigned long parent_rate, bool zero_delay, u32 *m, u32 *n, + unsigned long *frac, unsigned long *mod, int profile_nr) { u32 min_dpll_n_div; u64 output_rate; @@ -1845,6 +2007,13 @@ static u64 ad9545_calc_pll_params(struct ad9545_pll_clk *clk, unsigned long rate u64 den; u64 num; + if (zero_delay) { + *frac = 0; + *mod = 1; + + return ad9545_calc_pll_zero_delay_params(clk, rate, parent_rate, m, n, profile_nr); + } + /* half divider at output requires APLL to generate twice the frequency demanded */ rate *= 2; @@ -1988,9 +2157,44 @@ static unsigned long ad9545_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long mod = le32_to_cpu(regval); - /* Output rate of APLL = parent_rate * (N + (Frac / Mod)) * M */ - output_rate = mul_u64_u32_div(frac * parent_rate, m, mod); - output_rate += parent_rate * n * m; + if (clk->internal_zero_delay) { + int output_nr = clk->internal_zero_delay_source; + u32 q_div; + + ret = ad9545_get_q_div(clk->st, output_nr, &q_div); + if (ret < 0) + return ret; + + if (!m) + return 0; + + if (clk->profiles[i].fb_tagging) { + ret = regmap_bulk_read(clk->st->regmap, + ad9545_out_regs[output_nr].modulation_counter_reg, + ®val, 4); + if (ret < 0) + return ret; + + n = le32_to_cpu(regval); + } else { + ret = regmap_bulk_read(clk->st->regmap, + AD9545_DPLLX_HITLESS_N(clk->address, i), + ®val, 4); + if (ret < 0) + return ret; + + n = le32_to_cpu(regval) + 1; + } + + output_rate = 2 * q_div * parent_rate * n; + } else { + if (!mod) + return 0; + + /* Output rate of APLL = parent_rate * (N + (Frac / Mod)) * M */ + output_rate = mul_u64_u32_div(frac * parent_rate, m, mod); + output_rate += parent_rate * n * m; + } return output_rate / 2; } @@ -2001,12 +2205,15 @@ static long ad9545_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate, struct ad9545_pll_clk *clk = to_pll_clk(hw); unsigned long frac; unsigned long mod; + bool zero_delay; int ret; u64 ftw; int i; u32 m; u32 n; + clk->rate_requested_hz = rate; + /* if no ref is valid, check if requested rate can be set in free run mode */ i = ad9545_pll_get_parent(hw); if (i == clk->num_parents) { @@ -2014,12 +2221,61 @@ static long ad9545_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate, m = ad9545_calc_m_div(rate * 2); ret = ad9545_calc_ftw(clk, div_u64(rate * 2, m), &ftw); if (ret < 0) - return 0; + return ret; return rate; } - return ad9545_calc_pll_params(clk, rate, *parent_rate, &m, &n, &frac, &mod); + zero_delay = clk->internal_zero_delay; + + return ad9545_calc_pll_params(clk, rate, *parent_rate, zero_delay, &m, &n, &frac, &mod, i); +} + +static int ad9545_pll_set_feedback_tagging(struct ad9545_pll_clk *clk, unsigned long rate, + unsigned long parent_rate, unsigned int profile_nr, + u32 *n) +{ + unsigned long out_rate_hz; + int fb_output_nr; + __le32 regval; + u32 q_div; + int ret; + u8 val; + + clk->profiles[profile_nr].fb_tagging = true; + + val = FIELD_PREP(AD9545_TAG_MODE_MSK, AD9545_FB_PATH_TAG) | AD9545_BASE_FILTER_MSK; + ret = regmap_update_bits(clk->st->regmap, AD9545_DPLLX_FB_MODE(clk->address, profile_nr), + AD9545_BASE_FILTER_MSK | AD9545_TAG_MODE_MSK, val); + if (ret < 0) + return ret; + + fb_output_nr = clk->internal_zero_delay_source; + out_rate_hz = clk->internal_zero_delay_source_rate_hz; + + if (!out_rate_hz) + return 0; + + q_div = DIV_ROUND_UP_ULL(rate, out_rate_hz); + + /* Limit tagging frequency via N-Div */ + *n = DIV_ROUND_UP(out_rate_hz, AD9545_IN_MAX_TDC_FREQ_HZ); + regval = cpu_to_le32(*n - 1); + ret = regmap_bulk_write(clk->st->regmap, AD9545_DPLLX_HITLESS_N(clk->address, profile_nr), + ®val, 4); + if (ret < 0) + return ret; + + /* determine modulation period */ + regval = cpu_to_le32(DIV_ROUND_CLOSEST_ULL(rate, q_div * parent_rate)); + ret = regmap_bulk_write(clk->st->regmap, + ad9545_out_regs[fb_output_nr].modulation_counter_reg, + ®val, 4); + if (ret < 0) + return ret; + + return regmap_update_bits(clk->st->regmap, ad9545_out_regs[fb_output_nr].modulator_reg, + AD9545_MODULATOR_EN, AD9545_MODULATOR_EN); } static int ad9545_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) @@ -2028,7 +2284,10 @@ static int ad9545_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned l unsigned long out_rate; unsigned long frac; unsigned long mod; + int fb_output_nr; + bool zero_delay; __le32 regval; + u32 q_div; int ret; u32 m; u32 n; @@ -2041,12 +2300,54 @@ static int ad9545_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned l for (i = 0; i < clk->num_parents; i++) { parent_rate = clk_hw_get_rate(clk->parents[i]); - out_rate = ad9545_calc_pll_params(clk, rate, parent_rate, &m, &n, &frac, &mod); - if (out_rate != rate) - return -EINVAL; + zero_delay = clk->internal_zero_delay; + out_rate = ad9545_calc_pll_params(clk, rate, parent_rate, zero_delay, &m, &n, &frac, + &mod, i); + + /* + * Feedback under 2 kHz needs to be from tagged + * sources when hitless mode is active. + */ + clk->profiles[i].fb_tagging = false; + if (zero_delay && parent_rate < 2000) { + ret = ad9545_pll_set_feedback_tagging(clk, rate, parent_rate, i, &n); + } else if (zero_delay) { + ret = regmap_write(clk->st->regmap, + AD9545_DPLLX_FB_MODE(clk->address, i), + FIELD_PREP(AD9545_EN_HITLESS_MSK, 1)); + } else { + ret = regmap_write(clk->st->regmap, + AD9545_DPLLX_FB_MODE(clk->address, i), 0); + } + + if (ret < 0) + return ret; + + if (zero_delay) { + /* + * In zero delay mode: Phase Buildout N needs to be programmed to: + * N BUILDOUT = N HITLESS × 2 × Q/M + */ + + fb_output_nr = clk->internal_zero_delay_source; + if (!clk->internal_zero_delay_source_rate_hz) + return 0; + + q_div = DIV_ROUND_UP_ULL(rate, clk->internal_zero_delay_source_rate_hz); + regval = cpu_to_le32(DIV_ROUND_UP(n * 2 * q_div, m) - 1); + } else { + regval = cpu_to_le32(n - 1); + } + + ret = regmap_bulk_write(clk->st->regmap, + AD9545_DPLLX_N_DIV(clk->address, i), + ®val, 4); + if (ret < 0) + return ret; regval = cpu_to_le32(n - 1); - ret = regmap_bulk_write(clk->st->regmap, AD9545_DPLLX_N_DIV(clk->address, i), + ret = regmap_bulk_write(clk->st->regmap, + AD9545_DPLLX_HITLESS_N(clk->address, i), ®val, 4); if (ret < 0) return ret; @@ -2176,6 +2477,13 @@ static int ad9545_plls_setup(struct ad9545_state *st) pll->num_parents = init[i].num_parents; pll->parents = init[i].parent_hws; + if (!pll->slew_rate_limit_ps) { + regval = cpu_to_le32(pll->slew_rate_limit_ps); + ret = regmap_bulk_write(st->regmap, AD9545_DPLLX_SLEW_RATE(i), ®val, 4); + if (ret < 0) + return ret; + } + for (j = 0; j < AD9545_MAX_DPLL_PROFILES; j++) { if (!pll->profiles[j].en) continue; @@ -2189,6 +2497,22 @@ static int ad9545_plls_setup(struct ad9545_state *st) if (ret < 0) return ret; + reg = pll->internal_zero_delay_source; + if (i > 0) { + /* output numbering in this reg starts from 0 for each DPLL */ + if (reg > 5) + reg -= 6; + } + + ret = regmap_write(st->regmap, AD9545_DPLLX_FB_PATH(i, j), reg); + if (ret < 0) + return ret; + + reg = FIELD_PREP(AD9545_EN_HITLESS_MSK, pll->internal_zero_delay); + ret = regmap_write(st->regmap, AD9545_DPLLX_FB_MODE(i, j), reg); + if (ret < 0) + return ret; + /* set TDC source */ tdc_source = pll->profiles[j].tdc_source; ret = regmap_write(st->regmap, AD9545_DPLLX_SOURCE(i, j), From 486440c0213ff672334d165caad51bc140321ab4 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Thu, 6 Jan 2022 18:44:37 +0200 Subject: [PATCH 189/407] iio: hmc7044: add n-shot trigger If a sync_clk is specified and it supports n-shot generation, enable it in order to align the inputs of HMC7044 to the reference phase. Signed-off-by: Alexandru Tachici --- drivers/iio/frequency/hmc7044.c | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/iio/frequency/hmc7044.c b/drivers/iio/frequency/hmc7044.c index 4ea0309d8e1576..d688004f5dc545 100644 --- a/drivers/iio/frequency/hmc7044.c +++ b/drivers/iio/frequency/hmc7044.c @@ -598,6 +598,7 @@ static ssize_t hmc7044_sync_pin_mode_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct hmc7044 *hmc = iio_priv(indio_dev); + struct clk *sync_clk; int i, ret = -EINVAL; i = sysfs_match_string(sync_pin_modes, buf); @@ -607,6 +608,40 @@ static ssize_t hmc7044_sync_pin_mode_store(struct device *dev, mutex_unlock(&hmc->lock); } + if (ret) + return ret; + + sync_clk = clk_get(dev, "sync_clk"); + if (!IS_ERR(sync_clk)) { + /* + * Setup sync_clk to generate 1 pulse on clk_enable, + * if it is not configured to do that already. + */ + i = clk_get_nshot(sync_clk); + if (i < 0) { + clk_put(sync_clk); + return ret; + } + + if (i != 1) { + ret = clk_set_nshot(sync_clk, 1); + if (ret < 0) { + clk_put(sync_clk); + return ret; + } + } + + /* + * Above we setup the n-shot to only one pulse. + * Enable the clock to physically send the pulse. + * Disable the clock to prevent to a future error caused + * by enabling the same clock twice. + */ + clk_prepare_enable(sync_clk); + clk_disable_unprepare(sync_clk); + clk_put(sync_clk); + } + return ret ? ret : len; } From 73809012187e3dbd71ecb68fcd0bdd4c72bbb912 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Thu, 13 Jan 2022 20:28:22 +0200 Subject: [PATCH 190/407] clk: ad9545: fix output current selection Wrong iterator used here. Fixes: e649163a47aef ("clk: ad9545: Add support") Signed-off-by: Alexandru Tachici --- drivers/clk/adi/clk-ad9545.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index 2508023eb6df6d..1f7d64e7dfcea4 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -1617,7 +1617,7 @@ static int ad9545_outputs_setup(struct ad9545_state *st) for (j = 0; j < ARRAY_SIZE(ad9545_out_source_ua); j++) if (ad9545_out_source_ua[j] == st->out_clks[out_i].source_ua) - reg |= FIELD_PREP(GENMASK(2, 1), i); + reg |= FIELD_PREP(GENMASK(2, 1), j); reg |= FIELD_PREP(GENMASK(4, 3), st->out_clks[out_i].output_mode); From 39c5ee229e8af008e17cea12b45ab4352429db6d Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Tue, 18 Jan 2022 16:13:02 +0200 Subject: [PATCH 191/407] clk: ad9545: Fix validation timer write Validation timer was not written on the device. Fixes: e649163a47aef ("clk: ad9545: Add support") Signed-off-by: Alexandru Tachici --- drivers/clk/adi/clk-ad9545.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index 1f7d64e7dfcea4..21f0a1f2d4b843 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -41,6 +41,7 @@ #define AD9545_REF_A_PERIOD 0x0404 #define AD9545_REF_A_OFFSET_LIMIT 0x040C #define AD9545_REF_A_MONITOR_HYST 0x040F +#define AD9545_REF_A_VALID_TIMER 0x0410 #define AD9545_PHASE_LOCK_THRESH 0x0800 #define AD9545_PHASE_LOCK_FILL_RATE 0x0803 #define AD9545_PHASE_LOCK_DRAIN_RATE 0x0804 @@ -116,6 +117,7 @@ #define AD9545_REF_X_PERIOD(x) (AD9545_REF_A_PERIOD + ((x) * 0x20)) #define AD9545_REF_X_OFFSET_LIMIT(x) (AD9545_REF_A_OFFSET_LIMIT + ((x) * 0x20)) #define AD9545_REF_X_MONITOR_HYST(x) (AD9545_REF_A_MONITOR_HYST + ((x) * 0x20)) +#define AD9545_REF_X_VALID_TIMER(x) (AD9545_REF_A_VALID_TIMER + ((x) * 0x20)) #define AD9545_REF_X_PHASE_LOCK_FILL(x) (AD9545_PHASE_LOCK_FILL_RATE + ((x) * 0x20)) #define AD9545_REF_X_PHASE_LOCK_DRAIN(x) (AD9545_PHASE_LOCK_DRAIN_RATE + ((x) * 0x20)) #define AD9545_REF_X_FREQ_LOCK_FILL(x) (AD9545_FREQ_LOCK_FILL_RATE + ((x) * 0x20)) @@ -1819,6 +1821,12 @@ static int ad9545_input_refs_setup(struct ad9545_state *st) if (ret < 0) return ret; + regval = cpu_to_le32(st->ref_in_clks[i].valid_t_ms); + ret = regmap_bulk_write(st->regmap, AD9545_REF_X_VALID_TIMER(i), + ®val, 3); + if (ret < 0) + return ret; + regval = cpu_to_le32(st->ref_in_clks[i].phase_thresh_ps); ret = regmap_bulk_write(st->regmap, AD9545_SOURCEX_PHASE_THRESH(i), ®val, 3); From fe8b7e56e657e05595df9d1fe9d426e47c5a0a2a Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Thu, 20 Jan 2022 19:39:52 +0200 Subject: [PATCH 192/407] clk: ad9545: Fix free run rate recalc Fix recalculate rate function for the free-run case. Fixes: e649163a47aef ("clk: ad9545: Add support") Signed-off-by: Alexandru Tachici --- drivers/clk/adi/clk-ad9545.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index 21f0a1f2d4b843..707aec057aaa03 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -2141,7 +2141,7 @@ static unsigned long ad9545_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long */ i = ad9545_pll_get_parent(hw); if (i == clk->num_parents) - return div_u64(clk->free_run_freq * m, 2); + return DIV_ROUND_UP(clk->free_run_freq, 2) * m; parent_rate = clk_hw_get_rate(clk->parents[i]); From c631a3cfd604380f24ccbffeca6fa0d3c695bdba Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 27 Dec 2021 13:12:59 +0200 Subject: [PATCH 193/407] iio: addac: ad74413r: use ngpio size when iterating over mask ngpio is the actual number of GPIOs handled by the GPIO chip, as opposed to the max number of GPIOs. Fixes: fea251b6a5db ("iio: addac: add AD74413R driver") Signed-off-by: Cosmin Tanislav Reviewed-by: Andy Shevchenko --- drivers/iio/addac/ad74413r.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index a2b1f6625fee59..bcf609db63afac 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -288,7 +288,7 @@ static void ad74413r_gpio_set_multiple(struct gpio_chip *chip, unsigned int offset = 0; int ret; - for_each_set_bit_from(offset, mask, AD74413R_CHANNEL_MAX) { + for_each_set_bit_from(offset, mask, chip->ngpio) { unsigned int real_offset = st->gpo_gpio_offsets[offset]; ret = ad74413r_set_gpo_config(st, real_offset, @@ -334,7 +334,7 @@ static int ad74413r_gpio_get_multiple(struct gpio_chip *chip, if (ret) return ret; - for_each_set_bit_from(offset, mask, AD74413R_CHANNEL_MAX) { + for_each_set_bit_from(offset, mask, chip->ngpio) { unsigned int real_offset = st->comp_gpio_offsets[offset]; if (val & BIT(real_offset)) From 3cc1d29573808cf68c1e11e00c3566c2140dc6e7 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 27 Dec 2021 13:14:19 +0200 Subject: [PATCH 194/407] iio: addac: ad74413r: correct comparator gpio getters mask usage The value of the GPIOs is currently altered using offsets rather than masks. Make use of __assign_bit and the BIT macro to turn the offsets into masks. Fixes: fea251b6a5db ("iio: addac: add AD74413R driver") Signed-off-by: Cosmin Tanislav --- drivers/iio/addac/ad74413r.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index bcf609db63afac..e316136a6ed32c 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -134,7 +134,6 @@ struct ad74413r_state { #define AD74413R_CH_EN_MASK(x) BIT(x) #define AD74413R_REG_DIN_COMP_OUT 0x25 -#define AD74413R_DIN_COMP_OUT_SHIFT_X(x) x #define AD74413R_REG_ADC_RESULT_X(x) (0x26 + (x)) #define AD74413R_ADC_RESULT_MAX GENMASK(15, 0) @@ -316,7 +315,7 @@ static int ad74413r_gpio_get(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - status &= AD74413R_DIN_COMP_OUT_SHIFT_X(real_offset); + status &= BIT(real_offset); return status ? 1 : 0; } @@ -337,8 +336,7 @@ static int ad74413r_gpio_get_multiple(struct gpio_chip *chip, for_each_set_bit_from(offset, mask, chip->ngpio) { unsigned int real_offset = st->comp_gpio_offsets[offset]; - if (val & BIT(real_offset)) - *bits |= offset; + __assign_bit(offset, bits, val & BIT(real_offset)); } return ret; From 0bf96a08d41bf98c00d722fe9dddeaa11131e547 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 27 Dec 2021 13:13:56 +0200 Subject: [PATCH 195/407] iio: addac: ad74413r: for_each_set_bit_from -> for_each_set_bit The starting bit is always zero, it doesn't make much sense to use for_each_set_bit_from. Replace it with for_each_set_bit which doesn't start from a particular bit. Signed-off-by: Cosmin Tanislav Reviewed-by: Andy Shevchenko --- drivers/iio/addac/ad74413r.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index e316136a6ed32c..ac79ed69c2e0ba 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -284,10 +284,10 @@ static void ad74413r_gpio_set_multiple(struct gpio_chip *chip, struct ad74413r_state *st = gpiochip_get_data(chip); unsigned long real_mask = 0; unsigned long real_bits = 0; - unsigned int offset = 0; + unsigned int offset; int ret; - for_each_set_bit_from(offset, mask, chip->ngpio) { + for_each_set_bit(offset, mask, chip->ngpio) { unsigned int real_offset = st->gpo_gpio_offsets[offset]; ret = ad74413r_set_gpo_config(st, real_offset, @@ -325,7 +325,7 @@ static int ad74413r_gpio_get_multiple(struct gpio_chip *chip, unsigned long *bits) { struct ad74413r_state *st = gpiochip_get_data(chip); - unsigned int offset = 0; + unsigned int offset; unsigned int val; int ret; @@ -333,7 +333,7 @@ static int ad74413r_gpio_get_multiple(struct gpio_chip *chip, if (ret) return ret; - for_each_set_bit_from(offset, mask, chip->ngpio) { + for_each_set_bit(offset, mask, chip->ngpio) { unsigned int real_offset = st->comp_gpio_offsets[offset]; __assign_bit(offset, bits, val & BIT(real_offset)); From a726a76dca21b643122716e535b4d6b11ccba59a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 12 Jan 2022 12:34:56 -0800 Subject: [PATCH 196/407] iio: addac: ad74413r: Do not reference negative array offsets Instead of aiming rx_buf at an invalid array-boundary-crossing location, just skip the first increment. Seen when building with -Warray-bounds: drivers/iio/addac/ad74413r.c: In function 'ad74413r_update_scan_mode': drivers/iio/addac/ad74413r.c:843:22: warning: array subscript -4 is below array bounds of 'u8[16]' { aka 'unsigned char[16]'} [-Warray-bounds] 843 | u8 *rx_buf = &st->adc_samples_buf.rx_buf[-1 * AD74413R_FRAME_SIZE]; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/iio/addac/ad74413r.c:84:20: note: while referencing 'rx_buf' 84 | u8 rx_buf[AD74413R_FRAME_SIZE * AD74413R_CHANNEL_MAX]; | ^~~~~~ Cc: Lars-Peter Clausen Cc: Michael Hennerich Cc: Jonathan Cameron Cc: linux-iio@vger.kernel.org Fixes: fea251b6a5db ("iio: addac: add AD74413R driver") Reviewed-by: Cosmin Tanislav Signed-off-by: Kees Cook Reviewed-by: Cosmin Tanislav --- drivers/iio/addac/ad74413r.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index ac79ed69c2e0ba..f3cff0ce74f9c9 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -838,7 +838,7 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev, { struct ad74413r_state *st = iio_priv(indio_dev); struct spi_transfer *xfer = st->adc_samples_xfer; - u8 *rx_buf = &st->adc_samples_buf.rx_buf[-1 * AD74413R_FRAME_SIZE]; + u8 *rx_buf = st->adc_samples_buf.rx_buf; u8 *tx_buf = st->adc_samples_tx_buf; unsigned int channel; int ret = -EINVAL; @@ -892,9 +892,10 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev, spi_message_add_tail(xfer, &st->adc_samples_msg); - xfer++; tx_buf += AD74413R_FRAME_SIZE; - rx_buf += AD74413R_FRAME_SIZE; + if (xfer != st->adc_samples_xfer) + rx_buf += AD74413R_FRAME_SIZE; + xfer++; } xfer->rx_buf = rx_buf; From 7db932725679a170725cd248296d742903390bed Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 23 Feb 2022 11:23:49 +0200 Subject: [PATCH 197/407] iio: beamformer: adar1000: Fix detector_en value ADAR1000 detector_en attribute should be boolean https://jira.analog.com/browse/SDGSW-911 Fixes: dc7036543e06a649eb73e2a53d984bff4ef0e894 ("iio: adc: adar1000: Add powerdown and detector enables) Signed-off-by: Cristian Pop --- drivers/iio/beamformer/adar1000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/beamformer/adar1000.c b/drivers/iio/beamformer/adar1000.c index ca3dbe02858de5..f8b25f772cd057 100644 --- a/drivers/iio/beamformer/adar1000.c +++ b/drivers/iio/beamformer/adar1000.c @@ -1989,7 +1989,7 @@ static ssize_t adar1000_read_enable(struct iio_dev *indio_dev, if (ret < 0) return ret; - val = (val & 0xf) & (0x8 >> chan->channel); + val = !!((val & 0xf) & (0x8 >> chan->channel)); break; case ADAR1000_PA_BIAS_ON: From 2e5ee7acf2340b7dcb203759e880d045d95d54d0 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 23 Feb 2022 11:53:21 +0200 Subject: [PATCH 198/407] iio: beamformer: adar1000: Fix 'phase' out of range setting Channel attribute 'phase' is currently wrapped according to a modulo operation. That is setting it to a value of say, 450 writes the nearest allowable value to 90. For consistency, when writing a value outside of 0-360, it's nearest value is either 0 or 360. That is 450 maps to 360 instead of the wrap-around approach. https://jira.analog.com/browse/SDGSW-787 Fixes: 352467ba73c13f81cd08cd34115936e1c570608a ("iio: adc: adar1000: Fix phase selection logic") Signed-off-by: Cristian Pop --- drivers/iio/beamformer/adar1000.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/beamformer/adar1000.c b/drivers/iio/beamformer/adar1000.c index f8b25f772cd057..dca311b636b95c 100644 --- a/drivers/iio/beamformer/adar1000.c +++ b/drivers/iio/beamformer/adar1000.c @@ -507,9 +507,11 @@ static void adar1000_phase_search(struct adar1000_state *st, int val, int val2, { int i, prev, next; - val %= 360; + if (val > 360) + val = 360; + if (val < 0) - val += 360; + val = 0; for (i = 0; i < st->pt_size - 1; i++) { if (st->pt_info[i].val > val) From a202372af5be8663739274dd9ac83edbe31e7b5d Mon Sep 17 00:00:00 2001 From: Andrei Drimbarean Date: Thu, 17 Feb 2022 10:48:38 +0200 Subject: [PATCH 199/407] arch:arm:boot:dts:adrv9002: update TX DMA interrupt Update TX DMA interrupt number to avoid having the same on as the FMC I2C interrupt. New ID is according to HDL update. Signed-off-by: Andrei Drimbarean --- arch/arm/boot/dts/zynq-adrv9002-rx2tx2.dtsi | 2 +- arch/arm/boot/dts/zynq-adrv9002.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/zynq-adrv9002-rx2tx2.dtsi b/arch/arm/boot/dts/zynq-adrv9002-rx2tx2.dtsi index 61414e374f61a9..9ff9cd0c7a9d80 100644 --- a/arch/arm/boot/dts/zynq-adrv9002-rx2tx2.dtsi +++ b/arch/arm/boot/dts/zynq-adrv9002-rx2tx2.dtsi @@ -28,7 +28,7 @@ compatible = "adi,axi-dmac-1.00.a"; reg = <0x44A50000 0x10000>; #dma-cells = <1>; - interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <0 53 IRQ_TYPE_LEVEL_HIGH>; clock-names = "s_axi_aclk", "m_src_axi_aclk", "m_axis_aclk"; clocks = <&clkc 15>, <&clkc 16>, <&misc_clk_0>; diff --git a/arch/arm/boot/dts/zynq-adrv9002.dtsi b/arch/arm/boot/dts/zynq-adrv9002.dtsi index 8cc39776985056..ede78659c560ae 100644 --- a/arch/arm/boot/dts/zynq-adrv9002.dtsi +++ b/arch/arm/boot/dts/zynq-adrv9002.dtsi @@ -50,7 +50,7 @@ compatible = "adi,axi-dmac-1.00.a"; reg = <0x44A50000 0x10000>; #dma-cells = <1>; - interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <0 53 IRQ_TYPE_LEVEL_HIGH>; clock-names = "s_axi_aclk", "m_src_axi_aclk", "m_axis_aclk"; clocks = <&clkc 15>, <&clkc 16>, <&misc_clk_0>; From ec03c55382cf925d0546a1484424a50a0779e551 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 23 Feb 2022 17:59:05 +0100 Subject: [PATCH 200/407] iio: adc: ad9081: Only WARN in case SPI ID doesn't match chip ID Let's turn this case into a warning. We already check if the chip ID is in the list of supported IDs. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index c29f4486e0c04e..5aedefa936a66b 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -4705,12 +4705,7 @@ static int ad9081_probe(struct spi_device *spi) return -ENODEV; } - spi_id = spi_get_device_id(spi)->driver_data; conv->id = phy->chip_id.prod_id; - if (conv->id != (spi_id & CHIPID_MASK)) { - dev_err(&spi->dev, "Unrecognized CHIP_ID 0x%X\n", conv->id); - return -ENODEV; - } if (!phy->rx_disable) ad9081_clk_register(phy, "-rx_sampl_clk", @@ -4743,6 +4738,12 @@ static int ad9081_probe(struct spi_device *spi) case CHIPID_AD9082: case CHIPID_AD9988: case CHIPID_AD9986: + spi_id = spi_get_device_id(spi)->driver_data & CHIPID_MASK; + + if (conv->id != spi_id) + dev_warn(&spi->dev, "Expected AD%X found AD%X\n", + spi_id, conv->id); + ret = ad9081_setup(spi); if (ret) break; From 12fa83a09b14bc36a5a1e2e0babe336ade859d86 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Fri, 25 Feb 2022 16:30:37 +0200 Subject: [PATCH 201/407] arch: arm64: dts: stingray: Add ZUD1A-BREAKOUT eval board EEPROM This is useful for EEPROM programming and VADJ enable, using fru-dump tool. Signed-off-by: Cristian Pop --- .../dts/xilinx/zynqmp-zcu102-rev10-stingray.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts index 1c585a9bdd45fc..089eb5289dc57a 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts @@ -332,3 +332,19 @@ &hmc7044 { adi,pll1-ref-prio-ctrl = <0xE1>; /* prefer CLKIN1 -> CLKIN0 -> CLKIN2 -> CLKIN3 */ }; + +&i2c1 { + i2c-mux@75 { + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + /* HPC1_IIC */ + eeprom@50 { + compatible = "at24,24c02"; + reg = <0x50>; + }; + + }; + }; +}; From fe8965dd8de2d9ed58b64bf480d57a283afa76c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 25 Feb 2022 16:30:32 +0100 Subject: [PATCH 202/407] io: adrv9002: Update API to 48.49.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDK is taken as is which means that compilation will likely fail. The following patches will integrate the new SDK with linux and the existing driver code. Signed-off-by: Nuno Sá --- .../adrv9001/private/src/adrv9001_arm.c | 84 ++++------ .../public/include/adi_adrv9001_cals.h | 37 ++++ .../public/include/adi_adrv9001_cals_types.h | 26 +-- .../adrv9001/public/include/adi_adrv9001_fh.h | 26 ++- .../public/include/adi_adrv9001_fh_types.h | 4 +- .../public/include/adi_adrv9001_gpio.h | 53 ++---- .../public/include/adi_adrv9001_gpio_types.h | 11 +- .../include/adi_adrv9001_rx_gaincontrol.h | 4 +- .../adi_adrv9001_rx_gaincontrol_types.h | 2 + .../public/include/adi_adrv9001_rx_types.h | 15 +- .../public/include/adi_adrv9001_spi_types.h | 8 +- .../adrv9001/public/include/adi_adrv9001_tx.h | 4 +- .../public/include/adi_adrv9001_types.h | 11 ++ .../public/include/adi_adrv9001_version.h | 2 +- .../public/include/adrv9001_Init_t_parser.h | 6 +- .../adrv9001/public/src/adi_adrv9001_arm.c | 29 ++++ .../adrv9001/public/src/adi_adrv9001_cals.c | 82 +++++++++ .../adrv9001/public/src/adi_adrv9001_dpd.c | 12 +- .../adrv9001/public/src/adi_adrv9001_fh.c | 158 ++++++++++-------- .../adrv9001/public/src/adi_adrv9001_gpio.c | 41 +---- .../adrv9001/public/src/adi_adrv9001_rx.c | 82 +++++---- .../public/src/adi_adrv9001_rx_gaincontrol.c | 62 ++++++- .../adrv9001/public/src/adi_adrv9001_spi.c | 4 +- .../adrv9001/public/src/adi_adrv9001_ssi.c | 11 +- .../adrv9001/public/src/adi_adrv9001_tx.c | 120 ++++++------- 25 files changed, 543 insertions(+), 351 deletions(-) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c b/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c index 9f162219fa0500..70265f5341d423 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c @@ -36,10 +36,6 @@ #include "adrv9001_reg_addr_macros.h" #include "adrv9001_bf.h" #include "adi_adrv9001_hal.h" -#ifdef __KERNEL__ -#include -#endif - /* Header files related to libraries */ @@ -105,8 +101,8 @@ const char* const adrv9001_error_table_CmdCtrlMboxCmdError[] = "Command error" }; -const char* const adrv9001_error_table_CmdError[] = -{ +const char* const adrv9001_error_table_CmdError[] = +{ "Error occurred during an Init Calibration. Check that no signal is being applied to the Rx ports. Check that " "correct external LOs are applied, and synchronized, where appropriate", "Error occurred during a Tracking Calibration. Disable tracking calibrations, reset and program. If enabled " @@ -255,7 +251,7 @@ static __maybe_unused int32_t adrv9001_DmaMemReadByte(adi_adrv9001_Device_t *dev } regRead |= ADRV9001_DMA_CTL_LEGACY_MODE; - + /* bus size, 2'b00=byte; 2'b01=half-word; 2'b10=full-word; 2'b11=invalid */ /* core_bf.bus_size.write(bf_status, 2'b10); */ regRead |= ADRV9001_BF_ENCODE(0, ADRV9001_DMA_CTL_BUS_SIZE_MASK, ADRV9001_DMA_CTL_BUS_SIZE_SHIFT); @@ -327,7 +323,7 @@ static __maybe_unused int32_t adrv9001_DmaMemReadByte(adi_adrv9001_Device_t *dev returnData[i + 1] = dataRead0; ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_2", ADRV9001_ADDR_ARM_DMA_DATA2, &dataRead0); returnData[i + 2] = dataRead0; - + /* 'single_instruction' has to be cleared before reading DMA_DATA3 and set back after */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x0); ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_3", ADRV9001_ADDR_ARM_DMA_DATA3, &dataRead0); @@ -1044,7 +1040,7 @@ static void adrv9001_LoadSsiConfig(adi_adrv9001_Device_t *device, uint32_t *offs cfgData[tempOffset++] = (uint8_t)ssiConfig->cmosClkInversionEn; cfgData[tempOffset++] = (uint8_t)ssiConfig->ddrEn; - + cfgData[tempOffset++] = (uint8_t)ssiConfig->rxMaskStrobeEn; /* 4 bytes of padding is needed for alignment */ @@ -1565,15 +1561,15 @@ typedef struct duplexMode_e duplexMode; uint8_t fhModeOn; uint8_t reserved1[1u]; //< Reserved for future feature - uint8_t numDynamicProfile; // Number of Profile. =1 means only one profile and no switching + uint8_t numDynamicProfile; // Number of Profile. =1 means only one profile and no switching mcsMode_e mcsMode; // MCS mode selection: 0 - Disable, 1 - MCS Only, 2 - MCS + RFPLL phase sync - adcType_e adcTypeMonitor; // ADC type used in Monitor Mode - uint16_t pllLockTime_us; // Required lock time in microseconds for PLLs, based on ref_clk and loop bandwidth - pllModulus_t pllModuli; // PLL moduli - uint16_t pllPhaseSyncWait_us; // Worst case phase sync wait time in FH - mcsInf_e mcsInterfaceType; // 0-Disabled, 1-CMOS, 2-LVDS - uint8_t warmBootEnable; // Enable WarmBoot - Load initCal cefficients instead of running initCals - uint32_t reserved[1u]; // Reserved for future feature + adcType_e adcTypeMonitor; // ADC type used in Monitor Mode + uint16_t pllLockTime_us; // Required lock time in microseconds for PLLs, based on ref_clk and loop bandwidth + pllModulus_t pllModuli; // PLL moduli + uint16_t pllPhaseSyncWait_us; // Worst case phase sync wait time in FH + mcsInf_e mcsInterfaceType; // 0-Disabled, 1-CMOS, 2-LVDS + uint8_t warmBootEnable; // Enable WarmBoot - Load initCal cefficients instead of running initCals + uint32_t reserved[1u]; // Reserved for future feature } deviceSysConfig_t; */ static void adrv9001_DeviceSysConfigWrite(adi_adrv9001_Device_t *device, const adi_adrv9001_DeviceSysConfig_t *sysConfig, uint8_t cfgData[], uint32_t *offset) @@ -1611,13 +1607,13 @@ static void adrv9001_DeviceSysConfigWrite(adi_adrv9001_Device_t *device, const a { adrv9001_LoadFourBytes(&tempOffset, cfgData, sysConfig->pllModulus.dmModulus[i]); } - + /* PLL phase sync wait time in us */ adrv9001_LoadTwoBytes(&tempOffset, cfgData, sysConfig->pllPhaseSyncWait_us); cfgData[tempOffset++] = sysConfig->mcsInterfaceType; cfgData[tempOffset++] = sysConfig->warmBootEnable; - + /* 4 bytes padding; Reserved for future use */ tempOffset += 4; @@ -1994,7 +1990,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co uint8_t singleInstruction = 0; uint8_t spiMode = 0; uint8_t spiConfig_A = 0; - + ADI_ENTRY_PTR_ARRAY_EXPECT(device, data, byteCount); ADRV9001_DMAINFO("ARM_MEM_WRITE", armMemAddress, byteCount); @@ -2013,7 +2009,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co /* If Address is not on word boundary, Or ByteCount is not on Word boundary */ if (((armMemAddress & 0x00000003) > 0) || ((byteCount & 0x00000003) > 0)) { - if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || + if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || (ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4 == spiWriteMode)) { ADI_ERROR_REPORT(&device->common, @@ -2057,7 +2053,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co /* setting up the DMA control register for a write */ ADRV9001_SPIWRITEBYTEDMA(device, "ARM_DMA_CTL", ADRV9001_ADDR_ARM_DMA_CTL, regWrite); - + /* Enable single instruction and disable SPI streaming mode by default. * If ADRV9001 SPI streming mode is selected, then single instruction and single instruction are disbled */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x1); @@ -2180,25 +2176,15 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop uint32_t dataIndex = 0; uint32_t spiBufferSize = ((HAL_SPIWRITEARRAY_BUFFERSIZE / 3) - 1); uint8_t spiWriteArrray[HAL_SPIWRITEARRAY_BUFFERSIZE] = { 0 }; - uint32_t ADDR_ARM_DMA_DATA[4] = { ADRV9001_ADDR_ARM_DMA_DATA3, ADRV9001_ADDR_ARM_DMA_DATA2, ADRV9001_ADDR_ARM_DMA_DATA1, ADRV9001_ADDR_ARM_DMA_DATA0 }; - uint32_t index = 0; -#ifndef __KERNEL__ uint8_t addrMsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; uint8_t addrLsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; uint8_t dataArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; -#else - static uint8_t addrMsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; - static uint8_t addrLsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; - static uint8_t dataArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; - - memset(addrMsbArray, 0, sizeof(addrMsbArray)); - memset(addrLsbArray, 0, sizeof(addrLsbArray)); - memset(dataArray, 0, sizeof(dataArray)); -#endif - + uint32_t ADDR_ARM_DMA_DATA[4] = { ADRV9001_ADDR_ARM_DMA_DATA3, ADRV9001_ADDR_ARM_DMA_DATA2, ADRV9001_ADDR_ARM_DMA_DATA1, ADRV9001_ADDR_ARM_DMA_DATA0 }; + uint32_t index = 0; + ADI_ENTRY_PTR_ARRAY_EXPECT(device, numHopTableEntries, numHopTableEntriesByteCount); ADI_ENTRY_PTR_ARRAY_EXPECT(device, hopTableBufferData, hopTableBufferDataByteCount); - + /* Trigger appropriate SPI Interrupt upon table load */ if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) { @@ -2214,7 +2200,7 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop } ADRV9001_DMAINFO("ARM_MEM_WRITE", armMemAddress, byteCount); - + regWrite &= ~ADRV9001_DMA_CTL_RD_WRB; regWrite |= ADRV9001_DMA_CTL_SYS_CODEB; regWrite |= ADRV9001_BF_ENCODE(2, ADRV9001_DMA_CTL_BUS_SIZE_MASK, ADRV9001_DMA_CTL_BUS_SIZE_SHIFT); @@ -2262,7 +2248,7 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop dataArray[addrIndex] = numHopTableEntries[dataIndex]; addrIndex++; } - + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR3 >> 8) & 0x7F)); addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR3; dataArray[addrIndex] = (uint8_t)((hopTableBufferAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR3_BYTE_SHIFT); @@ -2412,7 +2398,7 @@ int32_t adrv9001_DmaMemRead(adi_adrv9001_Device_t *device, uint32_t address, uin returnData[i + 2] = dataRead; ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_1", ADRV9001_ADDR_ARM_DMA_DATA1, &dataRead); returnData[i + 1] = dataRead; - + /* 'single_instruction' has to be cleared before reading DMA_DATA3 and set back after */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x0); ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_0", ADRV9001_ADDR_ARM_DMA_DATA0, &dataRead); @@ -2477,7 +2463,7 @@ int32_t adrv9001_FlexStreamProcessorMemWrite(adi_adrv9001_Device_t *device, /* If Address is not on word boundary, Or ByteCount is not on Word boundary */ if (((flexSpAddress & 0x00000003) > 0) || ((byteCount & 0x00000003) > 0)) { - if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || + if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || (ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4 == spiWriteMode)) { ADI_ERROR_REPORT(&device->common, @@ -2512,7 +2498,7 @@ int32_t adrv9001_FlexStreamProcessorMemWrite(adi_adrv9001_Device_t *device, /* setting up the flex SP DMA control register for a write */ ADRV9001_SPIWRITEBYTEDMA(device, "FLEX_SP_ARM_DMA_CTL", ADRV9001_ADDR_FLEX_SP_ARM_DMA_CTL, regWrite); - + /* Enable single instruction and disable SPI streaming mode by default. * If ADRV9001 SPI streming mode is selected, then single instruction and single instruction are disbled */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x1); @@ -2775,7 +2761,7 @@ static const char* adrv9001_CmdErrMsgGet(uint32_t errCode) { return adrv9001_error_table_CmdError[6]; } - + return NULL; } @@ -2832,7 +2818,7 @@ int32_t adrv9001_ArmCmdErrorHandler(adi_adrv9001_Device_t *device, uint32_t detE ADI_EXPECT(adrv9001_ArmMailBoxErrCodeGet, device, &mailboxErrCode); errorString = adrv9001_CmdErrMsgGet(mailboxErrCode); - + ADI_ERROR_REPORT(&device->common, ADI_ADRV9001_SRC_ARMCMD, mailboxErrCode, @@ -2934,7 +2920,7 @@ static uint32_t adrv9001_ArmProfileWrite_Validate(adi_adrv9001_Device_t *device, ADI_ERROR_RETURN(device->common.error.newAction); } } - + /* Range check parameters in adi_adrv9001_TxSettings_t */ for (i = 0; i < ADI_ADRV9001_MAX_TXCHANNELS; i++) { @@ -2950,7 +2936,7 @@ static uint32_t adrv9001_ArmProfileWrite_Validate(adi_adrv9001_Device_t *device, ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.ssiDataFormatSel, ADI_ADRV9001_SSI_FORMAT_2_BIT_SYMBOL_DATA, ADI_ADRV9001_SSI_FORMAT_22_BIT_I_Q_DATA_1_BIT_GAIN_CHANGE_8_BIT_GAIN_INDEX); ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.numLaneSel, ADI_ADRV9001_SSI_1_LANE, ADI_ADRV9001_SSI_4_LANE); ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.strobeType, ADI_ADRV9001_SSI_SHORT_STROBE, ADI_ADRV9001_SSI_LONG_STROBE); - + if ((ADI_ADRV9001_SSI_TYPE_LVDS == init->tx.txProfile[i].txSsiConfig.ssiType) && (false == init->tx.txProfile[i].txSsiConfig.ddrEn) && (init->tx.txProfile[i].txInterfaceSampleRate_Hz > 30720000)) @@ -3127,7 +3113,7 @@ int32_t adrv9001_ArmProfileWrite(adi_adrv9001_Device_t *device, const adi_adrv90 cfgData[offset++] = (uint8_t)(init->clocks.armPowerSavingClkDiv - 1); cfgData[offset++] = (uint8_t)init->clocks.refClockOutEnable; - + cfgData[offset++] = (uint8_t)init->clocks.auxPllPower; cfgData[offset++] = (uint8_t)init->clocks.clkPllPower; @@ -3186,14 +3172,14 @@ int32_t adrv9001_ArmProfileWrite(adi_adrv9001_Device_t *device, const adi_adrv90 if (ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_TX_PROFILE_VALID)) { armChannels |= (init->tx.txInitChannelMask & (ADI_ADRV9001_TX1 | ADI_ADRV9001_TX2)); - + /* Tx channels must have a valid and enabled ILB channel unless the signaling is Direct FM/FSK */ if(ADRV9001_BF_EQUAL(init->tx.txInitChannelMask, ADI_ADRV9001_TX1) && (init->tx.txProfile[0].outputSignaling != ADI_ADRV9001_TX_DIRECT_FM_FSK)) { armChannels |= (init->rx.rxInitChannelMask & ADI_ADRV9001_ILB1); } - + if (ADRV9001_BF_EQUAL(init->tx.txInitChannelMask, ADI_ADRV9001_TX2) && (init->tx.txProfile[1].outputSignaling != ADI_ADRV9001_TX_DIRECT_FM_FSK)) { @@ -3482,7 +3468,7 @@ int32_t adrv9001_DynamicProfile_Write(adi_adrv9001_Device_t *device, int32_t recoveryAction = ADI_COMMON_ACT_NO_ACTION; uint32_t offset = 0; uint8_t cfgData[ADRV9001_DYNAMIC_PROFILE_BLOB_SIZE] = { 0 }; - + cfgData[offset++] = dynamicProfile->dynamicProfileIndex; cfgData[offset++] = 0; // padding cfgData[offset++] = 0; // padding diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals.h index 7854a717ebf01e..1fc87240cef599 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals.h @@ -278,6 +278,43 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate(adi_adrv9001_Device_t *adrv adi_adrv9000_DynamicProfile_t dynamicProfile[], uint32_t length); + /** + * \brief Read the InitCal coefficients needed for Warmboot + * + * \note Message type: \ref timing_mailbox "Mailbox command" + * + * \pre Channel state is CALIBRATED + * + * \param[in] device Context variable - Pointer to the ADRV9001 device settings data structure + * \param[out] savedCals Coefficients for enabled cals + * \param[in] maskChannel1 Calibration bit mask for channel 1 + * \param[in] maskChannel2 Calibration bit mask for channel 2 + * + * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover + */ + int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Get(adi_adrv9001_Device_t *device, + adi_adrv9001_Warmboot_Coeff_t *savedCals, + uint32_t maskChannel1, + uint32_t maskChannel2); + + /** + * \brief Store the InitCal coefficients needed for Warmboot + * + * \note Message type: \ref timing_mailbox "Mailbox command" + * + * \pre Channel state is STANDBY + * + * \param[in] device Context variable - Pointer to the ADRV9001 device settings data structure + * \param[in] savedCals Coefficients for enabled cals + * \param[in] maskChannel1 Calibration bit mask for channel 1 + * \param[in] maskChannel2 Calibration bit mask for channel 2 + * + * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover + */ + int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Set(adi_adrv9001_Device_t *device, + adi_adrv9001_Warmboot_Coeff_t *savedCals, + uint32_t maskChannel1, + uint32_t maskChannel2); #ifdef __cplusplus } #endif diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals_types.h index ad2ff7cc021af8..d96e247d1eb8cd 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals_types.h @@ -59,22 +59,22 @@ typedef enum adi_adrv9001_InitCalibrations typedef enum adi_adrv9001_TrackingCalibrations { /* SW and HW tracking cals */ - ADI_ADRV9001_TRACKING_CAL_TX_QEC = 0x00000001, //!< Tx Quadrature Error Correction - ADI_ADRV9001_TRACKING_CAL_TX_LO_LEAKAGE = 0x00000002, //!< Tx LO Leakage - ADI_ADRV9001_TRACKING_CAL_TX_LB_PD = 0x00000004, //!< Tx Loopback path delay - ADI_ADRV9001_TRACKING_CAL_TX_PAC = 0x00000008, //!< Tx Power Amplifier Correction - ADI_ADRV9001_TRACKING_CAL_TX_DPD_CLGC = 0x00000010, //!< Tx Digital Pre Distortion and Close Loop Gain Control + ADI_ADRV9001_TRACKING_CAL_TX_QEC = 0x00000001, //!< Tx Quadrature Error Correction + ADI_ADRV9001_TRACKING_CAL_TX_LO_LEAKAGE = 0x00000002, //!< Tx LO Leakage + ADI_ADRV9001_TRACKING_CAL_TX_LB_PD = 0x00000004, //!< Tx Loopback path delay + ADI_ADRV9001_TRACKING_CAL_TX_PAC = 0x00000008, //!< Tx Power Amplifier Correction + ADI_ADRV9001_TRACKING_CAL_TX_DPD_CLGC = 0x00000010, //!< Tx Digital Pre Distortion and Close Loop Gain Control /* Bit 6-7: Not used (Reserved for future purpose) */ - ADI_ADRV9001_TRACKING_CAL_RX_HD2 = 0x00000100, //!< Rx Harmonic Distortion - ADI_ADRV9001_TRACKING_CAL_RX_QEC_WBPOLY = 0x00000200, //!< Rx Quadrature Error Correction Wideband Poly + ADI_ADRV9001_TRACKING_CAL_RX_HD2 = 0x00000100, //!< Rx Harmonic Distortion + ADI_ADRV9001_TRACKING_CAL_RX_QEC_WBPOLY = 0x00000200, //!< Rx Quadrature Error Correction Wideband Poly /* Bit 10-11: Not used (Reserved for future purpose) */ - ADI_ADRV9001_TRACKING_CAL_ORX_QEC_WBPOLY = 0x00001000, //!< ORx Quadrature Error Correction Wideband Poly + ADI_ADRV9001_TRACKING_CAL_ORX_QEC_WBPOLY = 0x00001000, //!< ORx Quadrature Error Correction Wideband Poly /* Bit 13-18: Not used (Reserved for future purpose) */ - ADI_ADRV9001_TRACKING_CAL_RX_BBDC = 0x00080000, //!< Rx Baseband DC rejection - ADI_ADRV9001_TRACKING_CAL_RX_RFDC = 0x00100000, //!< Rx RF DC - ADI_ADRV9001_TRACKING_CAL_RX_QEC_FIC = 0x00200000, //!< Rx Quadrature Error Correction FIC - ADI_ADRV9001_TRACKING_CAL_RX_AGC = 0x00400000, //!< Rx Automatic Gain Control - ADI_ADRV9001_TRACKING_CAL_RX_RSSI = 0x00800000 //!< Rx RSSI + ADI_ADRV9001_TRACKING_CAL_RX_BBDC = 0x00080000, //!< Rx Baseband DC rejection + ADI_ADRV9001_TRACKING_CAL_RX_RFDC = 0x00100000, //!< Rx RF DC + ADI_ADRV9001_TRACKING_CAL_RX_QEC_FIC = 0x00200000, //!< Rx Quadrature Error Correction FIC + ADI_ADRV9001_TRACKING_CAL_RX_GAIN_CONTROL_DETECTORS = 0x00400000, //!< Rx Gain Control Detectors (Power, Analog Peak and Half Band) + ADI_ADRV9001_TRACKING_CAL_RX_RSSI = 0x00800000 //!< Rx RSSI /* Bit 24-31: Not used */ }adi_adrv9001_TrackingCalibrations_e; diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh.h index c01b1500c55a23..37ccb0d39d5668 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh.h @@ -141,19 +141,21 @@ int32_t adi_adrv9001_fh_HopTable_Get(adi_adrv9001_Device_t *adrv9001, /** * \brief Gets hop frame information for specified index * - * Adrv9001 maintains state for three frequency hopping frames; current frame, upcoming frame (frame at next hop edge), - * and next frame (i.e. two hop edges in the future). + * Adrv9001 maintains state for two frequency hopping frames; current frame and upcoming frame (frame at next hop edge) * This command allows to fetch hop frame information, as specified by adi_adrv9001_FhHopFrame_t, from any of these states. + * Rx Offset frequency information is only valid for Rx Channel(s) in the RF_ENABLED state * * \note Message type: \ref timing_mailbox "Mailbox command" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device data structure + * \param[in] fhHopSignal FH Hop Signal to get frame information from, as specified by adi_adrv9001_FhHopSignal_e * \param[in] frameIndex Frame index to get from, as specified by fh_adrv9001_FrameIndexSel_e * \param[out] hopFrame Hop frame info for specified frame index * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, + adi_adrv9001_FhHopSignal_e fhHopSignal, adi_adrv9001_FhFrameIndex_e frameIndex, adi_adrv9001_FhHopFrame_t *hopFrame); @@ -219,6 +221,24 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 int32_t adi_adrv9001_fh_HopTable_BytesPerTable_Get(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhPerDynamicLoad_e numberHopsPerDynamicLoad, uint32_t *bytesPerTable); +/** + * \brief Write the Rx offset frequency to update NCO with subsequent GPIO Pulse + * + * \pre Channel state is RF_ENABLED + * + * \note Message type: \ref timing_direct "Direct register access" + * + * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device data structure + * \param[in] hopSignal Hop signal associated with Rx port of interest + * \param[in] rx1OffsetFrequencyHz Rx1 NCO Update Frequency + * \param[in] rx2OffsetFrequencyHz Rx2 NCO Update Frequency + * + * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover + */ +int32_t adi_adrv9001_fh_RxOffsetFrequency_Set(adi_adrv9001_Device_t *adrv9001, + adi_adrv9001_FhHopSignal_e hopSignal, + int32_t rx1OffsetFrequencyHz, + int32_t rx2OffsetFrequencyHz); #ifdef __cplusplus } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h index a6c5a972371008..3e44ef30f67dee 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h @@ -92,8 +92,8 @@ typedef enum { */ typedef enum { ADI_ADRV9001_FHFRAMEINDEX_CURRENT_FRAME = 0u, /*!< Hop frame currently in progress */ - ADI_ADRV9001_FHFRAMEINDEX_UPCOMING_FRAME = 1u, /*!< The upcoming hop frame after the current*/ - ADI_ADRV9001_FHFRAMEINDEX_NEXT_FRAME = 2u, /*!< Next hop frame after the upcoming one (i.e. next-after-next) */ + ADI_ADRV9001_FHFRAMEINDEX_UPCOMING_FRAME = 1u, /*!< The upcoming hop frame after the current. + Only applicable in LO_MUX, will match CURRENT in LO_RETUNE*/ } adi_adrv9001_FhFrameIndex_e; /** diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h index a3eb3ff0d59b57..22ebc1fde8da60 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h @@ -120,7 +120,7 @@ int32_t adi_adrv9001_gpio_GpIntStatus_Get(adi_adrv9001_Device_t *adrv9001, uint3 * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_OutputPinLevel_Set(adi_adrv9001_Device_t *adrv9001, - adi_adrv9001_GpioPin_e pin, + adi_adrv9001_GpioPin_e pin, adi_adrv9001_GpioPinLevel_e level); /** @@ -158,90 +158,73 @@ int32_t adi_adrv9001_gpio_OutputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin, adi_adrv9001_GpioPinLevel_e *gpioInPinLevels); - -/** - * \brief Reads the ADRV9001 GPIO pin direction for BITBANG mode - * - * This function allows reading the direction of the GPIO - * - * \note Message type: \ref timing_direct "Direct register access" - * - * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure - * \param[in] pin The pin for which to get the direction - * \param[out] direction Current direction of the pin - * - * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover - */ -int32_t adi_adrv9001_gpio_PinDirection_Get(adi_adrv9001_Device_t *device, - adi_adrv9001_GpioPin_e pin, - adi_adrv9001_GpioPinDirection_e *direction); - + /** * \brief Configure specified pin as manual input - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] pin The GPIO pin to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_ManualInput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin); - + /** * \brief Configure specified pin crumb as manual output - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] crumb The GPIO pin crumb to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_ManualOutput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPinCrumbSel_e crumb); /** * \brief Configure specified analog GPIO pin as manual input - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] pin The analog GPIO pin to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin); /** * \brief Configure specified analog GPIO pin nibble as manual output - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] nibble The analog GPIO pin nibble to configure * \param[in] source The source signal to be output on the pins - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioAnalogPinNibbleSel_e nibble); /** - * \brief Sets the configuration for the Front End GPIO + * \brief Configures GPIO pins for ARM functionality * * \note Message type: \ref timing_mailbox "Mailbox command" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device data structure containing settings - * \param[in] gpioCtrlInitCfg GPIO signal configuration + * \param[in] gpioCtrlInitCfg GPIO signal configuration for ARM functionality * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioCtrlInitCfg_t *gpioCtrlInitCfg); - + /** * \brief Configure the ADRV9001 GPIO for the specified signal * @@ -258,7 +241,7 @@ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, int32_t adi_adrv9001_gpio_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioSignal_e signal, adi_adrv9001_GpioCfg_t *gpioConfig); - + /** * \brief Retrieve the ADRV9001 GPIO configuration for the requested signal * diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h index 6a1baf0c3d7194..c9967920c57cd5 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h @@ -197,10 +197,11 @@ typedef enum adi_adrv9001_GpioSignal ADI_ADRV9001_GPIO_SIGNAL_AUX_ADC_3, /*!< Aux ADC control 3 signal */ ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2, /*!< Frequency hopping hop request signal */ - - ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2_TABLE_SELECT = 42, /*!< Frequency hopping table select for HOP 2 */ - - ADI_ADRV9001_GPIO_NUM_SIGNALS = 43, /*!< Total Number of signals from BBIC */ + ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2_TABLE_SELECT, /*!< Frequency hopping table select for HOP 2 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_HOP1_NCO_ASYNC_CHANGE, /*!< Asynchronously change NCO for Hop1 */ + ADI_ADRV9001_GPIO_SIGNAL_FH_HOP2_NCO_ASYNC_CHANGE, /*!< Asynchronously change NCO for Hop2 */ + + ADI_ADRV9001_GPIO_NUM_SIGNALS = 46, /*!< Total Number of signals from BBIC*/ } adi_adrv9001_GpioSignal_e; /** @@ -250,10 +251,10 @@ typedef struct adi_adrv9001_GpioCtrlInitCfg adi_adrv9001_GpioCfg_t ext_pll_chip_enable[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) External PLL Chip Enables */ adi_adrv9001_GpioCfg_t vco_chip_enable[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) Rx VCO Chip Enables */ adi_adrv9001_GpioCfg_t ext_pll_lock[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) External PLL locks */ - adi_adrv9001_GpioCfg_t channelPowerSaving[ADI_ADRV9001_NUM_CHANNELS]; /*!< (DGPIO) Channel Power Saving Enables */ adi_adrv9001_GpioCfg_t systemPowerSavingAndMonitorEnable; /*!< (DGPIO) System Power Saving and Monitor Enable */ adi_adrv9001_GpioCfg_t systemPowerSavingAndMonitorWakeUp; /*!< (DGPIO) Monitor WakeUp */ + adi_adrv9001_GpioCfg_t fh_update_rx_nco[ADI_ADRV9001_NUM_CHANNELS]; /*!< (DGPIO) Trigger Update of Rx NCO in Frequency Hop Frame */ } adi_adrv9001_GpioCtrlInitCfg_t; diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_gaincontrol.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_gaincontrol.h index 934ea0fc2a5186..00943d2e1a318d 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_gaincontrol.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_gaincontrol.h @@ -61,7 +61,7 @@ int32_t adi_adrv9001_Rx_GainControl_Mode_Get(adi_adrv9001_Device_t *adrv9001, /** * \brief Configure Automatic Gain Control (AGC) for the specified Rx channel * - * \pre This function may be called any time after device initialization + * \pre Channel state is any of CALIBRATED, PRIMED, or RF_ENABLED * * \note This function does NOT enable AGC mode. Call adi_adrv9001_Rx_GainCtrlMode_Set() afterwards * \note Message type: \ref timing_direct "Direct register acccess" @@ -81,7 +81,7 @@ int32_t adi_adrv9001_Rx_GainControl_Configure(adi_adrv9001_Device_t *adrv9001, * * \note Message type: \ref timing_direct "Direct register acccess" * - * \pre This function may be used only if AGC is active + * \pre Channel state is any of CALIBRATED, PRIMED, or RF_ENABLED * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device data structure * \param[in] channel The Rx Channel for which to configure AGC diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_gaincontrol_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_gaincontrol_types.h index e38e85c0b05d4f..0c8dd9b951597d 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_gaincontrol_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_gaincontrol_types.h @@ -143,6 +143,8 @@ typedef struct adi_adrv9001_GainControlCfg adi_adrv9001_PowerDetector_t power; adi_adrv9001_PeakDetector_t peak; adi_adrv9001_ExtLna_t extLna; + bool rxQecFreezeEnable; /*!< RXQEC Freeze Enable/Disable, only applies in AGC mode*/ + adi_adrv9001_GpioPin_e gpioFreezePin; /*!< GPIO pin to activate to freeze AGC - set to 0/UNASSIGNED if unused */ } adi_adrv9001_GainControlCfg_t; typedef struct adi_adrv9001_RxGainControlPinCfg diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h index d780384ff4c2ae..9c3262f5c126a7 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h @@ -178,26 +178,13 @@ typedef struct adi_adrv9001_RxPortSwitchCfg bool manualRxPortSwitch; } adi_adrv9001_RxPortSwitchCfg_t; -/** - * \brief Supported LOID intervals - */ -typedef enum adi_adrv9001_LoidInterval -{ - ADI_ADRV9001_LOIDINTERVAL_RFDCINTERVAL_DIV_2 = 0, /* 1/2 rfdc estimation interval */ - ADI_ADRV9001_LOIDINTERVAL_RFDCINTERVAL_DIV_4 = 1, /* 1/4 rfdc estimation interval */ - ADI_ADRV9001_LOIDINTERVAL_RFDCINTERVAL_DIV_8 = 2, /* 1/8 rfdc estimation interval */ - ADI_ADRV9001_LOIDINTERVAL_RFDCINTERVAL_DIV_16 = 3 /* 1/16 rfdc estimation interval */ -} adi_adrv9001_LoidInterval_e; - /** * \brief Structure which holds the LOID configuration parameters */ typedef struct adi_adrv9001_RxrfdcLoidCfg { bool loidEnable; /* LOID enable flag for RX1 and RX2 */ - adi_adrv9001_LoidInterval_e loidInterval; /* Estimation interval */ - uint8_t loidThLow; /* Lower threshold for LO detection (in -dB) */ - uint8_t loidThHigh; /* Upper threshold for LO detection (in -dB) */ + uint8_t loidThreshold_negdBFS; /* Threshold for LO detection (in -dBFS) */ } adi_adrv9001_RxrfdcLoidCfg_t ; #ifdef __cplusplus diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi_types.h index d284d0d9a7c758..08beba259ad224 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_spi_types.h @@ -75,16 +75,16 @@ typedef enum typedef enum { - ADI_ADRV9001_SPI_MASTER_CS_ASSERTION_PER_BYTE = 0u, /* CS is asserted per byte */ - ADI_ADRV9001_SPI_MASTER_CS_ASSERTION_CONTINUOUS = 1u /* CS is asserted for the entire transactionBytes duration */ -} adi_adrv9001_spiMasterAssertionMode_e; + ADI_ADRV9001_SPI_MASTER_CS_TRANSFER_TRANSACTION_BYTES = 0u, /* CS assert for transactionBytes and only sends transactionBytes bytes */ + ADI_ADRV9001_SPI_MASTER_CS_TRANSFER_NUM_BYTES = 1u /* CS assert for numBytes and send all numBytes */ +} adi_adrv9001_spiMasterTransferMode_e; typedef struct { uint8_t numBytes; /* Number of bytes to write. Valid range is 1 - 30 */ uint8_t baudRateDiv; /* SPI baudRate = DEV_CLK_IN / baudRateDiv; Valid range is 0 - 31 */ uint8_t transactionBytes; /* Number of bytes per CS assertion.Valid range is 1 - 30 */ - adi_adrv9001_spiMasterAssertionMode_e assertionMode; /* CS assert/deassert during frame duration */ + adi_adrv9001_spiMasterTransferMode_e transferMode; /* CS transfer during frame duration */ adi_adrv9001_spiMasterSlaveDevices_e spiSlaveDevicesConnected; /* Single or multiple(only in future) SPI slaves connected with ADRV9001 */ adi_adrv9001_spiMasterSource_e csSource; /* GPIO type for all SPI pins: Analog or Digital */ adi_adrv9001_GpioPin_e pin; /* CS pin - Other SPI signals have dedicated pins: Pin9 = SPI_CLK, diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx.h index d396e39de6a3fc..32a6f03cb188c2 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_tx.h @@ -110,7 +110,9 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Get(adi_adrv9001_Device_t *adrv9001, * channel state must be any of STANDBY, CALIBRATED, PRIMED. * \pre If attenuation mode is ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI: * channel state must be any of STANDBY, CALIBRATED, PRIMED, RF_ENABLED - * \pre Attenuation mode is not ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC + * \pre Attenuation mode is ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC + * channel state must be any of STANDBY, CALIBRATED, PRIMED, RF_ENABLED + * clgcLoopOpen must be 0 * * \note Message type: \ref timing_direct "Direct register acccess" * \note The new attenuation only takes effect in the RF_ENABLED state - may read back incorrect value otherwise diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h index 00069de3335c1b..f258e8e701d8ea 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h @@ -37,6 +37,8 @@ /* TODO: Determine a reasonable value */ #define ADI_ADRV9001_READY_FOR_MCS_DELAY_US 100U +#define ADI_ADRV9001_WB_MAX_NUM_ENTRY 16384 +#define ADI_ADRV9001_WB_MAX_NUM_COEFF 6000 /** * \brief ADRV9001 part number @@ -178,6 +180,14 @@ typedef struct adi_adrv9001_SiliconVersion uint8_t minor; /*!< Minor silicon version */ } adi_adrv9001_SiliconVersion_t; +/** + * \brief WarmBoot InitCals Coefficients + */ +typedef struct adi_adrv9001_Warmboot_Coeff +{ + uint8_t calValue[ADI_ADRV9001_WB_MAX_NUM_ENTRY][ADI_ADRV9001_WB_MAX_NUM_COEFF]; +} adi_adrv9001_Warmboot_Coeff_t; + #ifndef CLIENT_IGNORE /** * \brief Data structure to hold a ADRV9001 device instance status information @@ -227,6 +237,7 @@ typedef struct adi_adrv9001_Info uint8_t frequencyHoppingEnabled; /*!< Frequency hopping enabled flag from currently loaded profile */ adi_adrv9001_RxGainTableType_e gainTableType[ADI_ADRV9001_MAX_RX_ONLY]; /*!< type of gain table loaded during ADRV9001 initialization */ uint8_t txAttenMode[ADI_ADRV9001_MAX_TXCHANNELS]; /* TX Attenuation Mode*/ + uint32_t chProfEnMask[ADI_ADRV9001_MAX_NUM_CHANNELS]; /* Mask for enabled channels and profiles in FW format - used for warmboot*/ } adi_adrv9001_Info_t; /** diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h index b00fd996a5dc58..613a4c78676c82 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h @@ -19,7 +19,7 @@ extern "C" { #endif /* Auto-generated version number - DO NOT MANUALLY EDIT */ -#define ADI_ADRV9001_CURRENT_VERSION "48.42.0" +#define ADI_ADRV9001_CURRENT_VERSION "48.49.2" #ifdef __cplusplus } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adrv9001_Init_t_parser.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adrv9001_Init_t_parser.h index 9e741c2525e78f..47764399e35324 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adrv9001_Init_t_parser.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adrv9001_Init_t_parser.h @@ -1,6 +1,6 @@ /* Auto-generated file - DO NOT MANUALLY EDIT */ -/* Filename: A:\profile-types\include\adrv9001_Init_t_parser.h */ -/* Created on: 10/29/2021 1:22:26 PM */ +/* Filename: C:\Jenkins\workspace\vice-driver_profile-types_master\include\adrv9001_Init_t_parser.h */ +/* Created on: 1/26/2022 1:23:20 PM */ /** * Contains auto-generated C macros for loading fields from a JSON file @@ -9,7 +9,7 @@ */ /** - * Copyright 2021 Analog Devices Inc. + * Copyright 2022 Analog Devices Inc. */ #include "adi_pmag_macros.h" diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c index ad60b17eb0e92f..45e4953265aef9 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c @@ -24,6 +24,7 @@ #include "adi_adrv9001_gpio.h" #include "adi_adrv9001_spi.h" #include "adi_adrv9001_radio.h" +#include "adi_adrv9001_rx.h" #include "adi_adrv9001_mcs.h" #include "adi_adrv9001_cals.h" #include "adi_adrv9001_fh.h" @@ -1150,6 +1151,11 @@ int32_t adi_adrv9001_arm_System_Program(adi_adrv9001_Device_t *device, uint8_t c uint8_t extData[2] = { 0 }; uint8_t cmdStatusByte = 0; int32_t recoveryAction = ADI_COMMON_ACT_NO_ACTION; + int orxFlgShift = 3; //ORX flag shift from FW bit position, lsb bit 1, to API bit position ADRV9001_ORX1 + int ilbFlgShift = 4; //ILB flag shift from FW bit position, lsb bit 2, to API bit position ADRV9001_ILB1 + int elbFlgShift = 5; //ELB flag shift from FW bit position, lsb bit 3, to API bit position ADRV9001_ELB1 + int txFlgShiftUp = 3; // TX enable flag, lsb bit 5 + int adcPortBFlg = 64; // ADC port B enable flag, lsb bit 6 /* Check device pointer is not null */ ADI_ENTRY_EXPECT(device); @@ -1178,6 +1184,29 @@ int32_t adi_adrv9001_arm_System_Program(adi_adrv9001_Device_t *device, uint8_t c } } + adi_adrv9001_RxPortSwitchCfg_t portSwitchCfg = { 0 }; + ADI_EXPECT(adi_adrv9001_Rx_PortSwitch_Inspect, device, &portSwitchCfg); + + /*Mask for Channel 1 */ + device->devStateInfo.chProfEnMask[0] = ((device->devStateInfo.initializedChannels & ADI_ADRV9001_RX1) | + ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ORX1) >> (orxFlgShift)) | + ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ILB1) >> (ilbFlgShift)) | + ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ELB1) >> (elbFlgShift)) | + ((device->devStateInfo.initializedChannels & ADI_ADRV9001_TX1) << (txFlgShiftUp))); + + /*Mask for Channel 2 */ + device->devStateInfo.chProfEnMask[1] = (((device->devStateInfo.initializedChannels & ADI_ADRV9001_RX2) >> 1) | + ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ORX2) >> (orxFlgShift + 1)) | + ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ILB2) >> (ilbFlgShift + 1)) | + ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ELB2) >> (elbFlgShift + 1)) | + ((device->devStateInfo.initializedChannels & ADI_ADRV9001_TX2) << (txFlgShiftUp - 1))); + + if (portSwitchCfg.enable == true) + { + device->devStateInfo.chProfEnMask[0] = device->devStateInfo.chProfEnMask[0] | adcPortBFlg; + device->devStateInfo.chProfEnMask[1] = device->devStateInfo.chProfEnMask[1] | adcPortBFlg; + } + ADI_API_RETURN(device); } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c index a0705688608c8d..a9c98a5cc56eb6 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c @@ -774,3 +774,85 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate(adi_adrv9001_Device_t *adrv ADI_API_RETURN(adrv9001); } + +int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Get(adi_adrv9001_Device_t *device, + adi_adrv9001_Warmboot_Coeff_t *savedCals, + uint32_t maskChannel1, + uint32_t maskChannel2) +{ + uint32_t tblSize[4]; + uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY] = { 0 }; + uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; + int calNo; + + ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); + ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0]*16, 1); + + for (calNo = 0; calNo < tblSize[0]; calNo++) + { + uint32_t addr = vecTbl[4*calNo]; + uint32_t size = vecTbl[(4*calNo) + 1]; + uint32_t initMask = vecTbl[(4*calNo) + 2]; + uint32_t profMask = vecTbl[(4*calNo) + 3]; + adi_common_ChannelNumber_e channel; + for (channel = ADI_CHANNEL_1; channel <= ADI_CHANNEL_2; channel++) + { + uint32_t chInitMask = maskChannel1; + profMask = profMask >> (8 * (channel - 1)); + if (profMask == 0) + continue; + if (((initMask & chInitMask) != 0) && ((profMask & device->devStateInfo.chProfEnMask[channel - 1]) != 0)) + { + ADI_EXPECT(adi_adrv9001_arm_Memory_Read, device, addr, calVal, size, 0); + int calSize; + for (calSize = 0; calSize < size; calSize++) + { + savedCals->calValue[calNo][calSize] = calVal[calSize]; + } + } + } + } + + ADI_API_RETURN(device); +} + +int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Set(adi_adrv9001_Device_t *device, + adi_adrv9001_Warmboot_Coeff_t *savedCals, + uint32_t maskChannel1, + uint32_t maskChannel2) +{ + uint32_t tblSize[4]; + uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY] = { 0 }; + uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; + int calNo; + + ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); + ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0]*16, 1); + + for (calNo = 0; calNo < tblSize[0]; calNo++) + { + uint32_t addr = vecTbl[4*calNo]; + uint32_t size = vecTbl[(4*calNo) + 1]; + uint32_t initMask = vecTbl[(4*calNo) + 2]; + uint32_t profMask = vecTbl[(4*calNo) + 3]; + adi_common_ChannelNumber_e channel; + for (channel = ADI_CHANNEL_1; channel <= ADI_CHANNEL_2; channel++) + { + uint32_t chInitMask = maskChannel1; + profMask = profMask >> (8 * (channel - 1)); + if (profMask == 0) + continue; + if (((initMask & chInitMask) != 0) && ((profMask & device->devStateInfo.chProfEnMask[channel - 1]) != 0)) + { + int calSize; + for (calSize = 0; calSize < size; calSize++) + { + calVal[calSize] = savedCals->calValue[calNo][calSize]; + } + ADI_EXPECT(adi_adrv9001_arm_Memory_Write, device, addr, calVal, size, 0); + } + } + } + + ADI_API_RETURN(device); +} \ No newline at end of file diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c index e92b41cbe5dc32..43bd89095b9ee3 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c @@ -75,7 +75,6 @@ int32_t adi_adrv9001_dpd_Initial_Configure(adi_adrv9001_Device_t *adrv9001, uint8_t armData[27] = { 0 }; uint8_t extData[5] = { 0 }; uint32_t offset = 0; - adi_adrv9001_DpdCfg_t dpdClgcRead = { 0 }; ADI_PERFORM_VALIDATION(adi_adrv9001_dpd_Initial_Configure_Validate, adrv9001, channel, dpdConfig); @@ -98,8 +97,7 @@ int32_t adi_adrv9001_dpd_Initial_Configure(adi_adrv9001_Device_t *adrv9001, ADI_EXPECT(adi_adrv9001_arm_Config_Write, adrv9001, armData, sizeof(armData), extData, sizeof(extData)) - ADI_EXPECT(adi_adrv9001_dpd_Inspect, adrv9001, channel, &dpdClgcRead) - if (dpdConfig->clgcEnable != 0 && dpdClgcRead.clgcLoopOpen == 0) + if (dpdConfig->clgcEnable != 0) { ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Set, adrv9001, channel, ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) } @@ -176,8 +174,6 @@ int32_t adi_adrv9001_dpd_Configure(adi_adrv9001_Device_t *adrv9001, uint8_t extData[5] = { 0 }; uint32_t offset = 0; - adi_adrv9001_DpdInitCfg_t dpdClgcRead = { 0 }; - ADI_PERFORM_VALIDATION(adi_adrv9001_dpd_Configure_Validate, adrv9001, channel, dpdConfig); adrv9001_LoadFourBytes(&offset, armData, sizeof(armData) - sizeof(uint32_t)); @@ -210,12 +206,6 @@ int32_t adi_adrv9001_dpd_Configure(adi_adrv9001_Device_t *adrv9001, extData[2] = OBJID_TC_TX_DPD; ADI_EXPECT(adi_adrv9001_arm_Config_Write, adrv9001, armData, sizeof(armData), extData, sizeof(extData)) - - ADI_EXPECT(adi_adrv9001_dpd_Initial_Inspect, adrv9001, channel, &dpdClgcRead) - if (dpdClgcRead.clgcEnable != 0 && dpdConfig->clgcLoopOpen == 0) - { - ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Set, adrv9001, channel, ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) - } ADI_API_RETURN(adrv9001); } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c index 83a1f24be56a51..cb29a00a65a043 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c @@ -44,6 +44,8 @@ FREQ_HOPPING_CONFIGURATION_NUM_BYTES) #define FREQ_HOPPING_MAX_NUM_BYTES 1536u #define FREQ_HOPPING_HOP_TABLE_PARTITION_ADDR_OFFSET 16u +#define FREQ_HOPPING_HOP1_OFFSET_FREQ_OVERWRITE_ADDR 0x2001FFF0 +#define FREQ_HOPPING_HOP2_OFFSET_FREQ_OVERWRITE_ADDR 0x2001FFF8 #define ADI_FH_CHECK_FH_ENABLED(device) \ if (device->devStateInfo.frequencyHoppingEnabled == 0) \ @@ -57,7 +59,7 @@ if (device->devStateInfo.frequencyHoppingEnabled == 0) \ ADI_API_RETURN(device); \ } -/* TODO JP: Determine if we need to validate the whole table. +/* TODO JP: Determine if we need to validate the whole table. It's difficult to validate the hop table due to the following: 1) At the time of receiving the HOP table, we don't know the channel sequence. So a tx or rx gain index might be valid, or it might be a 'don't care' value, programmed by the user. We could potentially enforce the @@ -65,7 +67,7 @@ if (device->devStateInfo.frequencyHoppingEnabled == 0) \ 2) There doesn't seem a nice way to validate the rx gain in API, since there is no state of the FH operating gain range. The best we could do would be to ensure its within the absolute min/max. However, this could be effected by point 1. - 3) Validating the whole table before its written to ARM might be valuable, however, it might + 3) Validating the whole table before its written to ARM might be valuable, however, it might also waste time. Especially considering we can't validate every field in the table. It might be better for ARM to validate it once received, or on the fly. */ @@ -75,8 +77,8 @@ static __maybe_unused int32_t adi_adrv9001_fh_FrameInfo_Validate(adi_adrv9001_De /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); - ADI_RANGE_CHECK_X(adrv9001, hopFrame->hopFrequencyHz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, hopFrame->hopFrequencyHz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); ADI_API_RETURN(adrv9001); } @@ -95,11 +97,11 @@ static uint32_t adi_adrv9001_fh_GetHopTableBufferAddress(adi_adrv9001_Device_t * adrv9001_ParseFourBytes(&offset, hopTableBufferAddressBlock, &hopTableBufferAddress); return hopTableBufferAddress; -} +} static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) -{ +{ uint32_t i; uint32_t j; uint8_t numHopSignals; @@ -139,7 +141,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } /* Can be unassigned but throw an error if it's set to analog*/ ADI_RANGE_CHECK(adrv9001, fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[0].pin, ADI_ADRV9001_GPIO_UNASSIGNED, ADI_ADRV9001_GPIO_DIGITAL_15); - if ((fhConfig->hopTableSelectConfig.hopTableSelectMode == ADI_ADRV9001_FHHOPTABLESELECTMODE_INDEPENDENT) + if ((fhConfig->hopTableSelectConfig.hopTableSelectMode == ADI_ADRV9001_FHHOPTABLESELECTMODE_INDEPENDENT) && (fhConfig->mode == ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP)) { /* Can be unassigned but throw an error if it's set to analog*/ @@ -184,18 +186,18 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De "Value must be non-zero in Tx only operation"); ADI_API_RETURN(adrv9001); } - + /* Check mode*/ ADI_RANGE_CHECK(adrv9001, fhConfig->mode, ADI_ADRV9001_FHMODE_LO_MUX_PREPROCESS, ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP); /* Check tableIndexCtrl_e */ ADI_RANGE_CHECK(adrv9001, fhConfig->tableIndexCtrl, ADI_ADRV9001_TABLEINDEXCTRL_AUTO_LOOP, ADI_ADRV9001_TABLEINDEXCTRL_GPIO); /* Check operating frequency range */ - ADI_RANGE_CHECK_X(adrv9001, fhConfig->minOperatingFrequency_Hz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, fhConfig->minOperatingFrequency_Hz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); - ADI_RANGE_CHECK_X(adrv9001, fhConfig->maxOperatingFrequency_Hz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, fhConfig->maxOperatingFrequency_Hz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); if (fhConfig->minOperatingFrequency_Hz >= fhConfig->maxOperatingFrequency_Hz) @@ -209,12 +211,12 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De ADI_API_RETURN(adrv9001); } /* Check RX gain ranges */ - ADI_RANGE_CHECK(adrv9001, fhConfig->minRxGainIndex, - ADI_ADRV9001_RX_GAIN_INDEX_MIN, + ADI_RANGE_CHECK(adrv9001, fhConfig->minRxGainIndex, + ADI_ADRV9001_RX_GAIN_INDEX_MIN, fhConfig->maxRxGainIndex); /* Max index can be equal to min and no greater than rx1MaxGainIndex */ - ADI_RANGE_CHECK(adrv9001, fhConfig->maxRxGainIndex, - fhConfig->minRxGainIndex, + ADI_RANGE_CHECK(adrv9001, fhConfig->maxRxGainIndex, + fhConfig->minRxGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); /* TODO JP: Investigate requirements for TX attenuation in diversity mode. Will min/max be the same, or will we need a seperate field? @@ -243,7 +245,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } /* Check frequency select pins */ - if (ADI_ADRV9001_TABLEINDEXCTRL_GPIO == fhConfig->tableIndexCtrl) + if (ADI_ADRV9001_TABLEINDEXCTRL_GPIO == fhConfig->tableIndexCtrl) { ADI_RANGE_CHECK(adrv9001, fhConfig->numTableIndexPins, 1u, ADI_ADRV9001_FH_MAX_NUM_FREQ_SELECT_PINS); for (i = 0; i < fhConfig->numTableIndexPins; i++) @@ -252,13 +254,13 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } } /* Configure gain select pins */ - if (true == fhConfig->gainSetupByPin) + if (true == fhConfig->gainSetupByPin) { for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) { if ((initializedChannelMask & (j == 0? channel1Mask:channel2Mask)) != 0x00u) { - + ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].numGainCtrlPins, 1u, ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_PINS); for (i = 0; i < fhConfig->gainSetupByPinConfig[j].numGainCtrlPins; i++) { @@ -267,7 +269,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De maxPossibleGainEntries = (1u << fhConfig->gainSetupByPinConfig[j].numGainCtrlPins); } - + if (ADRV9001_BF_EQUAL(adrv9001->devStateInfo.initializedChannels, CHANNELS[ADI_RX][j])) { /* Validate Rx gain table is within range specified by fhConfig */ @@ -285,7 +287,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De { ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].txAttenTable[i], fhConfig->minTxAtten_mdB, fhConfig->maxTxAtten_mdB); } - } + } } } @@ -294,7 +296,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De static __maybe_unused int32_t adi_adrv9001_fh_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) -{ +{ /* Check for NULL pointer */ ADI_NULL_PTR_RETURN(&adrv9001->common, fhConfig); ADI_API_RETURN(adrv9001); @@ -303,15 +305,12 @@ static __maybe_unused int32_t adi_adrv9001_fh_Inspect_Validate(adi_adrv9001_Devi static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhMode_e mode, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t tableSize) { - uint32_t frequencyIndex = 0; + uint32_t frequencyIndex = 0; uint32_t tempAddress = 0; - uint8_t maxNumHopFrequencies = (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) ? ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE : - (ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE) / 2; - if (tableId == ADI_ADRV9001_FHHOPTABLE_A) { if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) @@ -334,7 +333,8 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate tempAddress = adrv9001->devStateInfo.fhHopTableB2Addr; } } - + uint8_t maxNumHopFrequencies = (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) ? ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE : + (ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE) / 2; /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); /* Check for NULL pointer */ @@ -354,7 +354,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate ADI_API_RETURN(adrv9001); } - if ((hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_2) + if ((hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_2) && (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP)) { ADI_ERROR_REPORT(&adrv9001->common, @@ -366,7 +366,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate ADI_API_RETURN(adrv9001); } - + /* Check fhHopTable->numHopFrames are valid */ ADI_RANGE_CHECK(adrv9001, tableSize, 1u, maxNumHopFrequencies); @@ -376,7 +376,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate } ADI_API_RETURN(adrv9001); -} +} static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal, @@ -428,7 +428,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Inspect_Validate(adi_adrv } ADI_API_RETURN(adrv9001); -} +} int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) @@ -474,7 +474,7 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, armData[offset++] = fhConfig->tableIndexCtrl; armData[offset++] = fhConfig->gainSetupByPin; armData[offset++] = fhConfig->hopTableSelectConfig.hopTableSelectMode; - + armData[offset++] = hop1SignalsPortMask; armData[offset++] = hop2SignalsPortMask; @@ -493,14 +493,14 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, armData[offset++] = fhConfig->rxZeroIfEnable; offset += 2u; /* padding */ /* If in gain select by pin mode, load Rx gain and Tx attenuation tables */ - if (fhConfig->gainSetupByPin == true) + if (fhConfig->gainSetupByPin == true) { /* Load Rx gain and Tx atten table */ armData[offset++] = fhConfig->gainSetupByPinConfig[0].numRxGainTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[1].numRxGainTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[0].numTxAttenTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[1].numTxAttenTableEntries; - /* Create a second offset variable to point to the Tx atten table location. + /* Create a second offset variable to point to the Tx atten table location. Rx gain index is 1 byte, so second offset is offset + (ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES * 1) */ tempOffset = offset + 2 * ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; @@ -575,7 +575,7 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, } } /* Configure gain index pins if selected */ - if (fhConfig->gainSetupByPin == true) + if (fhConfig->gainSetupByPin == true) { /* Configure ADRV9001 GPIOs */ for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) @@ -634,7 +634,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a fhConfig->tableIndexCtrl = armData[offset++]; fhConfig->gainSetupByPin = armData[offset++]; fhConfig->hopTableSelectConfig.hopTableSelectMode = armData[offset++]; - + hop1SignalsPortMask = armData[offset++]; offset++; fhConfig->rxPortHopSignals[0] = ((hop1SignalsPortMask & 0x1) == 1) ? ADI_ADRV9001_FH_HOP_SIGNAL_1 : ADI_ADRV9001_FH_HOP_SIGNAL_2; @@ -664,7 +664,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a { fhConfig->gainSetupByPinConfig[j].numTxAttenTableEntries = armData[offset++]; } - + tempOffset = offset + 2 * ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; /* Rx and Tx tables */ for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) @@ -701,13 +701,13 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP, &(fhConfig->hopSignalGpioConfig[0])); ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_TABLE_SELECT, &(fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[0])); - + if (fhConfig->mode == ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) { ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2, &(fhConfig->hopSignalGpioConfig[1])); ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2_TABLE_SELECT, &(fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[1])); } - + /* Inspect table index pins if selected */ if (fhConfig->tableIndexCtrl == ADI_ADRV9001_TABLEINDEXCTRL_GPIO) { @@ -730,7 +730,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhMode_e mode, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t hopTableSize) { @@ -740,7 +740,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 uint32_t frequencyIndex = 0; uint8_t numHopTableEntries[4u]; uint32_t hopTableBufferAddress = 0; - + /* ARM Data is written directly to ARM memory because FREQ_HOPPING_NUM_BYTES is greater than set buffer size */ #ifndef __KERNEL__ uint8_t armData[FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; @@ -778,8 +778,8 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 hopTableAddress = adrv9001->devStateInfo.fhHopTableB2Addr; hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB2Addr; } - } - + } + adrv9001_LoadFourBytes(&offset, numHopTableEntries, hopTableSize); offset = 0; for (frequencyIndex = 0; frequencyIndex < hopTableSize; frequencyIndex++) @@ -794,7 +794,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 armData[offset++] = hopTable[frequencyIndex].tx1Attenuation_fifthdB; armData[offset++] = hopTable[frequencyIndex].tx2Attenuation_fifthdB; } - + /* Write the data directly to the ARM memory */ /* 'offset' is used to represent the exact number of bytes to write to avoid writing over the entire table */ ADI_EXPECT(adi_adrv9001_arm_Memory_WriteFH, adrv9001, hopSignal, tableId, hopTableAddress, numHopTableEntries, sizeof(numHopTableEntries), hopTableBufferAddress, armData, offset); @@ -803,7 +803,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t hopTableSize, uint32_t *numHopFramesRead) @@ -830,7 +830,7 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, memset(&armData, 0, sizeof(armData)); #endif - + if (tableId == ADI_ADRV9001_FHHOPTABLE_A) { if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) @@ -856,10 +856,10 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, hopTableAddress = adrv9001->devStateInfo.fhHopTableB2Addr; hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB2Addr; } - } + } ADI_PERFORM_VALIDATION(adi_adrv9001_fh_HopTable_Inspect_Validate, adrv9001, hopSignal, tableId, hopTable, hopTableSize); - /* Even though we are going to read directly from ARM memory, we can still use the GET protocol to + /* Even though we are going to read directly from ARM memory, we can still use the GET protocol to tell ARM how many bytes we will read. ARM will return an error if the read size is invalid */ adrv9001_LoadFourBytes(&offset, armData, sizeof(armData)); @@ -875,7 +875,7 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, OBJID_GO_GET_FH_HOP_TABLE, ADI_ADRV9001_DEFAULT_TIMEOUT_US, ADI_ADRV9001_DEFAULT_INTERVAL_US); - + /* First read number of frequencies in hop table */ offset = 0; ADI_EXPECT(adi_adrv9001_arm_Memory_Read, adrv9001, hopTableAddress, numHopFrequenciesReadbackBlock, sizeof(numHopFrequenciesReadbackBlock), false); @@ -977,11 +977,12 @@ int32_t adi_adrv9001_fh_HopTable_Get(adi_adrv9001_Device_t *adrv9001, ADI_API_RETURN(adrv9001); } -int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, + adi_adrv9001_FhHopSignal_e fhHopSignal, adi_adrv9001_FhFrameIndex_e frameIndex, adi_adrv9001_FhHopFrame_t *hopFrame) { - uint8_t armData[16u] = { 0 }; + uint8_t armData[sizeof(adrv9001_FhHopFrame_t)] = { 0 }; uint8_t extData[5u] = { 0 }; uint32_t offset = 0; uint32_t hopFrequencyHz_LSB = 0; @@ -990,8 +991,10 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); ADI_NULL_PTR_RETURN(&adrv9001->common, hopFrame); - ADI_RANGE_CHECK(adrv9001, frameIndex, ADI_ADRV9001_FHFRAMEINDEX_CURRENT_FRAME, ADI_ADRV9001_FHFRAMEINDEX_NEXT_FRAME); - + ADI_RANGE_CHECK(adrv9001, fhHopSignal, ADI_ADRV9001_FH_HOP_SIGNAL_1, ADI_ADRV9001_FH_HOP_SIGNAL_2); + ADI_RANGE_CHECK(adrv9001, frameIndex, ADI_ADRV9001_FHFRAMEINDEX_CURRENT_FRAME, ADI_ADRV9001_FHFRAMEINDEX_UPCOMING_FRAME); + + /* Write the size to the GET buffer */ adrv9001_LoadFourBytes(&offset, armData, sizeof(armData)); ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_GET, armData, sizeof(uint32_t), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); @@ -1000,6 +1003,7 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, extData[0] = 0; /* Channel Mask; unused for this command */ extData[1] = OBJID_GO_GET_FREQ_HOP_FRAME_INFO; extData[2] = frameIndex; + extData[3] = fhHopSignal; ADI_EXPECT(adi_adrv9001_arm_Cmd_Write, adrv9001, ADRV9001_ARM_GET_OPCODE, extData, sizeof(extData)); /* check the command status for timeout */ @@ -1023,9 +1027,9 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, hopFrame->tx1Attenuation_fifthdB = armData[offset++]; hopFrame->tx2Attenuation_fifthdB = armData[offset++]; ADI_API_RETURN(adrv9001); -} +} -int32_t adi_adrv9001_fh_Hop(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_fh_Hop(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal) { /* Flip the hop signal */ @@ -1062,7 +1066,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_NumberOfHops_Get(adi_adrv9001_Devi default: ADI_SHOULD_NOT_EXECUTE(adrv9001); } - + ADI_API_RETURN(adrv9001); } @@ -1094,7 +1098,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure_Validat mode, "FH mode must be dual hop for hopSignal to be HOP_2 "); } - + } ADI_ENTRY_PTR_EXPECT(adrv9001, spiPackedFhTable); @@ -1122,7 +1126,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure_Validat ADI_COMMON_ACT_ERR_CHECK_PARAM, tableSize, "spiPackedFhTable[] size is not sufficient "); - + } for (frequencyIndex = 0; frequencyIndex < tableSize; frequencyIndex++) { @@ -1199,7 +1203,7 @@ static uint32_t adrv9001_HopTable_Spi_Pack(adi_adrv9001_Device_t *adrv9001, /* Issue SW interrupt 4 or 11 to load FH table A or B. The SPI reg is self-cleared so there is no need to do read/mod/write. */ adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADRV9001_ADDR_SW_INTERRUPT_4, bitmSwInt, ADRV9001_SPI_WRITE_POLARITY); - + /* Restore back the original values of ADRV9001 DMA control register */ adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADRV9001_ADDR_ARM_DMA_CTL, regVal, ADRV9001_SPI_WRITE_POLARITY); @@ -1239,10 +1243,10 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 if (ADI_ADRV9001_FH_HOP_SIGNAL_1 == hopSignal) { bitmSwInt_A = 0x1; - hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; armAddr_A = adrv9001->devStateInfo.fhHopTableA1Addr; - bitmSwInt_B = 0x80; + bitmSwInt_B = 0x80; hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; armAddr_B = adrv9001->devStateInfo.fhHopTableB1Addr; } @@ -1259,12 +1263,12 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 } else { - bitmSwInt_A = 0x1; - hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + bitmSwInt_A = 0x1; + hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; armAddr_A = adrv9001->devStateInfo.fhHopTableA1Addr; - bitmSwInt_B = 0x2; - hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; + bitmSwInt_B = 0x2; + hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; armAddr_B = adrv9001->devStateInfo.fhHopTableB1Addr; } @@ -1305,7 +1309,7 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 adrv9001_LoadTwoBytes(&offset, fhTable_A, hopTable[i + j].tx2Attenuation_fifthdB); } ADI_EXPECT(adrv9001_HopTable_Spi_Pack, adrv9001, addrArray_A, fhTable_A, numberOfHops, &numWrBytes, bitmSwInt_A, spiPackedFhTable); - + offset = 0; for (j = numberOfHops; j < (2 * numberOfHops); j++) { @@ -1351,9 +1355,27 @@ int32_t adi_adrv9001_fh_HopTable_BytesPerTable_Get(adi_adrv9001_Device_t *adrv90 ADI_EXPECT(adi_adrv9001_fh_NumberOfHops_Get, adrv9001, numberHopsPerDynamicLoad, &numberOfHops); spiPackBytesPerTable = spiConfigBytes + spiAddrPackLength + spiInterruptBytes; - + payloadBytes = ((sizeof(adrv9001_FhHopFrame_t) * numberOfHops) + fhBytesLength) * 3; *bytesPerTable = payloadBytes + spiPackBytesPerTable; ADI_API_RETURN(adrv9001); } +int32_t adi_adrv9001_fh_RxOffsetFrequency_Set(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal, int32_t rx1OffsetFrequencyHz, int32_t rx2OffsetFrequencyHz) +{ + uint32_t offset = 0; + uint8_t rxOffsetFrequencyHzArray[8] = { 0 }; + adrv9001_LoadFourBytes(&offset, rxOffsetFrequencyHzArray, rx1OffsetFrequencyHz); + adrv9001_LoadFourBytes(&offset, rxOffsetFrequencyHzArray, rx2OffsetFrequencyHz); + if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) + { + + ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, FREQ_HOPPING_HOP1_OFFSET_FREQ_OVERWRITE_ADDR, rxOffsetFrequencyHzArray, sizeof(rxOffsetFrequencyHzArray), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); + } + else + { + ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, FREQ_HOPPING_HOP2_OFFSET_FREQ_OVERWRITE_ADDR, rxOffsetFrequencyHzArray, sizeof(rxOffsetFrequencyHzArray), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); + } + + ADI_API_RETURN(adrv9001); +} \ No newline at end of file diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c index a52a549e67eff3..5881a822a6a6ea 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c @@ -224,38 +224,6 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_gpio_ManualAnalogInput ADI_API_RETURN(device); } -static __maybe_unused int32_t adi_adrv9001_gpio_PinDirection_Get_Validate(adi_adrv9001_Device_t *device, - adi_adrv9001_GpioPin_e pin) -{ - ADI_API_RETURN(device); - ADI_RANGE_CHECK(device, pin, ADI_ADRV9001_GPIO_DIGITAL_00, ADI_ADRV9001_GPIO_ANALOG_11); -} - -int32_t adi_adrv9001_gpio_PinDirection_Get(adi_adrv9001_Device_t *device, - adi_adrv9001_GpioPin_e pin, - adi_adrv9001_GpioPinDirection_e *direction) -{ - uint16_t gpioOutEn = 0; - - ADI_PERFORM_VALIDATION(adi_adrv9001_gpio_PinDirection_Get_Validate, device, pin); - if (ADI_ADRV9001_GPIO_DIGITAL_00 <= pin && pin <= ADI_ADRV9001_GPIO_DIGITAL_15) - { - ADI_EXPECT(adrv9001_NvsRegmapCore_NvsGpioDirectionControlOe_Get, device, &gpioOutEn); - *direction = (gpioOutEn & (1 << (pin - 1))) >> (pin - 1); - } - else if (ADI_ADRV9001_GPIO_ANALOG_00 <= pin && pin <= ADI_ADRV9001_GPIO_ANALOG_11) - { - ADI_EXPECT(adrv9001_NvsRegmapCore1_NvsGpioAnalogDirectionControlOe_Get, device, &gpioOutEn); - *direction = (gpioOutEn & (1 << (pin - ADI_ADRV9001_GPIO_ANALOG_00))) >> (pin - ADI_ADRV9001_GPIO_ANALOG_00); - } - else - { - ADI_SHOULD_NOT_EXECUTE(device); - } - - ADI_API_RETURN(device); -} - int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *device, adi_adrv9001_GpioPin_e pin) { @@ -360,6 +328,15 @@ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, { ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_MON_BBIC_WAKEUP, &initCfg->systemPowerSavingAndMonitorWakeUp); } + + if (ADI_ADRV9001_GPIO_UNASSIGNED != initCfg->fh_update_rx_nco[0].pin) + { + ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP1_NCO_ASYNC_CHANGE, &initCfg->fh_update_rx_nco[0]); + } + if (ADI_ADRV9001_GPIO_UNASSIGNED != initCfg->fh_update_rx_nco[1].pin) + { + ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP2_NCO_ASYNC_CHANGE, &initCfg->fh_update_rx_nco[1]); + } ADI_API_RETURN(adrv9001); } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c index a0daf037579629..4f96e46e502527 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c @@ -98,7 +98,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Write_Val // Maximum combined gain step must not exceed 29000 mdB ADI_RANGE_CHECK(device, totalGainSteps, 0, 29000); } - + /*Check that the gain index offset is within range*/ ADI_RANGE_CHECK(device, gainIndexOffset, ADI_ADRV9001_MIN_RX_GAIN_TABLE_INDEX, ADI_ADRV9001_START_RX_GAIN_INDEX); @@ -126,7 +126,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Write_Val } ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + ADI_RANGE_CHECK(device, gainTableType, ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE, ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE); /*Check that Rx profile or ORx profile is valid*/ @@ -174,11 +174,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, int32_t j = 0; uint16_t numGainIndicesToWrite = 0; uint8_t lnaStepOffset = { 0 }; -#ifdef __KERNEL__ - static adi_adrv9001_RxGainTableRow_t lnaGainTable[127]; -#else adi_adrv9001_RxGainTableRow_t lnaGainTable[127] = { { 0 } }; -#endif adi_adrv9001_RxGainTableRow_t *gainTablePtr = NULL; uint8_t minGainIndex = 0; uint8_t indexOffset = 0; @@ -203,7 +199,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, { if (i == 0) { - lnaStepOffset = (gainIndexOffset - (lnaConfig->minGainIndex - 1)); + lnaStepOffset = (gainIndexOffset - (lnaConfig->minGainIndex - 1)); } else { @@ -227,7 +223,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, } gainTablePtr = lnaGainTable; } - + baseIndex = (gainIndexOffset - (numGainIndicesToWrite - 1)); minGainIndex = (uint8_t)baseIndex; ADI_EXPECT(adrv9001_RxGainTableFormat, device, gainTablePtr, &armDmaData[0], numGainIndicesToWrite); @@ -331,7 +327,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Read_Vali ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcMinimumGainIndex_Get, device, instance, &minGainIndex); ADI_RANGE_CHECK(device, gainIndexOffset, minGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); - + if (((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_RX_PROFILE_VALID)) == 0) && ((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_ORX_PROFILE_VALID)) == 0) && ((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_TX_PROFILE_VALID)) == 0)) @@ -477,7 +473,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); adi_common_channel_to_index(channel, &chan_idx); - + /* Check that Rx profile is valid */ if (0 == ADRV9001_BF_EQUAL(device->devStateInfo.initializedChannels, RX_CHANNELS[chan_idx])) { @@ -496,7 +492,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcMinimumGainIndex_Get, device, instance, &minGainIndex); ADI_RANGE_CHECK(device, gainIndex, minGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); - + /* Save the current gain control mode and set to the required mode */ ADI_EXPECT(adi_adrv9001_Rx_GainControl_Mode_Get, device, channel, gainCtrlMode); if (ADI_ADRV9001_RX_GAIN_CONTROL_MODE_SPI != *gainCtrlMode) @@ -674,7 +670,7 @@ static __maybe_unused int32_t adi_adrv9001_Rx_InterfaceGain_Validate(adi_adrv900 adi_adrv9001_RxInterfaceGain_e rxInterfaceGainMax = ADI_ADRV9001_RX_INTERFACE_GAIN_NEGATIVE_36_DB; adi_common_channel_to_index(channel, &chan_index); - + if (device->devStateInfo.rxOutputRate_kHz[chan_index] < RX_OUTPUT_RATE_kHZ) { if (gainTableType == ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE) @@ -713,7 +709,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Confi adi_adrv9001_RxInterfaceGainCtrl_t *rxInterfaceGainCtrl) { adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&device->common, rxInterfaceGainCtrl); @@ -744,11 +740,11 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Confi rxInterfaceGainCtrl->rssiMovingAverageDuration, 1, 10); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); if (ADI_ADRV9001_CHANNEL_CALIBRATED != state) { - ADI_ERROR_REPORT(device, + ADI_ERROR_REPORT(device, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -827,12 +823,12 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Set_V /* Perform Range check of allowed gain value */ ADI_EXPECT(adi_adrv9001_Rx_InterfaceGain_Validate, device, channel, gainTableType, gain); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); if ((ADI_ADRV9001_CHANNEL_PRIMED != state) && (ADI_ADRV9001_CHANNEL_RF_ENABLED != state)) { - ADI_ERROR_REPORT(device, + ADI_ERROR_REPORT(device, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -1450,12 +1446,12 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_PortSwitch_Configur } /* NULL pointer check */ - ADI_NULL_PTR_RETURN(&device->common, switchConfig); + ADI_NULL_PTR_RETURN(&device->common, switchConfig); /* Freuqency range check */ - ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); - ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); - ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); /* Min frequency must be smaller than max */ @@ -1483,7 +1479,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_PortSwitch_Configur "Port A and B freuqency ranges cannot overlap."); ADI_API_RETURN(device) } - + ADI_API_RETURN(device); } @@ -1492,7 +1488,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Configure(adi_adrv9001_Device_t *device, { uint8_t armData[42] = { 0 }; uint8_t extData[3] = { 0 }; - uint32_t offset = 0u; + uint32_t offset = 0u; ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_PortSwitch_Configure_Validate, device, switchConfig); @@ -1517,7 +1513,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Configure(adi_adrv9001_Device_t *device, extData[0] = 0; extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_CFG_RX_PORT_SWITCHING; - + ADI_EXPECT(adi_adrv9001_arm_Config_Write, device, armData, sizeof(armData), extData, sizeof(extData)) ADI_API_RETURN(device); @@ -1540,7 +1536,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Inspect(adi_adrv9001_Device_t *device, ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_PortSwitch_Inspect_Validate, device, switchConfig); ADI_EXPECT(adi_adrv9001_arm_Config_Read, device, OBJID_CFG_RX_PORT_SWITCHING, channelMask, offset, armReadBack, sizeof(armReadBack)) - + adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->minFreqPortA_Hz); adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->maxFreqPortA_Hz); adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->minFreqPortB_Hz); @@ -1563,7 +1559,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_RANGE_CHECK(device, gainTableType, ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE, ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE); ADI_NULL_PTR_RETURN(&device->common, lnaConfig); - + if (!lnaConfig->externalLnaPresent) { ADI_ERROR_REPORT(&device->common, @@ -1590,7 +1586,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu ADI_RANGE_CHECK(device, lnaConfig->numberLnaGainSteps, 2, 4); //ADI_RANGE_CHECK(device, lnaConfig->settlingDelay, 0, 0); //ADI_RANGE_CHECK(device, lnaConfig->lnaDigitalGainDelay, 0, 0); - + if(0 != lnaConfig->lnaGainSteps_mdB[0]) { ADI_ERROR_REPORT(&device->common, @@ -1601,7 +1597,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu "lnaConfig->lnaGainSteps_mdB[0] should have the gain step as '0' only"); ADI_ERROR_RETURN(device->common.error.newAction); } - + for (i = 1; i < lnaConfig->numberLnaGainSteps; i++) { if ((lnaConfig->lnaGainSteps_mdB[i] == 0) || ((lnaConfig->lnaGainSteps_mdB[i] % 500) != 0)) @@ -1685,12 +1681,12 @@ int32_t adi_adrv9001_Rx_ExternalLna_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapRxb_FeGainDelayIncr_Set, device, rxbAddr, (lnaConfig->lnaDigitalGainDelay + FEGAIN_INCR_FIXED_VALUE)); ADI_EXPECT(adrv9001_NvsRegmapRxb_FeGainDelayDecr_Set, device, rxbAddr, (lnaConfig->lnaDigitalGainDelay + FEGAIN_DECR_FIXED_VALUE)); ADI_EXPECT(adrv9001_NvsRegmapRx_ExtLnaDigitalGainDelay_Set, device, rxAddr, (lnaConfig->lnaDigitalGainDelay + EXTDIGGAIN_DELAY_FIXED_VALUE)); - + if (ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE == gainTableType) { ADI_EXPECT(adrv9001_NvsRegmapRx_GainCompForExtGain_Set, device, rxAddr, (uint8_t)lnaConfig->externalLnaPresent); } - + ADI_API_RETURN(device); } @@ -1778,11 +1774,11 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Loid_Configure_Vali adi_adrv9001_RadioState_t state = { 0 }; uint8_t port_index = 0; uint8_t chan_index = 0; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, loidConfig); - + /* Validate state is STANDBY or CALIBRATED*/ ADI_EXPECT(adi_adrv9001_Radio_State_Get, adrv9001, &state); adi_common_port_to_index(ADI_RX, &port_index); @@ -1811,13 +1807,13 @@ int32_t adi_adrv9001_Rx_Loid_Configure(adi_adrv9001_Device_t *adrv9001, ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_Loid_Configure_Validate, adrv9001, channel, loidConfig); armData[0] = loidConfig->loidEnable; - armData[1] = loidConfig->loidInterval; - armData[2] = loidConfig->loidThHigh; - armData[3] = loidConfig->loidThLow; + armData[1] = 1; + armData[2] = loidConfig->loidThreshold_negdBFS - 6; + armData[3] = loidConfig->loidThreshold_negdBFS - 6; /* Write LOID config to ARM mailbox */ ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_SET, &armData[0], sizeof(armData), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_RX, channel); extData[1] = OBJID_GS_LOID; @@ -1829,14 +1825,14 @@ int32_t adi_adrv9001_Rx_Loid_Configure(adi_adrv9001_Device_t *adrv9001, extData[1], (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_TIMEOUT_US, (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_INTERVAL_US); - + ADI_API_RETURN(adrv9001); } static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Loid_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) -{ +{ ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, loidConfig); @@ -1848,9 +1844,9 @@ int32_t adi_adrv9001_Rx_Loid_Inspect(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) { - uint8_t armReadBack[4] = { 0 }; + uint8_t armReadBack[4] = { 0 }; uint8_t extData[2] = { 0 }; - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_RX, channel); extData[1] = OBJID_GS_LOID; @@ -1869,11 +1865,9 @@ int32_t adi_adrv9001_Rx_Loid_Inspect(adi_adrv9001_Device_t *adrv9001, &armReadBack[0], sizeof(armReadBack), ADRV9001_ARM_MEM_READ_AUTOINCR) - + loidConfig->loidEnable = armReadBack[0]; - loidConfig->loidInterval = (adi_adrv9001_LoidInterval_e) armReadBack[1]; - loidConfig->loidThHigh = armReadBack[2]; - loidConfig->loidThLow = armReadBack[3]; + loidConfig->loidThreshold_negdBFS = armReadBack[2] + 6; ADI_API_RETURN(adrv9001); } \ No newline at end of file diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx_gaincontrol.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx_gaincontrol.c index e99327978e480c..20087c945499ba 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx_gaincontrol.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx_gaincontrol.c @@ -364,8 +364,8 @@ int32_t adi_adrv9001_Rx_GainControl_Configure(adi_adrv9001_Device_t *device, #endif /* The new formula should be: "decimated_data_overload_secondary_upper_threshold = Round((hbHighThresh - 0.33352)/1.33352)" - The equation above is derived based on the fact that the 2nd high counter should be set 1.5dB below the hbHighThresh value. - 20*log10((hbHighThresh + 1)/2^15) - 20*log10((secondary_upper_threshold + 1)/2^15) = 1.5 + The equation above is derived based on the fact that the 2nd high counter should be set 2.5dB below the hbHighThresh value. + 20*log10((hbHighThresh + 1)/2^15) - 20*log10((secondary_upper_threshold + 1)/2^15) = 2.5 */ threshCalc = (agcCfg->peak.hbHighThresh * APD_LOW_FREQ_THRESH_MULTIPLICATION_FACTOR) - APD_LOW_FREQ_THRESH_SUBTRACTION_FACTOR; threshCalc = DIV_ROUND_CLOSEST(threshCalc, APD_LOW_FREQ_THRESH_DIVISION_FACTOR); @@ -461,7 +461,35 @@ int32_t adi_adrv9001_Rx_GainControl_Configure(adi_adrv9001_Device_t *device, ADRV9001_SPIWRITEBYTE(device, "GPIO_SOURCE_SEL", (GPIO_SOURCE_SEL_ADDR + gpioCrumb3_2 - 1), gpioSource3_2); ADI_EXPECT(adrv9001_NvsRegmapRx_ControlOutMuxSel_Set, device, rxAddr, controlMuxAddress); + + /* Enable/Disable RXQEC Freeze*/ + if (ADI_CHANNEL_1 == channel) + { + ADI_EXPECT(adrv9001_NvsRegmapCore2_Rx1Fic2CaptPedSoftOverrideEnable_Set, device, agcCfg->rxQecFreezeEnable); + } + else + { + ADI_EXPECT(adrv9001_NvsRegmapCore2_Rx2Fic2CaptPedSoftOverrideEnable_Set, device, agcCfg->rxQecFreezeEnable); + } + if (agcCfg->gpioFreezePin != ADI_ADRV9001_GPIO_UNASSIGNED) + { + /* Enable freeze mode */ + ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcEnableGainFreeze_Set, device, rxbAddr, 0x1); + + /* Set up GPIO pins */ + ADI_EXPECT(adi_adrv9001_gpio_ManualInput_Configure, device, agcCfg->gpioFreezePin); + if (ADI_CHANNEL_1 == channel) + { + ADI_EXPECT(adrv9001_NvsRegmapCore1_Rx1AgcSlowloopFreezeGpioSelect_Set, device, (agcCfg->gpioFreezePin - 1)); + ADI_EXPECT(adrv9001_NvsRegmapCore1_Rx1AgcSlowloopFreezeGpioMask_Set, device, 0); + } + else + { + ADI_EXPECT(adrv9001_NvsRegmapCore1_Rx2AgcSlowloopFreezeGpioSelect_Set, device, (agcCfg->gpioFreezePin - 1)); + ADI_EXPECT(adrv9001_NvsRegmapCore1_Rx2AgcSlowloopFreezeGpioMask_Set, device, 0); + } + } ADI_API_RETURN(device); } @@ -635,6 +663,36 @@ int32_t adi_adrv9001_Rx_GainControl_Inspect(adi_adrv9001_Device_t *device, } } + /* Enable/Disable RXQEC Freeze flag*/ + if (ADI_CHANNEL_1 == channel) + { + ADI_EXPECT(adrv9001_NvsRegmapCore2_Rx1Fic2CaptPedSoftOverrideEnable_Get, device, &bfValue); + } + else + { + ADI_EXPECT(adrv9001_NvsRegmapCore2_Rx2Fic2CaptPedSoftOverrideEnable_Get, device, &bfValue); + } + agcCfg->rxQecFreezeEnable = (bool)bfValue; + + /* GPIO Freeze Pin*/ + ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcEnableGainFreeze_Get, device, rxbAddr, &bfValue); + if (bfValue == 0x1) + { + if (ADI_CHANNEL_1 == channel) + { + ADI_EXPECT(adrv9001_NvsRegmapCore1_Rx1AgcSlowloopFreezeGpioSelect_Get, device, &bfValue); + } + else + { + ADI_EXPECT(adrv9001_NvsRegmapCore1_Rx2AgcSlowloopFreezeGpioSelect_Get, device, &bfValue); + } + agcCfg->gpioFreezePin = (adi_adrv9001_GpioPin_e)(bfValue + 1); + } + else + { + agcCfg->gpioFreezePin = ADI_ADRV9001_GPIO_UNASSIGNED; + } + ADI_API_RETURN(device); } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_spi.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_spi.c index fc8068bce7fe8c..65144c06a2fb66 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_spi.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_spi.c @@ -570,7 +570,7 @@ int32_t adi_adrv9001_spi_Master_Configure(adi_adrv9001_Device_t *device, armData[offset++] = spiMasterConfig->numBytes; armData[offset++] = spiMasterConfig->baudRateDiv; armData[offset++] = spiMasterConfig->transactionBytes; - armData[offset++] = spiMasterConfig->assertionMode; + armData[offset++] = spiMasterConfig->transferMode; armData[offset++] = spiMasterConfig->spiSlaveDevicesConnected; armData[offset++] = spiMasterConfig->csSource; armData[offset++] = spiMasterConfig->pin - 1; @@ -613,7 +613,7 @@ int32_t adi_adrv9001_spi_Master_Inspect(adi_adrv9001_Device_t *device, spiMasterConfig->numBytes = armReadBack[offset++]; spiMasterConfig->baudRateDiv = armReadBack[offset++]; spiMasterConfig->transactionBytes = armReadBack[offset++]; - spiMasterConfig->assertionMode = armReadBack[offset++]; + spiMasterConfig->transferMode = armReadBack[offset++]; spiMasterConfig->spiSlaveDevicesConnected = armReadBack[offset++]; spiMasterConfig->csSource = armReadBack[offset++]; spiMasterConfig->pin = (armReadBack[offset++] + 1); diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_ssi.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_ssi.c index 7ca29599b0a76a..f427a71c13f876 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_ssi.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_ssi.c @@ -412,6 +412,7 @@ int32_t adi_adrv9001_Ssi_Tx_TestMode_Status_Inspect(adi_adrv9001_Device_t *devic uint8_t captureComplete = 0; uint32_t timeout_us = ADI_ADRV9001_SSI_DEBUG_TIMEOUT_US; adrv9001_BfNvsRegmapTx_e baseAddress = ADRV9001_BF_TX1_CORE; + uint8_t ddrSet = 0; waitInterval_us = (ADI_ADRV9001_SSI_DEBUG_INTERVAL_US > timeout_us) ? timeout_us : ADI_ADRV9001_SSI_DEBUG_INTERVAL_US; @@ -578,7 +579,15 @@ int32_t adi_adrv9001_Ssi_Tx_TestMode_Status_Inspect(adi_adrv9001_Device_t *devic ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDebugRampShiftError_Get, device, baseAddress, &ssiTestModeStatus->dataError); } - ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxStrobeAlignError_Get, device, baseAddress, &ssiTestModeStatus->strobeAlignError); + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDdrSel_Get, device, baseAddress, &ddrSet); + if (ddrSet == 0) + { + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxStrobeAlignError_Get, device, baseAddress, &ssiTestModeStatus->strobeAlignError); + } + else + { + ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxDdrStrobeAlignError_Get, device, baseAddress, &ssiTestModeStatus->strobeAlignError); + } ADI_EXPECT(adrv9001_NvsRegmapTx_CssiTxFifoFull_Get, device, baseAddress, &ssiTestModeStatus->fifoFull); diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c index dad674752fb722..8f77f25146008f 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c @@ -32,6 +32,7 @@ #include "adi_adrv9001_spi.h" #include "adi_adrv9001_radio.h" #include "adi_adrv9001_auxdac.h" +#include "adi_adrv9001_dpd.h" #include "adrv9001_validators.h" #include "adrv9001_arm.h" @@ -168,7 +169,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_AttenuationMode_Set currentState.channelStates[port_index][chan_index], "Error while attempting to set attenuation mode. Channel must be in STANDBY or CALIBRATED."); } - + /* Retrieve attenuation mode */ ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Get, device, channel, &txModeRead); if (txModeRead == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) @@ -195,14 +196,14 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Set(adi_adrv9001_Device_t *device, txChannelBaseAddr = Tx_Addr_Get(channel); device->devStateInfo.txAttenMode[channel - 1] = mode; - + if (mode == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) { mode = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI; } ADI_EXPECT(adrv9001_NvsRegmapTx_TxAttenMode_Set, device, txChannelBaseAddr, (uint8_t)mode); - + ADI_API_RETURN(device) } @@ -220,10 +221,9 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Get(adi_adrv9001_Device_t *device, adi_common_ChannelNumber_e channel, adi_adrv9001_TxAttenuationControlMode_e *mode) { - adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_AttenuationMode_Get_Validate, device, channel, mode); - + + adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_TX, channel, &state); if (state == ADI_ADRV9001_CHANNEL_PRIMED) { @@ -347,6 +347,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_Attenuation_Set_Val { uint8_t chan_index = 0; adi_adrv9001_TxAttenuationControlMode_e txModeRead = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_BYPASS; + adi_adrv9001_DpdCfg_t dpdCfgRead = { 0 }; ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); @@ -384,14 +385,15 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_Attenuation_Set_Val /* Retrieve attenuation mode */ ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Get, device, channel, &txModeRead); - if (txModeRead == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) + ADI_EXPECT(adi_adrv9001_dpd_Inspect, device, channel, &dpdCfgRead); + if ((txModeRead == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) & (dpdCfgRead.clgcLoopOpen != true)) { ADI_ERROR_REPORT(&device->common, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, ADI_COMMON_ACT_ERR_CHECK_PARAM, txModeRead, - "Invalid TxAttenuation Control Mode. Cannot control when mode CLGC is enabled"); + "Cannot set TxAtten when CLGC is enabled and loop is closed"); } ADI_API_RETURN(device); @@ -414,7 +416,7 @@ int32_t adi_adrv9001_Tx_Attenuation_Set(adi_adrv9001_Device_t* device, /* Save the current attenuation mode and set to the required mode */ ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Get, device, channel, &attenMode); - if (attenMode != ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI) + if ((attenMode != ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI)&(attenMode != ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC)) { ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Set, device, channel, ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI); } @@ -454,7 +456,7 @@ int32_t adi_adrv9001_Tx_Attenuation_Set(adi_adrv9001_Device_t* device, ADI_EXPECT(adrv9001_NvsRegmapTx_TxAttenuation_Set, device, txChannelBaseAddr, regData); /* Restore the atten mode */ - if (attenMode != ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI) + if ((attenMode != ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI) & (attenMode != ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC)) { ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Set, device, channel, attenMode); } @@ -960,9 +962,9 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat { int32_t txSampleRateDiv2_Hz = 0; adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + ADI_NULL_PTR_RETURN(&adrv9001->common, tone); if (tone->enable) { @@ -981,7 +983,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat "Channel state must be CALIBRATED"); } } - + ADI_API_RETURN(adrv9001); } @@ -992,7 +994,7 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Configure(adi_adrv9001_Device_t * uint8_t armData[12] = { 0 }; uint8_t extData[5] = { 0 }; uint32_t offset = 0; - + ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_InternalToneGeneration_Configure_Validate, adrv9001, channel, tone); adrv9001_LoadFourBytes(&offset, armData, sizeof(armData) - sizeof(uint32_t)); @@ -1000,7 +1002,7 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Configure(adi_adrv9001_Device_t * armData[offset++] = tone->amplitude; offset += 2; adrv9001_LoadFourBytes(&offset, armData, tone->frequency_Hz); - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_TX, channel); extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_CFG_TX_INTERNAL_TONE_GENERATION; @@ -1015,10 +1017,10 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat adi_adrv9001_TxInternalToneGeneration_t *tone) { adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, tone); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, adrv9001, ADI_TX, channel, &state); if (ADI_ADRV9001_CHANNEL_STANDBY == state) { @@ -1029,7 +1031,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat state, "Channel state must be any of CALIBRATED, PRIMED, RF_ENABLED"); } - + ADI_API_RETURN(adrv9001); } @@ -1040,12 +1042,12 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Inspect(adi_adrv9001_Device_t *ad uint8_t armReadBack[8] = { 0 }; uint8_t channelMask = 0; uint32_t offset = 0; - + ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_InternalToneGeneration_Inspect_Validate, adrv9001, channel, tone); channelMask = adi_adrv9001_Radio_MailboxChannel_Get(ADI_TX, channel); ADI_EXPECT(adi_adrv9001_arm_Config_Read, adrv9001, OBJID_CFG_TX_INTERNAL_TONE_GENERATION, channelMask, offset, armReadBack, sizeof(armReadBack)); - + tone->enable = (bool)armReadBack[offset++]; tone->amplitude = (adi_adrv9001_TxInternalToneAmplitude_e)armReadBack[offset++]; offset += 2; @@ -1203,7 +1205,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_PaRamp_Configure_Va { ADI_RANGE_CHECK(device, paRampCfg->gpioSource, ADI_ADRV9001_GPIO_UNASSIGNED, ADI_ADRV9001_GPIO_DIGITAL_15); } - + ADI_RANGE_CHECK(device, paRampCfg->rampClock_kHz, ADRV9001_TX_PA_RAMP_MIN_CLK_KHZ, ADRV9001_TX_PA_RAMP_MAX_CLK_KHZ); ADI_API_RETURN(device); @@ -1290,7 +1292,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, uint32_t refClk_Hz = 0; ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_PaRamp_Configure_Validate, device, channel, paRampCfg); - + // Use Analog RefClkDivRatio, DEVCLKOUT Divider not used here ADI_EXPECT(adrv9001_NvsRegmapCore3_RefClkIntDevclkDivideRatio_Get, device, &clkDivRatio); @@ -1298,9 +1300,9 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, refClk_Hz = KILO_TO_BASE_UNIT(device->devStateInfo.deviceClock_kHz) >> clkDivRatio; paRampDpClkDiv = DIV_ROUND_CLOSEST(refClk_Hz, KILO_TO_BASE_UNIT(paRampCfg->rampClock_kHz)); - + ADI_EXPECT(adi_adrv9001_AuxDac_Configure, device, paRampCfg->auxDacChannelSelect, paRampCfg->enable); - + switch (paRampCfg->auxDacChannelSelect) { case ADI_ADRV9001_AUXDAC0: @@ -1319,7 +1321,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_SHOULD_NOT_EXECUTE(device); break; } - + /* crossbar config for AUX DAC 0/1/2/3. Bit[0]: xbar 0 select: 1: TX2, 0: TX1 Bit[1]: xbar 1 select: 1: TX2, 0: TX1 @@ -1382,7 +1384,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, } muxSel = dataConfig; ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, muxSel); - + bfValue = (uint8_t) paRampCfg->triggerSelect; if (channel == ADI_CHANNEL_1) @@ -1395,14 +1397,14 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigStartDelay_Set, device, paRampCfg->triggerDelayRise); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigEndDelay_Set, device, paRampCfg->triggerDelayFall); // Set Ramp Clock to max for LUTWrite - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_ENABLE_PIN) - { + { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStopSel_Set, device, 0x1); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStopSel_Set, device, 0x1); @@ -1412,16 +1414,16 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStartSel_Set, device, bfValue); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStopSel_Set, device, bfValue); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStartSel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStopSel_Set, device, 0x0); } - + // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioSel_Set, device, (uint8_t)paRampCfg->gpioSource - 1); - - + + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_GPIO) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioMask_Set, device, 0x0); @@ -1447,16 +1449,16 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, /* Configure the delays */ ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigStartDelay_Set, device, paRampCfg->triggerDelayRise); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigEndDelay_Set, device, paRampCfg->triggerDelayFall); - + // Set Ramp Clock to max for LUTWrite - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + if (bfValue == 0x2) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStartSel_Set, device, 0x1); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, 0x1); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStopSel_Set, device, 0x1); @@ -1466,7 +1468,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStartSel_Set, device, bfValue); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, bfValue); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStartSel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStopSel_Set, device, 0x0); @@ -1475,7 +1477,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioSel_Set, device, (uint8_t)paRampCfg->gpioSource - 1); - + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_GPIO) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioMask_Set, device, 0x0); @@ -1485,7 +1487,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioMask_Set, device, 0x1); } - + /* Enable the clock only after all registers are configured */ ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Set, device, 0x1); @@ -1522,7 +1524,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_LutRdEnable_Set, device, 0x1); /* Read PA LUT data */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampLutRdData_Get, device, &bfValue); - + if (channel == ADI_CHANNEL_1) { @@ -1533,7 +1535,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1UpThreshold_Set, device, paRampCfg->upEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1DownThreshold_Set, device, paRampCfg->downEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1Asymmetric_Set, device, (uint8_t)paRampCfg->asymmetricRamp); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkEn_Set, device, (uint8_t)paRampCfg->enable); } else @@ -1545,10 +1547,10 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2UpThreshold_Set, device, paRampCfg->upEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2DownThreshold_Set, device, paRampCfg->downEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2Asymmetric_Set, device, (uint8_t)paRampCfg->asymmetricRamp); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Set, device, (uint8_t)paRampCfg->enable); } - + ADI_API_RETURN(device); } @@ -1659,14 +1661,14 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, uint8_t triggerSelectValue = 0; ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_PaRamp_Inspect_Validate, device, channel, paRampCfg); - + // Set all AuxDAC SPI Words to 0x0, Set Mux to 0x0 (all SPI), restore after LUTRead to prevent unwanted output on AuxDACs ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Get, device, &muxSelProgrammed); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Get, device, &spiWordProgrammed[0]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac1_Get, device, &spiWordProgrammed[1]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac2_Get, device, &spiWordProgrammed[2]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac3_Get, device, &spiWordProgrammed[3]); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac1_Set, device, 0x0); @@ -1677,7 +1679,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore3_RefClkIntDevclkDivideRatio_Get, device, &clkDivRatio); refClk_Hz = KILO_TO_BASE_UNIT(device->devStateInfo.deviceClock_kHz) >> clkDivRatio; - + // Not possible to return the configured AuxDAC for each channel based on XBAR..._Inspect will always return ADI_ADRV9001_AUXDAC0 paRampCfg->auxDacChannelSelect = ADI_ADRV9001_AUXDAC0; @@ -1694,7 +1696,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, rampClock_kHz = refClk_Hz / paRampDpClkDiv; /* Convert to kHz */ paRampCfg->rampClock_kHz = rampClock_kHz / 1000; - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); } else { @@ -1709,7 +1711,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, rampClock_kHz = refClk_Hz / paRampDpClkDiv; /* Convert to kHz */ paRampCfg->rampClock_kHz = rampClock_kHz / 1000; - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, 0x0); } for (idx = 0; idx < ADRV9001_TX_PA_RAMP_LUT_SIZE; idx++) @@ -1728,7 +1730,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, /* De-select pa_ramp_tx1_lut_sel bit */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1LutSel_Set, device, 0x0); // Restore Ramp Clock to configured after read - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); /* Set PA Ramp up/down threshold for Tx1 */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1UpThreshold_Get, device, &(paRampCfg->upEndIndex)); @@ -1741,7 +1743,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, /* De-select pa_ramp_tx2_lut_sel bit */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2LutSel_Set, device, 0x0); // Restore Ramp Clock to configured after read - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); /* Set PA Ramp up/down threshold for Tx2 */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2UpThreshold_Get, device, &(paRampCfg->upEndIndex)); @@ -1764,7 +1766,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioSel_Get, device, &bfValue); - paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; + paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnable_Get, device, &bfValue); @@ -1773,7 +1775,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigStartDelay_Get, device, &(paRampCfg->triggerDelayRise)); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigEndDelay_Get, device, &(paRampCfg->triggerDelayFall)); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkEn_Get, device, &bfValue); paRampCfg->enable = (bool)bfValue; } @@ -1791,7 +1793,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioSel_Get, device, &bfValue); - paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; + paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnable_Get, device, &bfValue); @@ -1800,11 +1802,11 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigStartDelay_Get, device, &(paRampCfg->triggerDelayRise)); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigEndDelay_Get, device, &(paRampCfg->triggerDelayFall)); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Get, device, &bfValue); paRampCfg->enable = (bool)bfValue; } - + // Restore AuxDAC SPI Words and Mux after LUTRead complete ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, muxSelProgrammed); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Set, device, spiWordProgrammed[0]); @@ -2056,7 +2058,7 @@ int32_t adi_adrv9001_Tx_DataPath_Loopback_Set(adi_adrv9001_Device_t *device, { adrv9001_BfNvsRegmapTx_e baseAddr = ADRV9001_BF_TX1_CORE; ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + if (ADI_CHANNEL_2 == channel) { baseAddr = ADRV9001_BF_TX2_CORE; From 1f41d386c5d2fb6cde656b0cda09a6a27cf26fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 25 Feb 2022 16:55:12 +0100 Subject: [PATCH 203/407] firmware: Update firmware for adrv9002 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Arm firmware updated to version 0.20.0.10. Update default profiles. Signed-off-by: Nuno Sá --- firmware/Navassa_CMOS_profile.json | 32 ++++++++++++++++++----------- firmware/Navassa_EvaluationFw.bin | Bin 294912 -> 294912 bytes firmware/Navassa_LVDS_profile.json | 32 ++++++++++++++++++----------- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/firmware/Navassa_CMOS_profile.json b/firmware/Navassa_CMOS_profile.json index a52377b6918d60..80b9f62664a985 100644 --- a/firmware/Navassa_CMOS_profile.json +++ b/firmware/Navassa_CMOS_profile.json @@ -48,13 +48,14 @@ "hpAdcCorner": 20000000, "lpAdcCorner": 0, "adcClk_kHz": 2211840, - "rxCorner3dB_kHz": 40000, - "rxCorner3dBLp_kHz": 40000, + "rxCorner3dB_kHz": 10000, + "rxCorner3dBLp_kHz": 10000, "tiaPower": 2, "tiaPowerLp": 2, "channelType": 1, "adcType": 1, "lpAdcCalMode": 0, + "gainTableType": 0, "rxDpProfile": { "rxNbDecTop": { "scicBlk23En": 0, @@ -164,13 +165,14 @@ "hpAdcCorner": 20000000, "lpAdcCorner": 0, "adcClk_kHz": 2211840, - "rxCorner3dB_kHz": 40000, - "rxCorner3dBLp_kHz": 40000, + "rxCorner3dB_kHz": 10000, + "rxCorner3dBLp_kHz": 10000, "tiaPower": 2, "tiaPowerLp": 2, "channelType": 2, "adcType": 1, "lpAdcCalMode": 0, + "gainTableType": 0, "rxDpProfile": { "rxNbDecTop": { "scicBlk23En": 0, @@ -287,6 +289,7 @@ "channelType": 0, "adcType": 1, "lpAdcCalMode": 0, + "gainTableType": 0, "rxDpProfile": { "rxNbDecTop": { "scicBlk23En": 0, @@ -403,6 +406,7 @@ "channelType": 0, "adcType": 1, "lpAdcCalMode": 0, + "gainTableType": 0, "rxDpProfile": { "rxNbDecTop": { "scicBlk23En": 0, @@ -519,6 +523,7 @@ "channelType": 64, "adcType": 1, "lpAdcCalMode": 0, + "gainTableType": 0, "rxDpProfile": { "rxNbDecTop": { "scicBlk23En": 0, @@ -635,6 +640,7 @@ "channelType": 128, "adcType": 1, "lpAdcCalMode": 0, + "gainTableType": 0, "rxDpProfile": { "rxNbDecTop": { "scicBlk23En": 0, @@ -751,6 +757,7 @@ "channelType": 0, "adcType": 1, "lpAdcCalMode": 0, + "gainTableType": 0, "rxDpProfile": { "rxNbDecTop": { "scicBlk23En": 0, @@ -867,6 +874,7 @@ "channelType": 0, "adcType": 1, "lpAdcCalMode": 0, + "gainTableType": 0, "rxDpProfile": { "rxNbDecTop": { "scicBlk23En": 0, @@ -1245,17 +1253,17 @@ } ], "pfirRxMagLowTiaLowSRHp": [ { "numCoeff": 21, - "coefficients": [ -12, 83, -293, 734, -1489, 2594, -3965, 5403, -6516, 5868, 27957, 5868, -6516, 5403, -3965, 2594, -1489, 734, -293, 83, -12 ] + "coefficients": [ -346, 1329, -1178, -1281, 1308, 2727, -1341, -5852, -1018, 12236, 19599, 12236, -1018, -5852, -1341, 2727, 1308, -1281, -1178, 1329, -346 ] }, { "numCoeff": 21, - "coefficients": [ -12, 83, -293, 734, -1489, 2594, -3965, 5403, -6516, 5868, 27957, 5868, -6516, 5403, -3965, 2594, -1489, 734, -293, 83, -12 ] + "coefficients": [ -346, 1329, -1178, -1281, 1308, 2727, -1341, -5852, -1018, 12236, 19599, 12236, -1018, -5852, -1341, 2727, 1308, -1281, -1178, 1329, -346 ] } ], "pfirRxMagLowTiaHighSRHp": [ { "numCoeff": 21, - "coefficients": [ -62, 194, 80, -829, 201, 1857, -179, -4602, -1259, 11431, 19102, 11431, -1259, -4602, -179, 1857, 201, -829, 80, 194, -62 ] + "coefficients": [ -2474, 892, 6049, 4321, -7599, -15881, -6074, 13307, 18926, 6338, -2843, 6338, 18926, 13307, -6074, -15881, -7599, 4321, 6049, 892, -2474 ] }, { "numCoeff": 21, - "coefficients": [ -62, 194, 80, -829, 201, 1857, -179, -4602, -1259, 11431, 19102, 11431, -1259, -4602, -179, 1857, 201, -829, 80, 194, -62 ] + "coefficients": [ -2474, 892, 6049, 4321, -7599, -15881, -6074, 13307, 18926, 6338, -2843, 6338, 18926, 13307, -6074, -15881, -7599, 4321, 6049, 892, -2474 ] } ], "pfirRxMagHighTiaHighSRHp": [ { "numCoeff": 21, @@ -1266,17 +1274,17 @@ } ], "pfirRxMagLowTiaLowSRLp": [ { "numCoeff": 21, - "coefficients": [ -12, 83, -293, 733, -1488, 2593, -3963, 5401, -6514, 5870, 27953, 5870, -6514, 5401, -3963, 2593, -1488, 733, -293, 83, -12 ] + "coefficients": [ -346, 1329, -1178, -1281, 1308, 2727, -1341, -5851, -1018, 12236, 19599, 12236, -1018, -5851, -1341, 2727, 1308, -1281, -1178, 1329, -346 ] }, { "numCoeff": 21, - "coefficients": [ -12, 83, -293, 733, -1488, 2593, -3963, 5401, -6514, 5870, 27953, 5870, -6514, 5401, -3963, 2593, -1488, 733, -293, 83, -12 ] + "coefficients": [ -346, 1329, -1178, -1281, 1308, 2727, -1341, -5851, -1018, 12236, 19599, 12236, -1018, -5851, -1341, 2727, 1308, -1281, -1178, 1329, -346 ] } ], "pfirRxMagLowTiaHighSRLp": [ { "numCoeff": 21, - "coefficients": [ -62, 194, 80, -828, 201, 1855, -180, -4597, -1254, 11428, 19093, 11428, -1254, -4597, -180, 1855, 201, -828, 80, 194, -62 ] + "coefficients": [ -2473, 892, 6048, 4321, -7598, -15879, -6072, 13306, 18924, 6338, -2843, 6338, 18924, 13306, -6072, -15879, -7598, 4321, 6048, 892, -2473 ] }, { "numCoeff": 21, - "coefficients": [ -62, 194, 80, -828, 201, 1855, -180, -4597, -1254, 11428, 19093, 11428, -1254, -4597, -180, 1855, 201, -828, 80, 194, -62 ] + "coefficients": [ -2473, 892, 6048, 4321, -7598, -15879, -6072, 13306, 18924, 6338, -2843, 6338, 18924, 13306, -6072, -15879, -7598, 4321, 6048, 892, -2473 ] } ], "pfirRxMagHighTiaHighSRLp": [ { "numCoeff": 21, diff --git a/firmware/Navassa_EvaluationFw.bin b/firmware/Navassa_EvaluationFw.bin index 730e3be79b2cb55db88669a7f941170e713fd2de..4d05aa885cafb64c5ad1516ae4cd24bb41cdbbfc 100644 GIT binary patch delta 83203 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 Date: Thu, 23 Dec 2021 10:04:34 +0100 Subject: [PATCH 204/407] iio: adrv9002: api: fix -Wframe-larger-than= for arm builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the frame larger than warning when building for arm. Signed-off-by: Nuno Sá --- .../adrv9001/private/src/adrv9001_arm.c | 84 +++++++++++-------- .../adrv9001/public/src/adi_adrv9001_cals.c | 18 +++- .../adrv9001/public/src/adi_adrv9001_rx.c | 72 ++++++++-------- 3 files changed, 101 insertions(+), 73 deletions(-) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c b/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c index 70265f5341d423..9f162219fa0500 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c @@ -36,6 +36,10 @@ #include "adrv9001_reg_addr_macros.h" #include "adrv9001_bf.h" #include "adi_adrv9001_hal.h" +#ifdef __KERNEL__ +#include +#endif + /* Header files related to libraries */ @@ -101,8 +105,8 @@ const char* const adrv9001_error_table_CmdCtrlMboxCmdError[] = "Command error" }; -const char* const adrv9001_error_table_CmdError[] = -{ +const char* const adrv9001_error_table_CmdError[] = +{ "Error occurred during an Init Calibration. Check that no signal is being applied to the Rx ports. Check that " "correct external LOs are applied, and synchronized, where appropriate", "Error occurred during a Tracking Calibration. Disable tracking calibrations, reset and program. If enabled " @@ -251,7 +255,7 @@ static __maybe_unused int32_t adrv9001_DmaMemReadByte(adi_adrv9001_Device_t *dev } regRead |= ADRV9001_DMA_CTL_LEGACY_MODE; - + /* bus size, 2'b00=byte; 2'b01=half-word; 2'b10=full-word; 2'b11=invalid */ /* core_bf.bus_size.write(bf_status, 2'b10); */ regRead |= ADRV9001_BF_ENCODE(0, ADRV9001_DMA_CTL_BUS_SIZE_MASK, ADRV9001_DMA_CTL_BUS_SIZE_SHIFT); @@ -323,7 +327,7 @@ static __maybe_unused int32_t adrv9001_DmaMemReadByte(adi_adrv9001_Device_t *dev returnData[i + 1] = dataRead0; ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_2", ADRV9001_ADDR_ARM_DMA_DATA2, &dataRead0); returnData[i + 2] = dataRead0; - + /* 'single_instruction' has to be cleared before reading DMA_DATA3 and set back after */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x0); ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_3", ADRV9001_ADDR_ARM_DMA_DATA3, &dataRead0); @@ -1040,7 +1044,7 @@ static void adrv9001_LoadSsiConfig(adi_adrv9001_Device_t *device, uint32_t *offs cfgData[tempOffset++] = (uint8_t)ssiConfig->cmosClkInversionEn; cfgData[tempOffset++] = (uint8_t)ssiConfig->ddrEn; - + cfgData[tempOffset++] = (uint8_t)ssiConfig->rxMaskStrobeEn; /* 4 bytes of padding is needed for alignment */ @@ -1561,15 +1565,15 @@ typedef struct duplexMode_e duplexMode; uint8_t fhModeOn; uint8_t reserved1[1u]; //< Reserved for future feature - uint8_t numDynamicProfile; // Number of Profile. =1 means only one profile and no switching + uint8_t numDynamicProfile; // Number of Profile. =1 means only one profile and no switching mcsMode_e mcsMode; // MCS mode selection: 0 - Disable, 1 - MCS Only, 2 - MCS + RFPLL phase sync - adcType_e adcTypeMonitor; // ADC type used in Monitor Mode - uint16_t pllLockTime_us; // Required lock time in microseconds for PLLs, based on ref_clk and loop bandwidth - pllModulus_t pllModuli; // PLL moduli - uint16_t pllPhaseSyncWait_us; // Worst case phase sync wait time in FH - mcsInf_e mcsInterfaceType; // 0-Disabled, 1-CMOS, 2-LVDS - uint8_t warmBootEnable; // Enable WarmBoot - Load initCal cefficients instead of running initCals - uint32_t reserved[1u]; // Reserved for future feature + adcType_e adcTypeMonitor; // ADC type used in Monitor Mode + uint16_t pllLockTime_us; // Required lock time in microseconds for PLLs, based on ref_clk and loop bandwidth + pllModulus_t pllModuli; // PLL moduli + uint16_t pllPhaseSyncWait_us; // Worst case phase sync wait time in FH + mcsInf_e mcsInterfaceType; // 0-Disabled, 1-CMOS, 2-LVDS + uint8_t warmBootEnable; // Enable WarmBoot - Load initCal cefficients instead of running initCals + uint32_t reserved[1u]; // Reserved for future feature } deviceSysConfig_t; */ static void adrv9001_DeviceSysConfigWrite(adi_adrv9001_Device_t *device, const adi_adrv9001_DeviceSysConfig_t *sysConfig, uint8_t cfgData[], uint32_t *offset) @@ -1607,13 +1611,13 @@ static void adrv9001_DeviceSysConfigWrite(adi_adrv9001_Device_t *device, const a { adrv9001_LoadFourBytes(&tempOffset, cfgData, sysConfig->pllModulus.dmModulus[i]); } - + /* PLL phase sync wait time in us */ adrv9001_LoadTwoBytes(&tempOffset, cfgData, sysConfig->pllPhaseSyncWait_us); cfgData[tempOffset++] = sysConfig->mcsInterfaceType; cfgData[tempOffset++] = sysConfig->warmBootEnable; - + /* 4 bytes padding; Reserved for future use */ tempOffset += 4; @@ -1990,7 +1994,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co uint8_t singleInstruction = 0; uint8_t spiMode = 0; uint8_t spiConfig_A = 0; - + ADI_ENTRY_PTR_ARRAY_EXPECT(device, data, byteCount); ADRV9001_DMAINFO("ARM_MEM_WRITE", armMemAddress, byteCount); @@ -2009,7 +2013,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co /* If Address is not on word boundary, Or ByteCount is not on Word boundary */ if (((armMemAddress & 0x00000003) > 0) || ((byteCount & 0x00000003) > 0)) { - if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || + if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || (ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4 == spiWriteMode)) { ADI_ERROR_REPORT(&device->common, @@ -2053,7 +2057,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co /* setting up the DMA control register for a write */ ADRV9001_SPIWRITEBYTEDMA(device, "ARM_DMA_CTL", ADRV9001_ADDR_ARM_DMA_CTL, regWrite); - + /* Enable single instruction and disable SPI streaming mode by default. * If ADRV9001 SPI streming mode is selected, then single instruction and single instruction are disbled */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x1); @@ -2176,15 +2180,25 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop uint32_t dataIndex = 0; uint32_t spiBufferSize = ((HAL_SPIWRITEARRAY_BUFFERSIZE / 3) - 1); uint8_t spiWriteArrray[HAL_SPIWRITEARRAY_BUFFERSIZE] = { 0 }; + uint32_t ADDR_ARM_DMA_DATA[4] = { ADRV9001_ADDR_ARM_DMA_DATA3, ADRV9001_ADDR_ARM_DMA_DATA2, ADRV9001_ADDR_ARM_DMA_DATA1, ADRV9001_ADDR_ARM_DMA_DATA0 }; + uint32_t index = 0; +#ifndef __KERNEL__ uint8_t addrMsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; uint8_t addrLsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; uint8_t dataArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; - uint32_t ADDR_ARM_DMA_DATA[4] = { ADRV9001_ADDR_ARM_DMA_DATA3, ADRV9001_ADDR_ARM_DMA_DATA2, ADRV9001_ADDR_ARM_DMA_DATA1, ADRV9001_ADDR_ARM_DMA_DATA0 }; - uint32_t index = 0; - +#else + static uint8_t addrMsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; + static uint8_t addrLsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; + static uint8_t dataArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; + + memset(addrMsbArray, 0, sizeof(addrMsbArray)); + memset(addrLsbArray, 0, sizeof(addrLsbArray)); + memset(dataArray, 0, sizeof(dataArray)); +#endif + ADI_ENTRY_PTR_ARRAY_EXPECT(device, numHopTableEntries, numHopTableEntriesByteCount); ADI_ENTRY_PTR_ARRAY_EXPECT(device, hopTableBufferData, hopTableBufferDataByteCount); - + /* Trigger appropriate SPI Interrupt upon table load */ if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) { @@ -2200,7 +2214,7 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop } ADRV9001_DMAINFO("ARM_MEM_WRITE", armMemAddress, byteCount); - + regWrite &= ~ADRV9001_DMA_CTL_RD_WRB; regWrite |= ADRV9001_DMA_CTL_SYS_CODEB; regWrite |= ADRV9001_BF_ENCODE(2, ADRV9001_DMA_CTL_BUS_SIZE_MASK, ADRV9001_DMA_CTL_BUS_SIZE_SHIFT); @@ -2248,7 +2262,7 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop dataArray[addrIndex] = numHopTableEntries[dataIndex]; addrIndex++; } - + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR3 >> 8) & 0x7F)); addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR3; dataArray[addrIndex] = (uint8_t)((hopTableBufferAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR3_BYTE_SHIFT); @@ -2398,7 +2412,7 @@ int32_t adrv9001_DmaMemRead(adi_adrv9001_Device_t *device, uint32_t address, uin returnData[i + 2] = dataRead; ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_1", ADRV9001_ADDR_ARM_DMA_DATA1, &dataRead); returnData[i + 1] = dataRead; - + /* 'single_instruction' has to be cleared before reading DMA_DATA3 and set back after */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x0); ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_0", ADRV9001_ADDR_ARM_DMA_DATA0, &dataRead); @@ -2463,7 +2477,7 @@ int32_t adrv9001_FlexStreamProcessorMemWrite(adi_adrv9001_Device_t *device, /* If Address is not on word boundary, Or ByteCount is not on Word boundary */ if (((flexSpAddress & 0x00000003) > 0) || ((byteCount & 0x00000003) > 0)) { - if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || + if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || (ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4 == spiWriteMode)) { ADI_ERROR_REPORT(&device->common, @@ -2498,7 +2512,7 @@ int32_t adrv9001_FlexStreamProcessorMemWrite(adi_adrv9001_Device_t *device, /* setting up the flex SP DMA control register for a write */ ADRV9001_SPIWRITEBYTEDMA(device, "FLEX_SP_ARM_DMA_CTL", ADRV9001_ADDR_FLEX_SP_ARM_DMA_CTL, regWrite); - + /* Enable single instruction and disable SPI streaming mode by default. * If ADRV9001 SPI streming mode is selected, then single instruction and single instruction are disbled */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x1); @@ -2761,7 +2775,7 @@ static const char* adrv9001_CmdErrMsgGet(uint32_t errCode) { return adrv9001_error_table_CmdError[6]; } - + return NULL; } @@ -2818,7 +2832,7 @@ int32_t adrv9001_ArmCmdErrorHandler(adi_adrv9001_Device_t *device, uint32_t detE ADI_EXPECT(adrv9001_ArmMailBoxErrCodeGet, device, &mailboxErrCode); errorString = adrv9001_CmdErrMsgGet(mailboxErrCode); - + ADI_ERROR_REPORT(&device->common, ADI_ADRV9001_SRC_ARMCMD, mailboxErrCode, @@ -2920,7 +2934,7 @@ static uint32_t adrv9001_ArmProfileWrite_Validate(adi_adrv9001_Device_t *device, ADI_ERROR_RETURN(device->common.error.newAction); } } - + /* Range check parameters in adi_adrv9001_TxSettings_t */ for (i = 0; i < ADI_ADRV9001_MAX_TXCHANNELS; i++) { @@ -2936,7 +2950,7 @@ static uint32_t adrv9001_ArmProfileWrite_Validate(adi_adrv9001_Device_t *device, ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.ssiDataFormatSel, ADI_ADRV9001_SSI_FORMAT_2_BIT_SYMBOL_DATA, ADI_ADRV9001_SSI_FORMAT_22_BIT_I_Q_DATA_1_BIT_GAIN_CHANGE_8_BIT_GAIN_INDEX); ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.numLaneSel, ADI_ADRV9001_SSI_1_LANE, ADI_ADRV9001_SSI_4_LANE); ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.strobeType, ADI_ADRV9001_SSI_SHORT_STROBE, ADI_ADRV9001_SSI_LONG_STROBE); - + if ((ADI_ADRV9001_SSI_TYPE_LVDS == init->tx.txProfile[i].txSsiConfig.ssiType) && (false == init->tx.txProfile[i].txSsiConfig.ddrEn) && (init->tx.txProfile[i].txInterfaceSampleRate_Hz > 30720000)) @@ -3113,7 +3127,7 @@ int32_t adrv9001_ArmProfileWrite(adi_adrv9001_Device_t *device, const adi_adrv90 cfgData[offset++] = (uint8_t)(init->clocks.armPowerSavingClkDiv - 1); cfgData[offset++] = (uint8_t)init->clocks.refClockOutEnable; - + cfgData[offset++] = (uint8_t)init->clocks.auxPllPower; cfgData[offset++] = (uint8_t)init->clocks.clkPllPower; @@ -3172,14 +3186,14 @@ int32_t adrv9001_ArmProfileWrite(adi_adrv9001_Device_t *device, const adi_adrv90 if (ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_TX_PROFILE_VALID)) { armChannels |= (init->tx.txInitChannelMask & (ADI_ADRV9001_TX1 | ADI_ADRV9001_TX2)); - + /* Tx channels must have a valid and enabled ILB channel unless the signaling is Direct FM/FSK */ if(ADRV9001_BF_EQUAL(init->tx.txInitChannelMask, ADI_ADRV9001_TX1) && (init->tx.txProfile[0].outputSignaling != ADI_ADRV9001_TX_DIRECT_FM_FSK)) { armChannels |= (init->rx.rxInitChannelMask & ADI_ADRV9001_ILB1); } - + if (ADRV9001_BF_EQUAL(init->tx.txInitChannelMask, ADI_ADRV9001_TX2) && (init->tx.txProfile[1].outputSignaling != ADI_ADRV9001_TX_DIRECT_FM_FSK)) { @@ -3468,7 +3482,7 @@ int32_t adrv9001_DynamicProfile_Write(adi_adrv9001_Device_t *device, int32_t recoveryAction = ADI_COMMON_ACT_NO_ACTION; uint32_t offset = 0; uint8_t cfgData[ADRV9001_DYNAMIC_PROFILE_BLOB_SIZE] = { 0 }; - + cfgData[offset++] = dynamicProfile->dynamicProfileIndex; cfgData[offset++] = 0; // padding cfgData[offset++] = 0; // padding diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c index a9c98a5cc56eb6..aaed72048c6bd1 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c @@ -781,9 +781,14 @@ int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Get(adi_adrv9001_Device uint32_t maskChannel2) { uint32_t tblSize[4]; - uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY] = { 0 }; +#ifndef __KERNEL__ + uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY] = { 0 }; uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; - int calNo; +#else + static uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY]; + static uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; +#endif + int calNo; ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0]*16, 1); @@ -822,9 +827,14 @@ int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Set(adi_adrv9001_Device uint32_t maskChannel2) { uint32_t tblSize[4]; - uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY] = { 0 }; +#ifndef __KERNEL__ + uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY] = { 0 }; uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; - int calNo; +#else + static uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY]; + static uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; +#endif + int calNo; ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0]*16, 1); diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c index 4f96e46e502527..3e3e0bfa9fee53 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c @@ -98,7 +98,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Write_Val // Maximum combined gain step must not exceed 29000 mdB ADI_RANGE_CHECK(device, totalGainSteps, 0, 29000); } - + /*Check that the gain index offset is within range*/ ADI_RANGE_CHECK(device, gainIndexOffset, ADI_ADRV9001_MIN_RX_GAIN_TABLE_INDEX, ADI_ADRV9001_START_RX_GAIN_INDEX); @@ -126,7 +126,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Write_Val } ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + ADI_RANGE_CHECK(device, gainTableType, ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE, ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE); /*Check that Rx profile or ORx profile is valid*/ @@ -174,7 +174,11 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, int32_t j = 0; uint16_t numGainIndicesToWrite = 0; uint8_t lnaStepOffset = { 0 }; +#ifdef __KERNEL__ + static adi_adrv9001_RxGainTableRow_t lnaGainTable[127]; +#else adi_adrv9001_RxGainTableRow_t lnaGainTable[127] = { { 0 } }; +#endif adi_adrv9001_RxGainTableRow_t *gainTablePtr = NULL; uint8_t minGainIndex = 0; uint8_t indexOffset = 0; @@ -199,7 +203,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, { if (i == 0) { - lnaStepOffset = (gainIndexOffset - (lnaConfig->minGainIndex - 1)); + lnaStepOffset = (gainIndexOffset - (lnaConfig->minGainIndex - 1)); } else { @@ -223,7 +227,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, } gainTablePtr = lnaGainTable; } - + baseIndex = (gainIndexOffset - (numGainIndicesToWrite - 1)); minGainIndex = (uint8_t)baseIndex; ADI_EXPECT(adrv9001_RxGainTableFormat, device, gainTablePtr, &armDmaData[0], numGainIndicesToWrite); @@ -327,7 +331,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Read_Vali ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcMinimumGainIndex_Get, device, instance, &minGainIndex); ADI_RANGE_CHECK(device, gainIndexOffset, minGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); - + if (((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_RX_PROFILE_VALID)) == 0) && ((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_ORX_PROFILE_VALID)) == 0) && ((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_TX_PROFILE_VALID)) == 0)) @@ -473,7 +477,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); adi_common_channel_to_index(channel, &chan_idx); - + /* Check that Rx profile is valid */ if (0 == ADRV9001_BF_EQUAL(device->devStateInfo.initializedChannels, RX_CHANNELS[chan_idx])) { @@ -492,7 +496,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcMinimumGainIndex_Get, device, instance, &minGainIndex); ADI_RANGE_CHECK(device, gainIndex, minGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); - + /* Save the current gain control mode and set to the required mode */ ADI_EXPECT(adi_adrv9001_Rx_GainControl_Mode_Get, device, channel, gainCtrlMode); if (ADI_ADRV9001_RX_GAIN_CONTROL_MODE_SPI != *gainCtrlMode) @@ -670,7 +674,7 @@ static __maybe_unused int32_t adi_adrv9001_Rx_InterfaceGain_Validate(adi_adrv900 adi_adrv9001_RxInterfaceGain_e rxInterfaceGainMax = ADI_ADRV9001_RX_INTERFACE_GAIN_NEGATIVE_36_DB; adi_common_channel_to_index(channel, &chan_index); - + if (device->devStateInfo.rxOutputRate_kHz[chan_index] < RX_OUTPUT_RATE_kHZ) { if (gainTableType == ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE) @@ -709,7 +713,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Confi adi_adrv9001_RxInterfaceGainCtrl_t *rxInterfaceGainCtrl) { adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&device->common, rxInterfaceGainCtrl); @@ -740,11 +744,11 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Confi rxInterfaceGainCtrl->rssiMovingAverageDuration, 1, 10); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); if (ADI_ADRV9001_CHANNEL_CALIBRATED != state) { - ADI_ERROR_REPORT(device, + ADI_ERROR_REPORT(device, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -823,12 +827,12 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Set_V /* Perform Range check of allowed gain value */ ADI_EXPECT(adi_adrv9001_Rx_InterfaceGain_Validate, device, channel, gainTableType, gain); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); if ((ADI_ADRV9001_CHANNEL_PRIMED != state) && (ADI_ADRV9001_CHANNEL_RF_ENABLED != state)) { - ADI_ERROR_REPORT(device, + ADI_ERROR_REPORT(device, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -1446,12 +1450,12 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_PortSwitch_Configur } /* NULL pointer check */ - ADI_NULL_PTR_RETURN(&device->common, switchConfig); + ADI_NULL_PTR_RETURN(&device->common, switchConfig); /* Freuqency range check */ - ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); - ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); - ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); /* Min frequency must be smaller than max */ @@ -1479,7 +1483,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_PortSwitch_Configur "Port A and B freuqency ranges cannot overlap."); ADI_API_RETURN(device) } - + ADI_API_RETURN(device); } @@ -1488,7 +1492,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Configure(adi_adrv9001_Device_t *device, { uint8_t armData[42] = { 0 }; uint8_t extData[3] = { 0 }; - uint32_t offset = 0u; + uint32_t offset = 0u; ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_PortSwitch_Configure_Validate, device, switchConfig); @@ -1513,7 +1517,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Configure(adi_adrv9001_Device_t *device, extData[0] = 0; extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_CFG_RX_PORT_SWITCHING; - + ADI_EXPECT(adi_adrv9001_arm_Config_Write, device, armData, sizeof(armData), extData, sizeof(extData)) ADI_API_RETURN(device); @@ -1536,7 +1540,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Inspect(adi_adrv9001_Device_t *device, ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_PortSwitch_Inspect_Validate, device, switchConfig); ADI_EXPECT(adi_adrv9001_arm_Config_Read, device, OBJID_CFG_RX_PORT_SWITCHING, channelMask, offset, armReadBack, sizeof(armReadBack)) - + adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->minFreqPortA_Hz); adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->maxFreqPortA_Hz); adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->minFreqPortB_Hz); @@ -1559,7 +1563,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_RANGE_CHECK(device, gainTableType, ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE, ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE); ADI_NULL_PTR_RETURN(&device->common, lnaConfig); - + if (!lnaConfig->externalLnaPresent) { ADI_ERROR_REPORT(&device->common, @@ -1586,7 +1590,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu ADI_RANGE_CHECK(device, lnaConfig->numberLnaGainSteps, 2, 4); //ADI_RANGE_CHECK(device, lnaConfig->settlingDelay, 0, 0); //ADI_RANGE_CHECK(device, lnaConfig->lnaDigitalGainDelay, 0, 0); - + if(0 != lnaConfig->lnaGainSteps_mdB[0]) { ADI_ERROR_REPORT(&device->common, @@ -1597,7 +1601,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu "lnaConfig->lnaGainSteps_mdB[0] should have the gain step as '0' only"); ADI_ERROR_RETURN(device->common.error.newAction); } - + for (i = 1; i < lnaConfig->numberLnaGainSteps; i++) { if ((lnaConfig->lnaGainSteps_mdB[i] == 0) || ((lnaConfig->lnaGainSteps_mdB[i] % 500) != 0)) @@ -1681,12 +1685,12 @@ int32_t adi_adrv9001_Rx_ExternalLna_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapRxb_FeGainDelayIncr_Set, device, rxbAddr, (lnaConfig->lnaDigitalGainDelay + FEGAIN_INCR_FIXED_VALUE)); ADI_EXPECT(adrv9001_NvsRegmapRxb_FeGainDelayDecr_Set, device, rxbAddr, (lnaConfig->lnaDigitalGainDelay + FEGAIN_DECR_FIXED_VALUE)); ADI_EXPECT(adrv9001_NvsRegmapRx_ExtLnaDigitalGainDelay_Set, device, rxAddr, (lnaConfig->lnaDigitalGainDelay + EXTDIGGAIN_DELAY_FIXED_VALUE)); - + if (ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE == gainTableType) { ADI_EXPECT(adrv9001_NvsRegmapRx_GainCompForExtGain_Set, device, rxAddr, (uint8_t)lnaConfig->externalLnaPresent); } - + ADI_API_RETURN(device); } @@ -1774,11 +1778,11 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Loid_Configure_Vali adi_adrv9001_RadioState_t state = { 0 }; uint8_t port_index = 0; uint8_t chan_index = 0; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, loidConfig); - + /* Validate state is STANDBY or CALIBRATED*/ ADI_EXPECT(adi_adrv9001_Radio_State_Get, adrv9001, &state); adi_common_port_to_index(ADI_RX, &port_index); @@ -1813,7 +1817,7 @@ int32_t adi_adrv9001_Rx_Loid_Configure(adi_adrv9001_Device_t *adrv9001, /* Write LOID config to ARM mailbox */ ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_SET, &armData[0], sizeof(armData), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_RX, channel); extData[1] = OBJID_GS_LOID; @@ -1825,14 +1829,14 @@ int32_t adi_adrv9001_Rx_Loid_Configure(adi_adrv9001_Device_t *adrv9001, extData[1], (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_TIMEOUT_US, (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_INTERVAL_US); - + ADI_API_RETURN(adrv9001); } static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Loid_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) -{ +{ ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, loidConfig); @@ -1844,9 +1848,9 @@ int32_t adi_adrv9001_Rx_Loid_Inspect(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) { - uint8_t armReadBack[4] = { 0 }; + uint8_t armReadBack[4] = { 0 }; uint8_t extData[2] = { 0 }; - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_RX, channel); extData[1] = OBJID_GS_LOID; @@ -1865,7 +1869,7 @@ int32_t adi_adrv9001_Rx_Loid_Inspect(adi_adrv9001_Device_t *adrv9001, &armReadBack[0], sizeof(armReadBack), ADRV9001_ARM_MEM_READ_AUTOINCR) - + loidConfig->loidEnable = armReadBack[0]; loidConfig->loidThreshold_negdBFS = armReadBack[2] + 6; From c63838aa4dbac065a523ce92447b8c443d95ee92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 23 Dec 2021 10:05:18 +0100 Subject: [PATCH 205/407] iio: adrv9002: api: fix mixed code declarations warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the mixed code declarations warnings for platforms using C90 where it is forbidden. Example of this is compiling the API under the linux kernel. Signed-off-by: Nuno Sá --- .../adrv9001/public/src/adi_adrv9001_arm.c | 14 +- .../adrv9001/public/src/adi_adrv9001_cals.c | 13 +- .../adrv9001/public/src/adi_adrv9001_fh.c | 146 +++++++++--------- .../adrv9001/public/src/adi_adrv9001_tx.c | 109 ++++++------- 4 files changed, 143 insertions(+), 139 deletions(-) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c index 45e4953265aef9..ebb60ce9f97df3 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c @@ -373,7 +373,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_arm_Memory_ReadWrite_V "Invalid parameter value. byteCount must be a multiple of 4 when using autoIncrement"); ADI_ERROR_RETURN(device->common.error.newAction); } - + ADI_RANGE_CHECK(device, spiWriteMode, ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4, ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4); ADI_API_RETURN(device); } @@ -398,7 +398,7 @@ int32_t adi_adrv9001_arm_Memory_Read32(adi_adrv9001_Device_t *device, uint8_t autoIncrement) { //uint8_t data[] = { 0 }; - + ADI_PERFORM_VALIDATION(adi_adrv9001_arm_Memory_ReadWrite_Validate, device, address, (uint8_t *)returnData, byteCount, 0, autoIncrement); ADI_EXPECT(adrv9001_DmaMemRead, device, address, (uint8_t *)returnData, byteCount, autoIncrement); @@ -1156,6 +1156,7 @@ int32_t adi_adrv9001_arm_System_Program(adi_adrv9001_Device_t *device, uint8_t c int elbFlgShift = 5; //ELB flag shift from FW bit position, lsb bit 3, to API bit position ADRV9001_ELB1 int txFlgShiftUp = 3; // TX enable flag, lsb bit 5 int adcPortBFlg = 64; // ADC port B enable flag, lsb bit 6 + adi_adrv9001_RxPortSwitchCfg_t portSwitchCfg = { 0 }; /* Check device pointer is not null */ ADI_ENTRY_EXPECT(device); @@ -1184,7 +1185,6 @@ int32_t adi_adrv9001_arm_System_Program(adi_adrv9001_Device_t *device, uint8_t c } } - adi_adrv9001_RxPortSwitchCfg_t portSwitchCfg = { 0 }; ADI_EXPECT(adi_adrv9001_Rx_PortSwitch_Inspect, device, &portSwitchCfg); /*Mask for Channel 1 */ @@ -1193,7 +1193,7 @@ int32_t adi_adrv9001_arm_System_Program(adi_adrv9001_Device_t *device, uint8_t c ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ILB1) >> (ilbFlgShift)) | ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ELB1) >> (elbFlgShift)) | ((device->devStateInfo.initializedChannels & ADI_ADRV9001_TX1) << (txFlgShiftUp))); - + /*Mask for Channel 2 */ device->devStateInfo.chProfEnMask[1] = (((device->devStateInfo.initializedChannels & ADI_ADRV9001_RX2) >> 1) | ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ORX2) >> (orxFlgShift + 1)) | @@ -1206,7 +1206,7 @@ int32_t adi_adrv9001_arm_System_Program(adi_adrv9001_Device_t *device, uint8_t c device->devStateInfo.chProfEnMask[0] = device->devStateInfo.chProfEnMask[0] | adcPortBFlg; device->devStateInfo.chProfEnMask[1] = device->devStateInfo.chProfEnMask[1] | adcPortBFlg; } - + ADI_API_RETURN(device); } @@ -1425,12 +1425,12 @@ int32_t adi_adrv9001_arm_Start(adi_adrv9001_Device_t *device) { uint8_t armCtl1 = 0; uint8_t mailBox[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; - + ADI_ENTRY_EXPECT(device); /* Set MailBox 0xFF */ ADI_EXPECT(adi_adrv9001_arm_Memory_Write, device, ADRV9001_ADDR_ARM_MAILBOX_GET, &mailBox[0], 4, ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); - + armCtl1 = ADRV9001_AC1_ARM_DEBUG_ENABLE | ADRV9001_AC1_ARM_MEM_HRESP_MASK | ADRV9001_AC1_ARM_M3_RUN; ADRV9001_SPIWRITEBYTE(device, "ARM_CTL_1", ADRV9001_ADDR_ARM_CTL_1, armCtl1); diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c index aaed72048c6bd1..c306c3487b885d 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c @@ -76,7 +76,7 @@ int32_t adi_adrv9001_cals_InitCals_Run(adi_adrv9001_Device_t *adrv9001, /* Mode to select the Init calibration algorithms to run */ payload[1] = (uint8_t)(initCals->calMode); - + /* A value of true will force all enabled calibrations to re-run */ payload[2] = (uint8_t)(initCals->force); @@ -586,7 +586,7 @@ int32_t adi_adrv9001_cals_InternalPathDelay_Get_Validate(adi_adrv9001_Device_t * { static uint8_t MAX_NUM_PROFILE = 6; adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(adrv9001, port, ADI_RX, ADI_TX); ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, internalPathDelays_ns); @@ -594,7 +594,7 @@ int32_t adi_adrv9001_cals_InternalPathDelay_Get_Validate(adi_adrv9001_Device_t * ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, adrv9001, port, channel, &state); if (ADI_ADRV9001_CHANNEL_STANDBY == state) { - ADI_ERROR_REPORT(&adrv9001->common, + ADI_ERROR_REPORT(&adrv9001->common, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_INV_PARAM, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -726,7 +726,7 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate_Validate(adi_adrv9001_Devic ADI_ENTRY_PTR_EXPECT(adrv9001, initCals); ADI_NULL_PTR_RETURN(&adrv9001->common, errorFlag); - ADI_NULL_PTR_RETURN(&adrv9001->common, dynamicProfile); + ADI_NULL_PTR_RETURN(&adrv9001->common, dynamicProfile); ADI_RANGE_CHECK(adrv9001, length, 1, MAX_NUM_PROFILE); for (port = ADI_RX; port <= ADI_TX; port++) @@ -764,7 +764,7 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate(adi_adrv9001_Device_t *adrv { int8_t i = 0; ADI_EXPECT(adi_adrv9001_cals_Dynamic_profiles_calibrate_Validate, adrv9001, initCals, errorFlag, dynamicProfile, length); - + for (i = 0; i <= (length - 1); i++) { ADI_EXPECT(adi_adrv9001_arm_NextDynamicProfile_Set, adrv9001, &dynamicProfile[i]); @@ -808,8 +808,9 @@ int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Get(adi_adrv9001_Device continue; if (((initMask & chInitMask) != 0) && ((profMask & device->devStateInfo.chProfEnMask[channel - 1]) != 0)) { - ADI_EXPECT(adi_adrv9001_arm_Memory_Read, device, addr, calVal, size, 0); int calSize; + + ADI_EXPECT(adi_adrv9001_arm_Memory_Read, device, addr, calVal, size, 0); for (calSize = 0; calSize < size; calSize++) { savedCals->calValue[calNo][calSize] = calVal[calSize]; diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c index cb29a00a65a043..299e0b62998b32 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c @@ -59,7 +59,7 @@ if (device->devStateInfo.frequencyHoppingEnabled == 0) \ ADI_API_RETURN(device); \ } -/* TODO JP: Determine if we need to validate the whole table. +/* TODO JP: Determine if we need to validate the whole table. It's difficult to validate the hop table due to the following: 1) At the time of receiving the HOP table, we don't know the channel sequence. So a tx or rx gain index might be valid, or it might be a 'don't care' value, programmed by the user. We could potentially enforce the @@ -67,7 +67,7 @@ if (device->devStateInfo.frequencyHoppingEnabled == 0) \ 2) There doesn't seem a nice way to validate the rx gain in API, since there is no state of the FH operating gain range. The best we could do would be to ensure its within the absolute min/max. However, this could be effected by point 1. - 3) Validating the whole table before its written to ARM might be valuable, however, it might + 3) Validating the whole table before its written to ARM might be valuable, however, it might also waste time. Especially considering we can't validate every field in the table. It might be better for ARM to validate it once received, or on the fly. */ @@ -77,8 +77,8 @@ static __maybe_unused int32_t adi_adrv9001_fh_FrameInfo_Validate(adi_adrv9001_De /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); - ADI_RANGE_CHECK_X(adrv9001, hopFrame->hopFrequencyHz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, hopFrame->hopFrequencyHz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); ADI_API_RETURN(adrv9001); } @@ -97,11 +97,11 @@ static uint32_t adi_adrv9001_fh_GetHopTableBufferAddress(adi_adrv9001_Device_t * adrv9001_ParseFourBytes(&offset, hopTableBufferAddressBlock, &hopTableBufferAddress); return hopTableBufferAddress; -} +} static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) -{ +{ uint32_t i; uint32_t j; uint8_t numHopSignals; @@ -141,7 +141,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } /* Can be unassigned but throw an error if it's set to analog*/ ADI_RANGE_CHECK(adrv9001, fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[0].pin, ADI_ADRV9001_GPIO_UNASSIGNED, ADI_ADRV9001_GPIO_DIGITAL_15); - if ((fhConfig->hopTableSelectConfig.hopTableSelectMode == ADI_ADRV9001_FHHOPTABLESELECTMODE_INDEPENDENT) + if ((fhConfig->hopTableSelectConfig.hopTableSelectMode == ADI_ADRV9001_FHHOPTABLESELECTMODE_INDEPENDENT) && (fhConfig->mode == ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP)) { /* Can be unassigned but throw an error if it's set to analog*/ @@ -186,18 +186,18 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De "Value must be non-zero in Tx only operation"); ADI_API_RETURN(adrv9001); } - + /* Check mode*/ ADI_RANGE_CHECK(adrv9001, fhConfig->mode, ADI_ADRV9001_FHMODE_LO_MUX_PREPROCESS, ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP); /* Check tableIndexCtrl_e */ ADI_RANGE_CHECK(adrv9001, fhConfig->tableIndexCtrl, ADI_ADRV9001_TABLEINDEXCTRL_AUTO_LOOP, ADI_ADRV9001_TABLEINDEXCTRL_GPIO); /* Check operating frequency range */ - ADI_RANGE_CHECK_X(adrv9001, fhConfig->minOperatingFrequency_Hz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, fhConfig->minOperatingFrequency_Hz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); - ADI_RANGE_CHECK_X(adrv9001, fhConfig->maxOperatingFrequency_Hz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, fhConfig->maxOperatingFrequency_Hz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); if (fhConfig->minOperatingFrequency_Hz >= fhConfig->maxOperatingFrequency_Hz) @@ -211,12 +211,12 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De ADI_API_RETURN(adrv9001); } /* Check RX gain ranges */ - ADI_RANGE_CHECK(adrv9001, fhConfig->minRxGainIndex, - ADI_ADRV9001_RX_GAIN_INDEX_MIN, + ADI_RANGE_CHECK(adrv9001, fhConfig->minRxGainIndex, + ADI_ADRV9001_RX_GAIN_INDEX_MIN, fhConfig->maxRxGainIndex); /* Max index can be equal to min and no greater than rx1MaxGainIndex */ - ADI_RANGE_CHECK(adrv9001, fhConfig->maxRxGainIndex, - fhConfig->minRxGainIndex, + ADI_RANGE_CHECK(adrv9001, fhConfig->maxRxGainIndex, + fhConfig->minRxGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); /* TODO JP: Investigate requirements for TX attenuation in diversity mode. Will min/max be the same, or will we need a seperate field? @@ -245,7 +245,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } /* Check frequency select pins */ - if (ADI_ADRV9001_TABLEINDEXCTRL_GPIO == fhConfig->tableIndexCtrl) + if (ADI_ADRV9001_TABLEINDEXCTRL_GPIO == fhConfig->tableIndexCtrl) { ADI_RANGE_CHECK(adrv9001, fhConfig->numTableIndexPins, 1u, ADI_ADRV9001_FH_MAX_NUM_FREQ_SELECT_PINS); for (i = 0; i < fhConfig->numTableIndexPins; i++) @@ -254,13 +254,13 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } } /* Configure gain select pins */ - if (true == fhConfig->gainSetupByPin) + if (true == fhConfig->gainSetupByPin) { for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) { if ((initializedChannelMask & (j == 0? channel1Mask:channel2Mask)) != 0x00u) { - + ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].numGainCtrlPins, 1u, ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_PINS); for (i = 0; i < fhConfig->gainSetupByPinConfig[j].numGainCtrlPins; i++) { @@ -269,7 +269,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De maxPossibleGainEntries = (1u << fhConfig->gainSetupByPinConfig[j].numGainCtrlPins); } - + if (ADRV9001_BF_EQUAL(adrv9001->devStateInfo.initializedChannels, CHANNELS[ADI_RX][j])) { /* Validate Rx gain table is within range specified by fhConfig */ @@ -287,7 +287,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De { ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].txAttenTable[i], fhConfig->minTxAtten_mdB, fhConfig->maxTxAtten_mdB); } - } + } } } @@ -296,7 +296,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De static __maybe_unused int32_t adi_adrv9001_fh_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) -{ +{ /* Check for NULL pointer */ ADI_NULL_PTR_RETURN(&adrv9001->common, fhConfig); ADI_API_RETURN(adrv9001); @@ -305,12 +305,15 @@ static __maybe_unused int32_t adi_adrv9001_fh_Inspect_Validate(adi_adrv9001_Devi static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhMode_e mode, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t tableSize) { - uint32_t frequencyIndex = 0; + uint32_t frequencyIndex = 0; uint32_t tempAddress = 0; + uint8_t maxNumHopFrequencies = (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) ? ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE : + (ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE) / 2; + if (tableId == ADI_ADRV9001_FHHOPTABLE_A) { if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) @@ -333,8 +336,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate tempAddress = adrv9001->devStateInfo.fhHopTableB2Addr; } } - uint8_t maxNumHopFrequencies = (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) ? ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE : - (ADI_ADRV9001_FH_MAX_HOP_TABLE_SIZE) / 2; + /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); /* Check for NULL pointer */ @@ -354,7 +356,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate ADI_API_RETURN(adrv9001); } - if ((hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_2) + if ((hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_2) && (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP)) { ADI_ERROR_REPORT(&adrv9001->common, @@ -366,7 +368,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate ADI_API_RETURN(adrv9001); } - + /* Check fhHopTable->numHopFrames are valid */ ADI_RANGE_CHECK(adrv9001, tableSize, 1u, maxNumHopFrequencies); @@ -376,7 +378,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate } ADI_API_RETURN(adrv9001); -} +} static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal, @@ -428,7 +430,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Inspect_Validate(adi_adrv } ADI_API_RETURN(adrv9001); -} +} int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) @@ -474,7 +476,7 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, armData[offset++] = fhConfig->tableIndexCtrl; armData[offset++] = fhConfig->gainSetupByPin; armData[offset++] = fhConfig->hopTableSelectConfig.hopTableSelectMode; - + armData[offset++] = hop1SignalsPortMask; armData[offset++] = hop2SignalsPortMask; @@ -493,14 +495,14 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, armData[offset++] = fhConfig->rxZeroIfEnable; offset += 2u; /* padding */ /* If in gain select by pin mode, load Rx gain and Tx attenuation tables */ - if (fhConfig->gainSetupByPin == true) + if (fhConfig->gainSetupByPin == true) { /* Load Rx gain and Tx atten table */ armData[offset++] = fhConfig->gainSetupByPinConfig[0].numRxGainTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[1].numRxGainTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[0].numTxAttenTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[1].numTxAttenTableEntries; - /* Create a second offset variable to point to the Tx atten table location. + /* Create a second offset variable to point to the Tx atten table location. Rx gain index is 1 byte, so second offset is offset + (ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES * 1) */ tempOffset = offset + 2 * ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; @@ -575,7 +577,7 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, } } /* Configure gain index pins if selected */ - if (fhConfig->gainSetupByPin == true) + if (fhConfig->gainSetupByPin == true) { /* Configure ADRV9001 GPIOs */ for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) @@ -634,7 +636,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a fhConfig->tableIndexCtrl = armData[offset++]; fhConfig->gainSetupByPin = armData[offset++]; fhConfig->hopTableSelectConfig.hopTableSelectMode = armData[offset++]; - + hop1SignalsPortMask = armData[offset++]; offset++; fhConfig->rxPortHopSignals[0] = ((hop1SignalsPortMask & 0x1) == 1) ? ADI_ADRV9001_FH_HOP_SIGNAL_1 : ADI_ADRV9001_FH_HOP_SIGNAL_2; @@ -664,7 +666,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a { fhConfig->gainSetupByPinConfig[j].numTxAttenTableEntries = armData[offset++]; } - + tempOffset = offset + 2 * ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; /* Rx and Tx tables */ for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) @@ -701,13 +703,13 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP, &(fhConfig->hopSignalGpioConfig[0])); ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_TABLE_SELECT, &(fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[0])); - + if (fhConfig->mode == ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) { ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2, &(fhConfig->hopSignalGpioConfig[1])); ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2_TABLE_SELECT, &(fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[1])); } - + /* Inspect table index pins if selected */ if (fhConfig->tableIndexCtrl == ADI_ADRV9001_TABLEINDEXCTRL_GPIO) { @@ -730,7 +732,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhMode_e mode, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t hopTableSize) { @@ -740,7 +742,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 uint32_t frequencyIndex = 0; uint8_t numHopTableEntries[4u]; uint32_t hopTableBufferAddress = 0; - + /* ARM Data is written directly to ARM memory because FREQ_HOPPING_NUM_BYTES is greater than set buffer size */ #ifndef __KERNEL__ uint8_t armData[FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; @@ -778,8 +780,8 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 hopTableAddress = adrv9001->devStateInfo.fhHopTableB2Addr; hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB2Addr; } - } - + } + adrv9001_LoadFourBytes(&offset, numHopTableEntries, hopTableSize); offset = 0; for (frequencyIndex = 0; frequencyIndex < hopTableSize; frequencyIndex++) @@ -794,7 +796,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 armData[offset++] = hopTable[frequencyIndex].tx1Attenuation_fifthdB; armData[offset++] = hopTable[frequencyIndex].tx2Attenuation_fifthdB; } - + /* Write the data directly to the ARM memory */ /* 'offset' is used to represent the exact number of bytes to write to avoid writing over the entire table */ ADI_EXPECT(adi_adrv9001_arm_Memory_WriteFH, adrv9001, hopSignal, tableId, hopTableAddress, numHopTableEntries, sizeof(numHopTableEntries), hopTableBufferAddress, armData, offset); @@ -803,7 +805,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t hopTableSize, uint32_t *numHopFramesRead) @@ -830,7 +832,7 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, memset(&armData, 0, sizeof(armData)); #endif - + if (tableId == ADI_ADRV9001_FHHOPTABLE_A) { if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) @@ -856,10 +858,10 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, hopTableAddress = adrv9001->devStateInfo.fhHopTableB2Addr; hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB2Addr; } - } + } ADI_PERFORM_VALIDATION(adi_adrv9001_fh_HopTable_Inspect_Validate, adrv9001, hopSignal, tableId, hopTable, hopTableSize); - /* Even though we are going to read directly from ARM memory, we can still use the GET protocol to + /* Even though we are going to read directly from ARM memory, we can still use the GET protocol to tell ARM how many bytes we will read. ARM will return an error if the read size is invalid */ adrv9001_LoadFourBytes(&offset, armData, sizeof(armData)); @@ -875,7 +877,7 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, OBJID_GO_GET_FH_HOP_TABLE, ADI_ADRV9001_DEFAULT_TIMEOUT_US, ADI_ADRV9001_DEFAULT_INTERVAL_US); - + /* First read number of frequencies in hop table */ offset = 0; ADI_EXPECT(adi_adrv9001_arm_Memory_Read, adrv9001, hopTableAddress, numHopFrequenciesReadbackBlock, sizeof(numHopFrequenciesReadbackBlock), false); @@ -977,12 +979,12 @@ int32_t adi_adrv9001_fh_HopTable_Get(adi_adrv9001_Device_t *adrv9001, ADI_API_RETURN(adrv9001); } -int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, - adi_adrv9001_FhHopSignal_e fhHopSignal, - adi_adrv9001_FhFrameIndex_e frameIndex, - adi_adrv9001_FhHopFrame_t *hopFrame) +int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, + adi_adrv9001_FhHopSignal_e fhHopSignal, + adi_adrv9001_FhFrameIndex_e frameIndex, + adi_adrv9001_FhHopFrame_t *hopFrame) { - uint8_t armData[sizeof(adrv9001_FhHopFrame_t)] = { 0 }; + uint8_t armData[sizeof(adrv9001_FhHopFrame_t)] = { 0 }; uint8_t extData[5u] = { 0 }; uint32_t offset = 0; uint32_t hopFrequencyHz_LSB = 0; @@ -991,10 +993,10 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); ADI_NULL_PTR_RETURN(&adrv9001->common, hopFrame); - ADI_RANGE_CHECK(adrv9001, fhHopSignal, ADI_ADRV9001_FH_HOP_SIGNAL_1, ADI_ADRV9001_FH_HOP_SIGNAL_2); - ADI_RANGE_CHECK(adrv9001, frameIndex, ADI_ADRV9001_FHFRAMEINDEX_CURRENT_FRAME, ADI_ADRV9001_FHFRAMEINDEX_UPCOMING_FRAME); - - + ADI_RANGE_CHECK(adrv9001, fhHopSignal, ADI_ADRV9001_FH_HOP_SIGNAL_1, ADI_ADRV9001_FH_HOP_SIGNAL_2); + ADI_RANGE_CHECK(adrv9001, frameIndex, ADI_ADRV9001_FHFRAMEINDEX_CURRENT_FRAME, ADI_ADRV9001_FHFRAMEINDEX_UPCOMING_FRAME); + + /* Write the size to the GET buffer */ adrv9001_LoadFourBytes(&offset, armData, sizeof(armData)); ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_GET, armData, sizeof(uint32_t), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); @@ -1027,9 +1029,9 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, hopFrame->tx1Attenuation_fifthdB = armData[offset++]; hopFrame->tx2Attenuation_fifthdB = armData[offset++]; ADI_API_RETURN(adrv9001); -} +} -int32_t adi_adrv9001_fh_Hop(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_fh_Hop(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal) { /* Flip the hop signal */ @@ -1066,7 +1068,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_NumberOfHops_Get(adi_adrv9001_Devi default: ADI_SHOULD_NOT_EXECUTE(adrv9001); } - + ADI_API_RETURN(adrv9001); } @@ -1098,7 +1100,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure_Validat mode, "FH mode must be dual hop for hopSignal to be HOP_2 "); } - + } ADI_ENTRY_PTR_EXPECT(adrv9001, spiPackedFhTable); @@ -1126,7 +1128,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure_Validat ADI_COMMON_ACT_ERR_CHECK_PARAM, tableSize, "spiPackedFhTable[] size is not sufficient "); - + } for (frequencyIndex = 0; frequencyIndex < tableSize; frequencyIndex++) { @@ -1203,7 +1205,7 @@ static uint32_t adrv9001_HopTable_Spi_Pack(adi_adrv9001_Device_t *adrv9001, /* Issue SW interrupt 4 or 11 to load FH table A or B. The SPI reg is self-cleared so there is no need to do read/mod/write. */ adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADRV9001_ADDR_SW_INTERRUPT_4, bitmSwInt, ADRV9001_SPI_WRITE_POLARITY); - + /* Restore back the original values of ADRV9001 DMA control register */ adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADRV9001_ADDR_ARM_DMA_CTL, regVal, ADRV9001_SPI_WRITE_POLARITY); @@ -1243,10 +1245,10 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 if (ADI_ADRV9001_FH_HOP_SIGNAL_1 == hopSignal) { bitmSwInt_A = 0x1; - hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; armAddr_A = adrv9001->devStateInfo.fhHopTableA1Addr; - bitmSwInt_B = 0x80; + bitmSwInt_B = 0x80; hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; armAddr_B = adrv9001->devStateInfo.fhHopTableB1Addr; } @@ -1263,12 +1265,12 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 } else { - bitmSwInt_A = 0x1; - hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + bitmSwInt_A = 0x1; + hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; armAddr_A = adrv9001->devStateInfo.fhHopTableA1Addr; - bitmSwInt_B = 0x2; - hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; + bitmSwInt_B = 0x2; + hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; armAddr_B = adrv9001->devStateInfo.fhHopTableB1Addr; } @@ -1309,7 +1311,7 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 adrv9001_LoadTwoBytes(&offset, fhTable_A, hopTable[i + j].tx2Attenuation_fifthdB); } ADI_EXPECT(adrv9001_HopTable_Spi_Pack, adrv9001, addrArray_A, fhTable_A, numberOfHops, &numWrBytes, bitmSwInt_A, spiPackedFhTable); - + offset = 0; for (j = numberOfHops; j < (2 * numberOfHops); j++) { @@ -1355,7 +1357,7 @@ int32_t adi_adrv9001_fh_HopTable_BytesPerTable_Get(adi_adrv9001_Device_t *adrv90 ADI_EXPECT(adi_adrv9001_fh_NumberOfHops_Get, adrv9001, numberHopsPerDynamicLoad, &numberOfHops); spiPackBytesPerTable = spiConfigBytes + spiAddrPackLength + spiInterruptBytes; - + payloadBytes = ((sizeof(adrv9001_FhHopFrame_t) * numberOfHops) + fhBytesLength) * 3; *bytesPerTable = payloadBytes + spiPackBytesPerTable; @@ -1369,7 +1371,7 @@ int32_t adi_adrv9001_fh_RxOffsetFrequency_Set(adi_adrv9001_Device_t *adrv9001, a adrv9001_LoadFourBytes(&offset, rxOffsetFrequencyHzArray, rx2OffsetFrequencyHz); if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) { - + ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, FREQ_HOPPING_HOP1_OFFSET_FREQ_OVERWRITE_ADDR, rxOffsetFrequencyHzArray, sizeof(rxOffsetFrequencyHzArray), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); } else diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c index 8f77f25146008f..6d3c0e08a254e2 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c @@ -169,7 +169,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_AttenuationMode_Set currentState.channelStates[port_index][chan_index], "Error while attempting to set attenuation mode. Channel must be in STANDBY or CALIBRATED."); } - + /* Retrieve attenuation mode */ ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Get, device, channel, &txModeRead); if (txModeRead == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) @@ -196,14 +196,14 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Set(adi_adrv9001_Device_t *device, txChannelBaseAddr = Tx_Addr_Get(channel); device->devStateInfo.txAttenMode[channel - 1] = mode; - + if (mode == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) { mode = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI; } ADI_EXPECT(adrv9001_NvsRegmapTx_TxAttenMode_Set, device, txChannelBaseAddr, (uint8_t)mode); - + ADI_API_RETURN(device) } @@ -221,9 +221,10 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Get(adi_adrv9001_Device_t *device, adi_common_ChannelNumber_e channel, adi_adrv9001_TxAttenuationControlMode_e *mode) { - ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_AttenuationMode_Get_Validate, device, channel, mode); - adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; + + ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_AttenuationMode_Get_Validate, device, channel, mode); + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_TX, channel, &state); if (state == ADI_ADRV9001_CHANNEL_PRIMED) { @@ -962,9 +963,9 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat { int32_t txSampleRateDiv2_Hz = 0; adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + ADI_NULL_PTR_RETURN(&adrv9001->common, tone); if (tone->enable) { @@ -983,7 +984,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat "Channel state must be CALIBRATED"); } } - + ADI_API_RETURN(adrv9001); } @@ -994,7 +995,7 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Configure(adi_adrv9001_Device_t * uint8_t armData[12] = { 0 }; uint8_t extData[5] = { 0 }; uint32_t offset = 0; - + ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_InternalToneGeneration_Configure_Validate, adrv9001, channel, tone); adrv9001_LoadFourBytes(&offset, armData, sizeof(armData) - sizeof(uint32_t)); @@ -1002,7 +1003,7 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Configure(adi_adrv9001_Device_t * armData[offset++] = tone->amplitude; offset += 2; adrv9001_LoadFourBytes(&offset, armData, tone->frequency_Hz); - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_TX, channel); extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_CFG_TX_INTERNAL_TONE_GENERATION; @@ -1017,10 +1018,10 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat adi_adrv9001_TxInternalToneGeneration_t *tone) { adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, tone); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, adrv9001, ADI_TX, channel, &state); if (ADI_ADRV9001_CHANNEL_STANDBY == state) { @@ -1031,7 +1032,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat state, "Channel state must be any of CALIBRATED, PRIMED, RF_ENABLED"); } - + ADI_API_RETURN(adrv9001); } @@ -1042,12 +1043,12 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Inspect(adi_adrv9001_Device_t *ad uint8_t armReadBack[8] = { 0 }; uint8_t channelMask = 0; uint32_t offset = 0; - + ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_InternalToneGeneration_Inspect_Validate, adrv9001, channel, tone); channelMask = adi_adrv9001_Radio_MailboxChannel_Get(ADI_TX, channel); ADI_EXPECT(adi_adrv9001_arm_Config_Read, adrv9001, OBJID_CFG_TX_INTERNAL_TONE_GENERATION, channelMask, offset, armReadBack, sizeof(armReadBack)); - + tone->enable = (bool)armReadBack[offset++]; tone->amplitude = (adi_adrv9001_TxInternalToneAmplitude_e)armReadBack[offset++]; offset += 2; @@ -1205,7 +1206,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_PaRamp_Configure_Va { ADI_RANGE_CHECK(device, paRampCfg->gpioSource, ADI_ADRV9001_GPIO_UNASSIGNED, ADI_ADRV9001_GPIO_DIGITAL_15); } - + ADI_RANGE_CHECK(device, paRampCfg->rampClock_kHz, ADRV9001_TX_PA_RAMP_MIN_CLK_KHZ, ADRV9001_TX_PA_RAMP_MAX_CLK_KHZ); ADI_API_RETURN(device); @@ -1292,7 +1293,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, uint32_t refClk_Hz = 0; ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_PaRamp_Configure_Validate, device, channel, paRampCfg); - + // Use Analog RefClkDivRatio, DEVCLKOUT Divider not used here ADI_EXPECT(adrv9001_NvsRegmapCore3_RefClkIntDevclkDivideRatio_Get, device, &clkDivRatio); @@ -1300,9 +1301,9 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, refClk_Hz = KILO_TO_BASE_UNIT(device->devStateInfo.deviceClock_kHz) >> clkDivRatio; paRampDpClkDiv = DIV_ROUND_CLOSEST(refClk_Hz, KILO_TO_BASE_UNIT(paRampCfg->rampClock_kHz)); - + ADI_EXPECT(adi_adrv9001_AuxDac_Configure, device, paRampCfg->auxDacChannelSelect, paRampCfg->enable); - + switch (paRampCfg->auxDacChannelSelect) { case ADI_ADRV9001_AUXDAC0: @@ -1321,7 +1322,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_SHOULD_NOT_EXECUTE(device); break; } - + /* crossbar config for AUX DAC 0/1/2/3. Bit[0]: xbar 0 select: 1: TX2, 0: TX1 Bit[1]: xbar 1 select: 1: TX2, 0: TX1 @@ -1384,7 +1385,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, } muxSel = dataConfig; ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, muxSel); - + bfValue = (uint8_t) paRampCfg->triggerSelect; if (channel == ADI_CHANNEL_1) @@ -1397,14 +1398,14 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigStartDelay_Set, device, paRampCfg->triggerDelayRise); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigEndDelay_Set, device, paRampCfg->triggerDelayFall); // Set Ramp Clock to max for LUTWrite - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_ENABLE_PIN) - { + { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStopSel_Set, device, 0x1); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStopSel_Set, device, 0x1); @@ -1414,16 +1415,16 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStartSel_Set, device, bfValue); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStopSel_Set, device, bfValue); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStartSel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStopSel_Set, device, 0x0); } - + // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioSel_Set, device, (uint8_t)paRampCfg->gpioSource - 1); - - + + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_GPIO) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioMask_Set, device, 0x0); @@ -1449,16 +1450,16 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, /* Configure the delays */ ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigStartDelay_Set, device, paRampCfg->triggerDelayRise); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigEndDelay_Set, device, paRampCfg->triggerDelayFall); - + // Set Ramp Clock to max for LUTWrite - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + if (bfValue == 0x2) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStartSel_Set, device, 0x1); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, 0x1); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStopSel_Set, device, 0x1); @@ -1468,7 +1469,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStartSel_Set, device, bfValue); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, bfValue); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStartSel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStopSel_Set, device, 0x0); @@ -1477,7 +1478,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioSel_Set, device, (uint8_t)paRampCfg->gpioSource - 1); - + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_GPIO) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioMask_Set, device, 0x0); @@ -1487,7 +1488,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioMask_Set, device, 0x1); } - + /* Enable the clock only after all registers are configured */ ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Set, device, 0x1); @@ -1524,7 +1525,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_LutRdEnable_Set, device, 0x1); /* Read PA LUT data */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampLutRdData_Get, device, &bfValue); - + if (channel == ADI_CHANNEL_1) { @@ -1535,7 +1536,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1UpThreshold_Set, device, paRampCfg->upEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1DownThreshold_Set, device, paRampCfg->downEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1Asymmetric_Set, device, (uint8_t)paRampCfg->asymmetricRamp); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkEn_Set, device, (uint8_t)paRampCfg->enable); } else @@ -1547,10 +1548,10 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2UpThreshold_Set, device, paRampCfg->upEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2DownThreshold_Set, device, paRampCfg->downEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2Asymmetric_Set, device, (uint8_t)paRampCfg->asymmetricRamp); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Set, device, (uint8_t)paRampCfg->enable); } - + ADI_API_RETURN(device); } @@ -1661,14 +1662,14 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, uint8_t triggerSelectValue = 0; ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_PaRamp_Inspect_Validate, device, channel, paRampCfg); - + // Set all AuxDAC SPI Words to 0x0, Set Mux to 0x0 (all SPI), restore after LUTRead to prevent unwanted output on AuxDACs ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Get, device, &muxSelProgrammed); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Get, device, &spiWordProgrammed[0]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac1_Get, device, &spiWordProgrammed[1]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac2_Get, device, &spiWordProgrammed[2]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac3_Get, device, &spiWordProgrammed[3]); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac1_Set, device, 0x0); @@ -1679,7 +1680,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore3_RefClkIntDevclkDivideRatio_Get, device, &clkDivRatio); refClk_Hz = KILO_TO_BASE_UNIT(device->devStateInfo.deviceClock_kHz) >> clkDivRatio; - + // Not possible to return the configured AuxDAC for each channel based on XBAR..._Inspect will always return ADI_ADRV9001_AUXDAC0 paRampCfg->auxDacChannelSelect = ADI_ADRV9001_AUXDAC0; @@ -1696,7 +1697,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, rampClock_kHz = refClk_Hz / paRampDpClkDiv; /* Convert to kHz */ paRampCfg->rampClock_kHz = rampClock_kHz / 1000; - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); } else { @@ -1711,7 +1712,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, rampClock_kHz = refClk_Hz / paRampDpClkDiv; /* Convert to kHz */ paRampCfg->rampClock_kHz = rampClock_kHz / 1000; - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, 0x0); } for (idx = 0; idx < ADRV9001_TX_PA_RAMP_LUT_SIZE; idx++) @@ -1730,7 +1731,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, /* De-select pa_ramp_tx1_lut_sel bit */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1LutSel_Set, device, 0x0); // Restore Ramp Clock to configured after read - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); /* Set PA Ramp up/down threshold for Tx1 */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1UpThreshold_Get, device, &(paRampCfg->upEndIndex)); @@ -1743,7 +1744,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, /* De-select pa_ramp_tx2_lut_sel bit */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2LutSel_Set, device, 0x0); // Restore Ramp Clock to configured after read - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); /* Set PA Ramp up/down threshold for Tx2 */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2UpThreshold_Get, device, &(paRampCfg->upEndIndex)); @@ -1766,7 +1767,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioSel_Get, device, &bfValue); - paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; + paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnable_Get, device, &bfValue); @@ -1775,7 +1776,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigStartDelay_Get, device, &(paRampCfg->triggerDelayRise)); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigEndDelay_Get, device, &(paRampCfg->triggerDelayFall)); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkEn_Get, device, &bfValue); paRampCfg->enable = (bool)bfValue; } @@ -1793,7 +1794,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioSel_Get, device, &bfValue); - paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; + paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnable_Get, device, &bfValue); @@ -1802,11 +1803,11 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigStartDelay_Get, device, &(paRampCfg->triggerDelayRise)); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigEndDelay_Get, device, &(paRampCfg->triggerDelayFall)); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Get, device, &bfValue); paRampCfg->enable = (bool)bfValue; } - + // Restore AuxDAC SPI Words and Mux after LUTRead complete ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, muxSelProgrammed); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Set, device, spiWordProgrammed[0]); @@ -2058,7 +2059,7 @@ int32_t adi_adrv9001_Tx_DataPath_Loopback_Set(adi_adrv9001_Device_t *device, { adrv9001_BfNvsRegmapTx_e baseAddr = ADRV9001_BF_TX1_CORE; ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + if (ADI_CHANNEL_2 == channel) { baseAddr = ADRV9001_BF_TX2_CORE; From 626c9ad970aa4ffb7dc3c8258973be29aed85f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Tue, 17 Aug 2021 16:08:12 +0200 Subject: [PATCH 206/407] iio: adrv9002: api: add api to get gpio direction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an API to allow reading the direction of a GPIO. This change has to be re-applied as it's still not merged into the "upstream" sdk code (already applied so this the last time we have to re-apply it). Signed-off-by: Nuno Sá --- .../public/include/adi_adrv9001_gpio.h | 49 +++++++++++++------ .../adrv9001/public/src/adi_adrv9001_gpio.c | 32 ++++++++++++ 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h index 22ebc1fde8da60..7179df8add7404 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h @@ -120,7 +120,7 @@ int32_t adi_adrv9001_gpio_GpIntStatus_Get(adi_adrv9001_Device_t *adrv9001, uint3 * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_OutputPinLevel_Set(adi_adrv9001_Device_t *adrv9001, - adi_adrv9001_GpioPin_e pin, + adi_adrv9001_GpioPin_e pin, adi_adrv9001_GpioPinLevel_e level); /** @@ -158,58 +158,75 @@ int32_t adi_adrv9001_gpio_OutputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin, adi_adrv9001_GpioPinLevel_e *gpioInPinLevels); - + +/** + * \brief Reads the ADRV9001 GPIO pin direction for BITBANG mode + * + * This function allows reading the direction of the GPIO + * + * \note Message type: \ref timing_direct "Direct register access" + * + * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure + * \param[in] pin The pin for which to get the direction + * \param[out] direction Current direction of the pin + * + * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover + */ +int32_t adi_adrv9001_gpio_PinDirection_Get(adi_adrv9001_Device_t *device, + adi_adrv9001_GpioPin_e pin, + adi_adrv9001_GpioPinDirection_e *direction); + /** * \brief Configure specified pin as manual input - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] pin The GPIO pin to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_ManualInput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin); - + /** * \brief Configure specified pin crumb as manual output - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] crumb The GPIO pin crumb to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_ManualOutput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPinCrumbSel_e crumb); /** * \brief Configure specified analog GPIO pin as manual input - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] pin The analog GPIO pin to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin); /** * \brief Configure specified analog GPIO pin nibble as manual output - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] nibble The analog GPIO pin nibble to configure * \param[in] source The source signal to be output on the pins - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioAnalogPinNibbleSel_e nibble); /** @@ -224,7 +241,7 @@ int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *ad */ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioCtrlInitCfg_t *gpioCtrlInitCfg); - + /** * \brief Configure the ADRV9001 GPIO for the specified signal * @@ -241,7 +258,7 @@ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, int32_t adi_adrv9001_gpio_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioSignal_e signal, adi_adrv9001_GpioCfg_t *gpioConfig); - + /** * \brief Retrieve the ADRV9001 GPIO configuration for the requested signal * diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c index 5881a822a6a6ea..41915478780e93 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c @@ -224,6 +224,38 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_gpio_ManualAnalogInput ADI_API_RETURN(device); } +static __maybe_unused int32_t adi_adrv9001_gpio_PinDirection_Get_Validate(adi_adrv9001_Device_t *device, + adi_adrv9001_GpioPin_e pin) +{ + ADI_API_RETURN(device); + ADI_RANGE_CHECK(device, pin, ADI_ADRV9001_GPIO_DIGITAL_00, ADI_ADRV9001_GPIO_ANALOG_11); +} + +int32_t adi_adrv9001_gpio_PinDirection_Get(adi_adrv9001_Device_t *device, + adi_adrv9001_GpioPin_e pin, + adi_adrv9001_GpioPinDirection_e *direction) +{ + uint16_t gpioOutEn = 0; + + ADI_PERFORM_VALIDATION(adi_adrv9001_gpio_PinDirection_Get_Validate, device, pin); + if (ADI_ADRV9001_GPIO_DIGITAL_00 <= pin && pin <= ADI_ADRV9001_GPIO_DIGITAL_15) + { + ADI_EXPECT(adrv9001_NvsRegmapCore_NvsGpioDirectionControlOe_Get, device, &gpioOutEn); + *direction = (gpioOutEn & (1 << (pin - 1))) >> (pin - 1); + } + else if (ADI_ADRV9001_GPIO_ANALOG_00 <= pin && pin <= ADI_ADRV9001_GPIO_ANALOG_11) + { + ADI_EXPECT(adrv9001_NvsRegmapCore1_NvsGpioAnalogDirectionControlOe_Get, device, &gpioOutEn); + *direction = (gpioOutEn & (1 << (pin - ADI_ADRV9001_GPIO_ANALOG_00))) >> (pin - ADI_ADRV9001_GPIO_ANALOG_00); + } + else + { + ADI_SHOULD_NOT_EXECUTE(device); + } + + ADI_API_RETURN(device); +} + int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *device, adi_adrv9001_GpioPin_e pin) { From 7eb17ecb729e058e1a4c645b9d35d98b20a8226c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Tue, 1 Mar 2022 10:21:39 +0100 Subject: [PATCH 207/407] iio: adrv9002: adapt to the new API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Very small change regrading an enum rename from ADI_ADRV9001_TRACKING_CAL_RX_AGC to ADI_ADRV9001_TRACKING_CAL_RX_GAIN_CONTROL_DETECTORS. Signed-off-by: Nuno Sá --- drivers/iio/adc/navassa/adrv9002.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/navassa/adrv9002.c b/drivers/iio/adc/navassa/adrv9002.c index 53330f50eb6d7c..5378f60dacaaad 100644 --- a/drivers/iio/adc/navassa/adrv9002.c +++ b/drivers/iio/adc/navassa/adrv9002.c @@ -1124,7 +1124,7 @@ static const u32 rx_track_calls[] = { [RX_QEC_FIC] = ADI_ADRV9001_TRACKING_CAL_RX_QEC_FIC, [RX_QEC_W_POLY] = ADI_ADRV9001_TRACKING_CAL_RX_QEC_WBPOLY, [ORX_QEC_W_POLY] = ADI_ADRV9001_TRACKING_CAL_ORX_QEC_WBPOLY, - [RX_AGC] = ADI_ADRV9001_TRACKING_CAL_RX_AGC, + [RX_AGC] = ADI_ADRV9001_TRACKING_CAL_RX_GAIN_CONTROL_DETECTORS, [RX_TRACK_BBDC] = ADI_ADRV9001_TRACKING_CAL_RX_BBDC, [RX_HD2] = ADI_ADRV9001_TRACKING_CAL_RX_HD2, [RX_RSSI_CAL] = ADI_ADRV9001_TRACKING_CAL_RX_RSSI, From fd25ba04aac46aff6c2e9d9fbde9f0f1d0a78654 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 3 Mar 2022 12:15:50 +0100 Subject: [PATCH 208/407] iio: adc: ad9371: Additional calibrations for LO change procedure This adds additional required calibrations in addition to RX_QEC and TX_QEC, which are required for large frequency step procedure as detailed in UG-992. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9371.c | 63 +++++++++++++++++++++++++++++++++++++--- drivers/iio/adc/ad9371.h | 1 + 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ad9371.c b/drivers/iio/adc/ad9371.c index bbce6f23706079..8d7dd32af8f255 100644 --- a/drivers/iio/adc/ad9371.c +++ b/drivers/iio/adc/ad9371.c @@ -111,6 +111,7 @@ enum ad9371_iio_dev_attr { AD9371_ENSM_MODE, AD9371_ENSM_MODE_AVAIL, AD9371_INIT_CAL, + AD9371_LARGE_LO_STEP_CAL, }; int ad9371_spi_read(struct spi_device *spi, unsigned reg) @@ -1208,6 +1209,9 @@ static ssize_t ad9371_phy_store(struct device *dev, ad9371_set_radio_state(phy, RADIO_RESTORE_STATE); } break; + case AD9371_LARGE_LO_STEP_CAL: + ret = strtobool(buf, &phy->large_freq_step_cal_en); + break; default: ret = -EINVAL; } @@ -1241,6 +1245,9 @@ static ssize_t ad9371_phy_show(struct device *dev, if (val) ret = sprintf(buf, "%d\n", !!(phy->cal_mask & val)); break; + case AD9371_LARGE_LO_STEP_CAL: + ret = sprintf(buf, "%u\n", phy->large_freq_step_cal_en); + break; default: ret = -EINVAL; } @@ -1299,6 +1306,25 @@ static IIO_DEVICE_ATTR(calibrate_tx_lol_ext_en, S_IRUGO | S_IWUSR, ad9371_phy_store, AD9371_INIT_CAL | (TX_LO_LEAKAGE_EXTERNAL << 8)); +static IIO_DEVICE_ATTR(calibrate_loopback_rx_lo_delay_en, S_IRUGO | S_IWUSR, + ad9371_phy_show, + ad9371_phy_store, + AD9371_INIT_CAL | (LOOPBACK_RX_LO_DELAY << 8)); + +static IIO_DEVICE_ATTR(calibrate_loopback_rx_rx_qec_en, S_IRUGO | S_IWUSR, + ad9371_phy_show, + ad9371_phy_store, + AD9371_INIT_CAL | (LOOPBACK_RX_RX_QEC_INIT << 8)); + +static IIO_DEVICE_ATTR(calibrate_rx_lo_delay_en, S_IRUGO | S_IWUSR, + ad9371_phy_show, + ad9371_phy_store, + AD9371_INIT_CAL | (RX_LO_DELAY << 8)); + +static IIO_DEVICE_ATTR(large_lo_step_calibration_en, S_IRUGO | S_IWUSR, + ad9371_phy_show, + ad9371_phy_store, + AD9371_LARGE_LO_STEP_CAL); static struct attribute *ad9371_phy_attributes[] = { &iio_dev_attr_ensm_mode.dev_attr.attr, @@ -1308,6 +1334,10 @@ static struct attribute *ad9371_phy_attributes[] = { &iio_dev_attr_calibrate_tx_qec_en.dev_attr.attr, &iio_dev_attr_calibrate_tx_lol_en.dev_attr.attr, &iio_dev_attr_calibrate_tx_lol_ext_en.dev_attr.attr, + &iio_dev_attr_calibrate_loopback_rx_lo_delay_en.dev_attr.attr, + &iio_dev_attr_calibrate_loopback_rx_rx_qec_en.dev_attr.attr, + &iio_dev_attr_calibrate_rx_lo_delay_en.dev_attr.attr, + &iio_dev_attr_large_lo_step_calibration_en.dev_attr.attr, NULL, }; @@ -1326,6 +1356,10 @@ static struct attribute *ad9375_phy_attributes[] = { &iio_dev_attr_calibrate_tx_lol_en.dev_attr.attr, &iio_dev_attr_calibrate_tx_lol_ext_en.dev_attr.attr, &iio_dev_attr_calibrate_vswr_en.dev_attr.attr, + &iio_dev_attr_calibrate_loopback_rx_lo_delay_en.dev_attr.attr, + &iio_dev_attr_calibrate_loopback_rx_rx_qec_en.dev_attr.attr, + &iio_dev_attr_calibrate_rx_lo_delay_en.dev_attr.attr, + &iio_dev_attr_large_lo_step_calibration_en.dev_attr.attr, NULL, }; @@ -1364,7 +1398,7 @@ static ssize_t ad9371_phy_lo_write(struct iio_dev *indio_dev, struct ad9371_rf_phy *phy = iio_priv(indio_dev); u64 readin; u8 status; - int ret = 0; + int ret = 0, retry = 10; ret = kstrtoull(buf, 10, &readin); if (ret) @@ -1378,9 +1412,30 @@ static ssize_t ad9371_phy_lo_write(struct iio_dev *indio_dev, if (ret != MYKONOS_ERR_OK) break; - ret = MYKONOS_checkPllsLockStatus(phy->mykDevice, &status); - if (!((status & BIT(chan->channel + 1) || (ret != MYKONOS_ERR_OK)))) - ret = -EFAULT; + do { + ret = MYKONOS_checkPllsLockStatus(phy->mykDevice, &status); + if (!((status & BIT(chan->channel + 1) || (ret != MYKONOS_ERR_OK)))) { + msleep(20); + ret = -EFAULT; + } + } while (retry-- && ret == -EFAULT); /* Wait for up to 200ms */ + + if (phy->large_freq_step_cal_en) { + ret = ad9371_init_cal(phy, TX_QEC_INIT | LOOPBACK_RX_LO_DELAY | + LOOPBACK_RX_RX_QEC_INIT | RX_LO_DELAY | RX_QEC_INIT); + if (ret != MYKONOS_ERR_OK) { + dev_err(&phy->spi->dev, "%s (%d)", + getMykonosErrorMessage(ret), ret); + ret = -EFAULT; + } + } else { + ret = MYKONOS_resetExtTxLolChannel(phy->mykDevice, + phy->mykDevice->tx->txChannels); + + if (ret != MYKONOS_ERR_OK) + dev_err(&phy->spi->dev, "%s: %s (%d)", __func__, + getMykonosErrorMessage(ret), ret); + } ad9371_set_radio_state(phy, RADIO_RESTORE_STATE); break; diff --git a/drivers/iio/adc/ad9371.h b/drivers/iio/adc/ad9371.h index 3d0803d9bee3fc..011e72f273a36b 100644 --- a/drivers/iio/adc/ad9371.h +++ b/drivers/iio/adc/ad9371.h @@ -231,6 +231,7 @@ struct ad9371_rf_phy { u32 cal_mask; u32 rf_bandwith[3]; bool is_initialized; + bool large_freq_step_cal_en; }; int ad9371_hdl_loopback(struct ad9371_rf_phy *phy, bool enable); From b7323b33eeea7b9138dea54b852c1a0addd36f2a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 12 Jul 2021 17:20:25 +0300 Subject: [PATCH 209/407] units: Add SI metric prefix definitions Sometimes it's useful to have well-defined SI metric prefix to be used to self-describe the formulas or equations. List most popular ones in the units.h. Signed-off-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- include/linux/units.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/linux/units.h b/include/linux/units.h index aaf716364ec34a..3457179f7116a4 100644 --- a/include/linux/units.h +++ b/include/linux/units.h @@ -4,6 +4,26 @@ #include +/* Metric prefixes in accordance with Système international (d'unités) */ +#define PETA 1000000000000000ULL +#define TERA 1000000000000ULL +#define GIGA 1000000000UL +#define MEGA 1000000UL +#define KILO 1000UL +#define HECTO 100UL +#define DECA 10UL +#define DECI 10UL +#define CENTI 100UL +#define MILLI 1000UL +#define MICRO 1000000UL +#define NANO 1000000000UL +#define PICO 1000000000000ULL +#define FEMTO 1000000000000000ULL + +#define MILLIWATT_PER_WATT 1000L +#define MICROWATT_PER_MILLIWATT 1000L +#define MICROWATT_PER_WATT 1000000L + #define ABSOLUTE_ZERO_MILLICELSIUS -273150 static inline long milli_kelvin_to_millicelsius(long t) From 135573095be0159b9a36a1c4743e721538e2a0e9 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Tue, 9 Nov 2021 12:08:05 +0200 Subject: [PATCH 210/407] dt:bindings:iio:frequency: Add ADMV4420 doc Add device tree bindings for the ADMV4420 K band downconverter. Signed-off-by: Cristian Pop --- .../bindings/iio/frequency/adi,admv4420.yaml | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml new file mode 100644 index 00000000000000..da7fe85ec92ef3 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/frequency/adi,admv4420.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADMV4420 K Band Downconverter + +maintainers: + - Cristian Pop + +description: + The ADMV4420 is a highly integrated, double balanced, active + mixer with an integrated fractional-N synthesizer, ideally suited + for next generation K band satellite communications + +properties: + compatible: + enum: + - adi,admv4420 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 1000000 + + adi,lo-freq-khz: + description: LO Frequency + $ref: /schemas/types.yaml#/definitions/uint32 + + adi,ref-ext-single-ended-en: + description: External reference selected. + type: boolean + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + mixer@0 { + compatible = "adi,admv4420"; + reg = <0>; + spi-max-frequency = <1000000>; + adi,lo-freq-khz = <16750000>; + adi,ref-ext-single-ended-en; + }; + }; +... From 121263424f29f8d9f8e4207bf9e164c52365727e Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Thu, 14 Oct 2021 12:24:43 +0300 Subject: [PATCH 211/407] iio:frequency:admv4420.c: Add support for ADMV4420 Add support for K Band Downconverter with Integrated Fractional-N PLL and VCO. More info: https://www.analog.com/en/products/admv4420.html Signed-off-by: Cristian Pop --- drivers/iio/Kconfig.adi | 1 + drivers/iio/frequency/Kconfig | 12 + drivers/iio/frequency/Makefile | 1 + drivers/iio/frequency/admv4420.c | 398 +++++++++++++++++++++++++++++++ 4 files changed, 412 insertions(+) create mode 100644 drivers/iio/frequency/admv4420.c diff --git a/drivers/iio/Kconfig.adi b/drivers/iio/Kconfig.adi index 3f2624a7466daa..4338428fdfb5b3 100644 --- a/drivers/iio/Kconfig.adi +++ b/drivers/iio/Kconfig.adi @@ -113,6 +113,7 @@ config IIO_ALL_ADI_DRIVERS select ADL5960 select ADMV1013 select ADMV1014 + select ADMV4420 select ADMV8818 select ADRF6780 select CF_AXI_DDS diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig index b0a53993a5fc42..f1424021282797 100644 --- a/drivers/iio/frequency/Kconfig +++ b/drivers/iio/frequency/Kconfig @@ -88,6 +88,18 @@ config ADMV1014 To compile this driver as a module, choose M here: the module will be called admv1014. +config ADMV4420 + tristate "Analog Devices ADMV4420 K Band Downconverter" + depends on SPI + depends on COMMON_CLK + depends on OF + help + Say yes here to build support for Analog Devices K Band Downconverter with + Integrated Fractional-N PLL and VCO. + + To compile this driver as a module, choose M here: the + module will be called admv4420. + config ADRF6780 tristate "Analog Devices ADRF6780 Microwave Upconverter" depends on SPI diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile index 2c465f85f4a07e..fe9ec3a22395c3 100644 --- a/drivers/iio/frequency/Makefile +++ b/drivers/iio/frequency/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_ADF5355) += adf5355.o obj-$(CONFIG_ADL5960) += adl5960.o obj-$(CONFIG_ADMV1013) += admv1013.o obj-$(CONFIG_ADMV1014) += admv1014.o +obj-$(CONFIG_ADMV1014) += admv4420.o obj-$(CONFIG_ADRF6780) += adrf6780.o cf_axi_dds_drv-y := cf_axi_dds.o cf_axi_dds_buffer_stream.o obj-$(CONFIG_CF_AXI_DDS) += cf_axi_dds_drv.o diff --git a/drivers/iio/frequency/admv4420.c b/drivers/iio/frequency/admv4420.c new file mode 100644 index 00000000000000..51134aee851094 --- /dev/null +++ b/drivers/iio/frequency/admv4420.c @@ -0,0 +1,398 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * ADMV4420 + * + * Copyright 2021 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* ADMV4420 Register Map */ +#define ADMV4420_SPI_CONFIG_1 0x00 +#define ADMV4420_SPI_CONFIG_2 0x01 +#define ADMV4420_CHIPTYPE 0x03 +#define ADMV4420_PRODUCT_ID_L 0x04 +#define ADMV4420_PRODUCT_ID_H 0x05 +#define ADMV4420_SCRATCHPAD 0x0A +#define ADMV4420_SPI_REV 0x0B +#define ADMV4420_ENABLES 0x103 +#define ADMV4420_SDO_LEVEL 0x108 +#define ADMV4420_INT_L 0x200 +#define ADMV4420_INT_H 0x201 +#define ADMV4420_FRAC_L 0x202 +#define ADMV4420_FRAC_M 0x203 +#define ADMV4420_FRAC_H 0x204 +#define ADMV4420_MOD_L 0x208 +#define ADMV4420_MOD_M 0x209 +#define ADMV4420_MOD_H 0x20A +#define ADMV4420_R_DIV_L 0x20C +#define ADMV4420_R_DIV_H 0x20D +#define ADMV4420_REFERENCE 0x20E +#define ADMV4420_VCO_DATA_READBACK1 0x211 +#define ADMV4420_VCO_DATA_READBACK2 0x212 +#define ADMV4420_PLL_MUX_SEL 0x213 +#define ADMV4420_LOCK_DETECT 0x214 +#define ADMV4420_BAND_SELECT 0x215 +#define ADMV4420_VCO_ALC_TIMEOUT 0x216 +#define ADMV4420_VCO_MANUAL 0x217 +#define ADMV4420_ALC 0x219 +#define ADMV4420_VCO_TIMEOUT1 0x21C +#define ADMV4420_VCO_TIMEOUT2 0x21D +#define ADMV4420_VCO_BAND_DIV 0x21E +#define ADMV4420_VCO_READBACK_SEL 0x21F +#define ADMV4420_AUTOCAL 0x226 +#define ADMV4420_CP_STATE 0x22C +#define ADMV4420_CP_BLEED_EN 0x22D +#define ADMV4420_CP_CURRENT 0x22E +#define ADMV4420_CP_BLEED 0x22F + +#define ADMV4420_SPI_CONFIG_1_SDOACTIVE (BIT(4) | BIT(3)) +#define ADMV4420_SPI_CONFIG_1_ENDIAN (BIT(5) | BIT(2)) +#define ADMV4420_SPI_CONFIG_1_SOFTRESET (BIT(7) | BIT(1)) + +#define ADMV4420_REFERENCE_DIVIDE_BY_2_MASK BIT(0) +#define ADMV4420_REFERENCE_MODE_MASK BIT(1) +#define ADMV4420_REFERENCE_DOUBLER_MASK BIT(2) + +#define ADMV4420_REF_DIVIDER_MAX_VAL GENMASK(9, 0) +#define ADMV4420_N_COUNTER_INT_MAX GENMASK(15, 0) +#define ADMV4420_N_COUNTER_FRAC_MAX GENMASK(23, 0) +#define ADMV4420_N_COUNTER_MOD_MAX GENMASK(23, 0) + +#define ENABLE_PLL BIT(6) +#define ENABLE_LO BIT(5) +#define ENABLE_VCO BIT(3) +#define ENABLE_IFAMP BIT(2) +#define ENABLE_MIXER BIT(1) +#define ENABLE_LNA BIT(0) + +#define ADMV4420_SCRATCH_PAD_VAL_1 0xAD +#define ADMV4420_SCRATCH_PAD_VAL_2 0xEA + +#define ADMV4420_REF_FREQ_HZ 50000000 +#define MAX_N_COUNTER 655360UL +#define MAX_R_DIVIDER 1024 +#define ADMV4420_DEFAULT_LO_FREQ_HZ 16750000000ULL + +enum admv4420_mux_sel { + ADMV4420_LOW = 0, + ADMV4420_LOCK_DTCT = 1, + ADMV4420_R_COUNTER_PER_2 = 4, + ADMV4420_N_CONUTER_PER_2 = 5, + ADMV4420_HIGH = 8, +}; + +struct admv4420_reference_block { + bool doubler_en; + bool divide_by_2_en; + bool ref_single_ended; + u32 divider; +}; + +struct admv4420_n_counter { + u32 int_val; + u32 frac_val; + u32 mod_val; + u32 n_counter; +}; + +struct admv4420_state { + struct spi_device *spi; + struct regmap *regmap; + u64 vco_freq_hz; + u64 lo_freq_hz; + struct admv4420_reference_block ref_block; + struct admv4420_n_counter n_counter; + enum admv4420_mux_sel mux_sel; + struct mutex lock; + u8 transf_buf[4] ____cacheline_aligned; +}; + +static const struct regmap_config admv4420_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .read_flag_mask = BIT(7), +}; + +static int admv4420_reg_access(struct iio_dev *indio_dev, + u32 reg, u32 writeval, + u32 *readval) +{ + struct admv4420_state *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + else + return regmap_write(st->regmap, reg, writeval); +} + +static int admv4420_set_n_counter(struct admv4420_state *st, u32 int_val, + u32 frac_val, u32 mod_val) +{ + int ret; + + put_unaligned_le32(frac_val, st->transf_buf); + ret = regmap_bulk_write(st->regmap, ADMV4420_FRAC_L, st->transf_buf, 3); + if (ret) + return ret; + + put_unaligned_le32(mod_val, st->transf_buf); + ret = regmap_bulk_write(st->regmap, ADMV4420_MOD_L, st->transf_buf, 3); + if (ret) + return ret; + + put_unaligned_le32(int_val, st->transf_buf); + return regmap_bulk_write(st->regmap, ADMV4420_INT_L, st->transf_buf, 2); +} + +static int admv4420_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct admv4420_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_FREQUENCY: + + *val = div_u64_rem(st->lo_freq_hz, MICRO, val2); + + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static const struct iio_info admv4420_info = { + .read_raw = admv4420_read_raw, + .debugfs_reg_access = &admv4420_reg_access, +}; + +static const struct iio_chan_spec admv4420_channels[] = { + { + .type = IIO_ALTVOLTAGE, + .output = 0, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY), + }, +}; + +static void admv4420_fw_parse(struct admv4420_state *st) +{ + struct device *dev = &st->spi->dev; + u32 tmp; + int ret; + + ret = device_property_read_u32(dev, "adi,lo-freq-khz", &tmp); + if (!ret) + st->lo_freq_hz = (u64)tmp * KILO; + + st->ref_block.ref_single_ended = device_property_read_bool(dev, + "adi,ref-ext-single-ended-en"); +} + +static inline uint64_t admv4420_calc_pfd_vco(struct admv4420_state *st) +{ + return div_u64(st->vco_freq_hz * 10, st->n_counter.n_counter); +} + +static inline uint32_t admv4420_calc_pfd_ref(struct admv4420_state *st) +{ + uint32_t tmp; + u8 doubler, divide_by_2; + + doubler = st->ref_block.doubler_en ? 2 : 1; + divide_by_2 = st->ref_block.divide_by_2_en ? 2 : 1; + tmp = ADMV4420_REF_FREQ_HZ * doubler; + + return (tmp / (st->ref_block.divider * divide_by_2)); +} + +static int admv4420_calc_parameters(struct admv4420_state *st) +{ + u64 pfd_ref, pfd_vco; + bool sol_found = false; + + st->ref_block.doubler_en = false; + st->ref_block.divide_by_2_en = false; + st->vco_freq_hz = div_u64(st->lo_freq_hz, 2); + + for (st->ref_block.divider = 1; st->ref_block.divider < MAX_R_DIVIDER; + st->ref_block.divider++) { + pfd_ref = admv4420_calc_pfd_ref(st); + for (st->n_counter.n_counter = 1; st->n_counter.n_counter < MAX_N_COUNTER; + st->n_counter.n_counter++) { + pfd_vco = admv4420_calc_pfd_vco(st); + if (pfd_ref == pfd_vco) { + sol_found = true; + break; + } + } + + if (sol_found) + break; + + st->n_counter.n_counter = 1; + } + if (!sol_found) + return -1; + + st->n_counter.int_val = div_u64_rem(st->n_counter.n_counter, 10, &st->n_counter.frac_val); + st->n_counter.mod_val = 10; + + return 0; +} + +static int admv4420_setup(struct iio_dev *indio_dev) +{ + struct admv4420_state *st = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; + u32 val; + int ret; + + ret = regmap_write(st->regmap, ADMV4420_SPI_CONFIG_1, + ADMV4420_SPI_CONFIG_1_SOFTRESET); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADMV4420_SPI_CONFIG_1, + ADMV4420_SPI_CONFIG_1_SDOACTIVE | + ADMV4420_SPI_CONFIG_1_ENDIAN); + if (ret) + return ret; + + ret = regmap_write(st->regmap, + ADMV4420_SCRATCHPAD, + ADMV4420_SCRATCH_PAD_VAL_1); + if (ret) + return ret; + + ret = regmap_read(st->regmap, ADMV4420_SCRATCHPAD, &val); + if (ret) + return ret; + + if (val != ADMV4420_SCRATCH_PAD_VAL_1) { + dev_err(dev, "Failed ADMV4420 to read/write scratchpad %x ", val); + return -EIO; + } + + ret = regmap_write(st->regmap, + ADMV4420_SCRATCHPAD, + ADMV4420_SCRATCH_PAD_VAL_2); + if (ret) + return ret; + + ret = regmap_read(st->regmap, ADMV4420_SCRATCHPAD, &val); + if (ret) + return ret; + + if (val != ADMV4420_SCRATCH_PAD_VAL_2) { + dev_err(dev, "Failed to read/write scratchpad %x ", val); + return -EIO; + } + + st->mux_sel = ADMV4420_LOCK_DTCT; + st->lo_freq_hz = ADMV4420_DEFAULT_LO_FREQ_HZ; + + admv4420_fw_parse(st); + + ret = admv4420_calc_parameters(st); + if (ret) { + dev_err(dev, "Failed calc parameters for %lld ", st->vco_freq_hz); + return ret; + } + + ret = regmap_write(st->regmap, ADMV4420_R_DIV_L, + FIELD_GET(0xFF, st->ref_block.divider)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADMV4420_R_DIV_H, + FIELD_GET(0xFF00, st->ref_block.divider)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADMV4420_REFERENCE, + st->ref_block.divide_by_2_en | + FIELD_PREP(ADMV4420_REFERENCE_MODE_MASK, st->ref_block.ref_single_ended) | + FIELD_PREP(ADMV4420_REFERENCE_DOUBLER_MASK, st->ref_block.doubler_en)); + if (ret) + return ret; + + ret = admv4420_set_n_counter(st, st->n_counter.int_val, + st->n_counter.frac_val, + st->n_counter.mod_val); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADMV4420_PLL_MUX_SEL, st->mux_sel); + if (ret) + return ret; + + return regmap_write(st->regmap, ADMV4420_ENABLES, + ENABLE_PLL | ENABLE_LO | ENABLE_VCO | + ENABLE_IFAMP | ENABLE_MIXER | ENABLE_LNA); +} + +static int admv4420_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct admv4420_state *st; + struct regmap *regmap; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + regmap = devm_regmap_init_spi(spi, &admv4420_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(regmap), + "Failed to initializing spi regmap\n"); + + st = iio_priv(indio_dev); + st->spi = spi; + st->regmap = regmap; + + indio_dev->name = "admv4420"; + indio_dev->info = &admv4420_info; + indio_dev->channels = admv4420_channels; + indio_dev->num_channels = ARRAY_SIZE(admv4420_channels); + + ret = admv4420_setup(indio_dev); + if (ret) { + dev_err(&spi->dev, "Setup ADMV4420 failed (%d)\n", ret); + return ret; + } + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id admv4420_of_match[] = { + { .compatible = "adi,admv4420" }, + { } +}; + +MODULE_DEVICE_TABLE(of, admv4420_of_match); + +static struct spi_driver admv4420_driver = { + .driver = { + .name = "admv4420", + .of_match_table = admv4420_of_match, + }, + .probe = admv4420_probe, +}; + +module_spi_driver(admv4420_driver); + +MODULE_AUTHOR("Cristian Pop "); +MODULE_DESCRIPTION("Analog Devices ADMV44200 K Band Downconverter"); +MODULE_LICENSE("Dual BSD/GPL"); From f89fba90e2d5c2f8a7e4014136960379fa76f73d Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Fri, 4 Mar 2022 15:45:02 +0200 Subject: [PATCH 212/407] arch: arm64: dts: adi-adar3002-longs-peak.dts: Configure ADMV4420 Configure ADMV4420 downconverters into receive front-end. Signed-off-by: Cristian Pop --- .../boot/dts/xilinx/adi-adar3002-longs-peak.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts index e575589133a535..d0a7ecb06eb246 100644 --- a/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts +++ b/arch/arm64/boot/dts/xilinx/adi-adar3002-longs-peak.dts @@ -108,6 +108,22 @@ vss-supply = <&dac_vss>; vdd-supply = <&dac_vdd>; }; + + admv4420_CSB1@2 { + compatible = "adi,admv4420"; + reg = <2>; + spi-max-frequency = <500000>; + label = "admv4420_CSB1"; + adi,lo-freq-khz = <16750000>; + }; + + admv4420_CSB2@3 { + compatible = "adi,admv4420"; + reg = <3>; + spi-max-frequency = <500000>; + label = "admv4420_CSB2"; + adi,lo-freq-khz = <16750000>; + }; }; &i2c_to_spi_1 { From cb17ac1465378db729668082a40b55c6ef0f0009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 4 Mar 2022 10:51:11 +0100 Subject: [PATCH 213/407] firmware: add adrv9002 compensated gain table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add RX compensated gain table. This will be loaded by driver when the profile is set to use this table type. Signed-off-by: Nuno Sá --- firmware/RxGainTable_GainCompensated.csv | 70 ++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 firmware/RxGainTable_GainCompensated.csv diff --git a/firmware/RxGainTable_GainCompensated.csv b/firmware/RxGainTable_GainCompensated.csv new file mode 100644 index 00000000000000..bdfe8ab660f971 --- /dev/null +++ b/firmware/RxGainTable_GainCompensated.csv @@ -0,0 +1,70 @@ +Gain Index,FE Control Word,TIA Control,ADC Control,Ext Control,Phase Offset,Digital Gain +187,251,0,0,0,0,693 +188,251,0,0,0,0,693 +189,250,0,0,0,0,656 +190,250,0,0,0,0,656 +191,250,0,0,0,0,656 +192,249,0,0,0,0,623 +193,249,0,0,0,0,623 +194,248,0,0,0,0,598 +195,248,0,0,0,0,598 +196,247,0,0,0,0,573 +197,247,0,0,0,0,573 +198,246,0,0,0,0,554 +199,246,0,0,0,0,554 +200,245,0,0,0,0,535 +201,245,0,0,0,0,535 +202,244,0,0,0,0,520 +203,243,0,0,0,0,504 +204,242,0,0,0,0,491 +205,242,0,0,0,0,490 +206,241,0,0,0,0,477 +207,240,0,0,0,0,466 +208,239,0,0,0,0,454 +209,238,0,0,0,0,444 +210,237,0,0,0,0,434 +211,236,0,0,0,0,425 +212,234,0,0,0,0,408 +213,233,0,0,0,0,400 +214,232,0,0,0,0,393 +215,230,0,0,0,0,378 +216,229,0,0,0,0,371 +217,227,0,0,0,0,359 +218,226,0,0,0,0,353 +219,224,0,0,0,0,342 +220,222,0,0,0,0,332 +221,220,0,0,0,0,322 +222,218,0,0,0,0,313 +223,215,0,0,0,0,299 +224,213,0,0,0,0,291 +225,210,0,0,0,0,279 +226,208,0,0,0,0,272 +227,205,0,0,0,0,262 +228,202,0,0,0,0,252 +229,199,0,0,0,0,243 +230,195,0,0,0,0,231 +231,192,0,0,0,0,223 +232,188,0,0,0,0,214 +233,184,0,0,0,0,204 +234,180,0,0,0,0,195 +235,175,0,0,0,0,184 +236,170,0,0,0,0,175 +237,165,0,0,0,0,165 +238,160,0,0,0,0,156 +239,154,0,0,0,0,146 +240,148,0,0,0,0,137 +241,142,0,0,0,0,128 +242,135,0,0,0,0,118 +243,128,0,0,0,0,109 +244,120,0,0,0,0,100 +245,112,0,0,0,0,90 +246,104,0,0,0,0,82 +247,94,0,0,0,0,71 +248,85,0,0,0,0,63 +249,75,0,0,0,0,54 +250,64,0,0,0,0,45 +251,53,0,0,0,0,36 +252,41,0,0,0,0,27 +253,28,0,0,0,0,18 +254,14,0,0,0,0,9 +255,0,0,0,0,0,0 From add8026d42254f4ff12715acb317d59287b5dae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 4 Mar 2022 10:53:37 +0100 Subject: [PATCH 214/407] iio: adrv9002: support RX compensated gain tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the RX gain table type is being provided by the loaded profile, we can properly support it. Hence, depending on the configured gain table selected in the profile, we load the chosen one at setup time. The table type is also being reported when reading the profile_config attribute. Signed-off-by: Nuno Sá --- drivers/iio/adc/navassa/adrv9002.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/navassa/adrv9002.c b/drivers/iio/adc/navassa/adrv9002.c index 5378f60dacaaad..2dc10b3b0ae670 100644 --- a/drivers/iio/adc/navassa/adrv9002.c +++ b/drivers/iio/adc/navassa/adrv9002.c @@ -2656,6 +2656,7 @@ static int adrv9002_digital_init(struct adrv9002_rf_phy *phy) struct adrv9002_rx_chan *rx = &phy->rx_channels[c]; struct adrv9002_tx_chan *tx = &phy->tx_channels[c]; adi_adrv9001_RxProfile_t *p = &rx_cfg[c].profile; + const char *rx_table; if (rx->orx_en || tx->channel.enabled) { ret = adi_adrv9001_Utilities_RxGainTable_Load(phy->adrv9001, ADI_ORX, @@ -2672,9 +2673,10 @@ static int adrv9002_digital_init(struct adrv9002_rf_phy *phy) if (!rx->channel.enabled) continue; - ret = adi_adrv9001_Utilities_RxGainTable_Load(phy->adrv9001, ADI_RX, - "RxGainTable.csv", rx->channel.number, - &p->lnaConfig, t_type); + rx_table = p->gainTableType ? "RxGainTable_GainCompensated.csv" : "RxGainTable.csv"; + ret = adi_adrv9001_Utilities_RxGainTable_Load(phy->adrv9001, ADI_RX, rx_table, + rx->channel.number, &p->lnaConfig, + t_type); if (ret) return adrv9002_dev_err(phy); } @@ -4281,6 +4283,11 @@ const char *const mcs[] = { "Enabled RFPLL Phase" }; +const char *const rx_gain_type[] = { + "Correction", + "Compensated" +}; + static ssize_t adrv9002_profile_bin_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count) @@ -4301,6 +4308,8 @@ static ssize_t adrv9002_profile_bin_read(struct file *filp, struct kobject *kobj "RX2 LO: %s\n" "TX1 LO: %s\n" "TX2 LO: %s\n" + "RX1 Gain Table Type: %s\n" + "RX2 Gain Table Type: %s\n" "RX Channel Mask: 0x%x\n" "TX Channel Mask: 0x%x\n" "Duplex Mode: %s\n" @@ -4310,6 +4319,8 @@ static ssize_t adrv9002_profile_bin_read(struct file *filp, struct kobject *kobj clks->clkPllVcoFreq_daHz * 10ULL, clks->armPowerSavingClkDiv, lo_maps[clks->rx1LoSelect], lo_maps[clks->rx2LoSelect], lo_maps[clks->tx1LoSelect], lo_maps[clks->tx2LoSelect], + rx_gain_type[rx->rxChannelCfg[ADRV9002_CHANN_1].profile.gainTableType], + rx_gain_type[rx->rxChannelCfg[ADRV9002_CHANN_2].profile.gainTableType], rx->rxInitChannelMask, tx->txInitChannelMask, duplex[sys->duplexMode], sys->fhModeOn, mcs[sys->mcsMode], ssi[phy->ssi_type]); From 4afa96405b7f7cb16587c23afdbc7c23a005889f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 4 Mar 2022 10:56:02 +0100 Subject: [PATCH 215/407] arch: arm{64}: config: add adrv9002 compensated gain table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the adrv9002 supports RX compensated gain table, include it on the firmware list for the supported archs. Signed-off-by: Nuno Sá --- arch/arm/configs/zynq_xcomm_adv7511_defconfig | 2 +- arch/arm64/configs/adi_zynqmp_defconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/zynq_xcomm_adv7511_defconfig b/arch/arm/configs/zynq_xcomm_adv7511_defconfig index 2240c3f207f03a..b7b6657bdd5007 100644 --- a/arch/arm/configs/zynq_xcomm_adv7511_defconfig +++ b/arch/arm/configs/zynq_xcomm_adv7511_defconfig @@ -57,7 +57,7 @@ CONFIG_NET_IPIP=m CONFIG_VLAN_8021Q=m CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y -CONFIG_EXTRA_FIRMWARE="ad9467_intbypass_ad9517.stp ad9517.stp ad9517_fmcomms6.stp adau1761.bin imageon_edid.bin pzsdr-fmc-ad9517.stp Mykonos_M3.bin TaliseStream.bin TaliseTDDArmFirmware.bin TaliseTxArmFirmware.bin TaliseRxArmFirmware.bin Navassa_EvaluationFw.bin RxGainTable.csv ORxGainTable.csv TxAttenTable.csv Navassa_Stream.bin Navassa_CMOS_profile.json Navassa_LVDS_profile.json" +CONFIG_EXTRA_FIRMWARE="ad9467_intbypass_ad9517.stp ad9517.stp ad9517_fmcomms6.stp adau1761.bin imageon_edid.bin pzsdr-fmc-ad9517.stp Mykonos_M3.bin TaliseStream.bin TaliseTDDArmFirmware.bin TaliseTxArmFirmware.bin TaliseRxArmFirmware.bin Navassa_EvaluationFw.bin RxGainTable.csv RxGainTable_GainCompensated.csv ORxGainTable.csv TxAttenTable.csv Navassa_Stream.bin Navassa_CMOS_profile.json Navassa_LVDS_profile.json" CONFIG_EXTRA_FIRMWARE_DIR="./firmware" CONFIG_CONNECTOR=y CONFIG_MTD=y diff --git a/arch/arm64/configs/adi_zynqmp_defconfig b/arch/arm64/configs/adi_zynqmp_defconfig index 6302b3b22da5c9..da1862103f9bc4 100644 --- a/arch/arm64/configs/adi_zynqmp_defconfig +++ b/arch/arm64/configs/adi_zynqmp_defconfig @@ -121,7 +121,7 @@ CONFIG_PCI=y CONFIG_PCIE_XILINX_NWL=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y -CONFIG_EXTRA_FIRMWARE="ad9144_fmc_ebz_ad9516.stp Mykonos_M3.bin TaliseStream.bin TaliseTDDArmFirmware.bin TaliseTxArmFirmware.bin TaliseRxArmFirmware.bin adau1761.bin Navassa_EvaluationFw.bin RxGainTable.csv ORxGainTable.csv TxAttenTable.csv Navassa_Stream.bin Navassa_CMOS_profile.json Navassa_LVDS_profile.json" +CONFIG_EXTRA_FIRMWARE="ad9144_fmc_ebz_ad9516.stp Mykonos_M3.bin TaliseStream.bin TaliseTDDArmFirmware.bin TaliseTxArmFirmware.bin TaliseRxArmFirmware.bin adau1761.bin Navassa_EvaluationFw.bin RxGainTable.csv RxGainTable_GainCompensated.csv ORxGainTable.csv TxAttenTable.csv Navassa_Stream.bin Navassa_CMOS_profile.json Navassa_LVDS_profile.json" CONFIG_EXTRA_FIRMWARE_DIR="./firmware" CONFIG_CONNECTOR=y CONFIG_MTD=y From a728e578e377850c104bf238ad2a23a82df41ada Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Wed, 12 Jan 2022 22:00:36 +0200 Subject: [PATCH 216/407] iio: adc: ad7124: fix mask used for setting AIN_BUFP & AIN_BUFM bits According to page 90 of the datasheet [1], AIN_BUFP is bit 6 and AIN_BUFM is bit 5 of the CONFIG_0 -> CONFIG_7 registers. Fix the mask used for setting these bits. [1]: https://www.analog.com/media/en/technical-documentation/data-sheets/ad7124-8.pdf Fixes: 0eaecea6e487 ("iio: adc: ad7124: Add buffered input support") Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220112200036.694490-1-cosmin.tanislav@analog.com Cc: Signed-off-by: Jonathan Cameron (cherry picked from commit 0e33d15f1dce9e3a80a970ea7f0b27837168aeca) --- drivers/iio/adc/ad7124.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index dcdedd421c2039..b9ac2a32b931e5 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -78,7 +78,7 @@ #define AD7124_CONFIG_REF_SEL(x) FIELD_PREP(AD7124_CONFIG_REF_SEL_MSK, x) #define AD7124_CONFIG_PGA_MSK GENMASK(2, 0) #define AD7124_CONFIG_PGA(x) FIELD_PREP(AD7124_CONFIG_PGA_MSK, x) -#define AD7124_CONFIG_IN_BUFF_MSK GENMASK(7, 6) +#define AD7124_CONFIG_IN_BUFF_MSK GENMASK(6, 5) #define AD7124_CONFIG_IN_BUFF(x) FIELD_PREP(AD7124_CONFIG_IN_BUFF_MSK, x) /* AD7124_FILTER_X */ From 1c108761fdbac4b275d29918b9d82ce5e15685c9 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 4 Mar 2022 14:10:59 +0100 Subject: [PATCH 217/407] iio: adc: ad9371: Fix profile loading for clkPllVcoDiv=1.5 This fixes loading profiles where clkPllVcoDiv=1.5 or clkPllVcoDiv=1 Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9371.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad9371.c b/drivers/iio/adc/ad9371.c index 8d7dd32af8f255..3b8106ba43e38f 100644 --- a/drivers/iio/adc/ad9371.c +++ b/drivers/iio/adc/ad9371.c @@ -3739,7 +3739,23 @@ static int ad9371_parse_profile(struct ad9371_rf_phy *phy, if (clocks) { GET_TOKEN(mykDevice->clocks, deviceClock_kHz); GET_TOKEN(mykDevice->clocks, clkPllVcoFreq_kHz); - GET_TOKEN(mykDevice->clocks, clkPllVcoDiv); + + ret = sscanf(line, " ", &int32, &int32_2); + if (ret > 0) { + if (ret == 1) { + if (int32 == 1) + mykDevice->clocks->clkPllVcoDiv = VCODIV_1; + else if (int32 == 2) + mykDevice->clocks->clkPllVcoDiv = VCODIV_2; + else if (int32 == 3) + mykDevice->clocks->clkPllVcoDiv = VCODIV_3; + } else if (ret == 2) { + if (int32 == 1 && int32_2 == 5) + mykDevice->clocks->clkPllVcoDiv = VCODIV_1p5; + } + continue; + } + GET_TOKEN(mykDevice->clocks, clkPllHsDiv); } From 7dadb2eb4bebe7826f856c1f323a1ce6f0170a61 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Mon, 7 Mar 2022 18:52:27 +0200 Subject: [PATCH 218/407] uio: uio_dmem_genirq: Fix NULL pointer deference The issue was reported on: https://github.com/analogdevicesinc/linux/issues/1837 Fixes: 757e2c54a613 (uio_dmem_genirq: Specify the dynamic memory regions from dts) Signed-off-by: Dragos Bogdan --- drivers/uio/uio_dmem_genirq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index e1f7fa2e392cd1..e760af8123395a 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c @@ -164,7 +164,7 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev) pdev->dev.of_node); uioinfo->version = "devicetree"; /* alloc pdata */ - pdata = kzalloc(sizeof(pdata), GFP_KERNEL); + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) { ret = -ENOMEM; dev_err(&pdev->dev, "unable to kmalloc\n"); From 8dfb0f02e680ad956604cec0352949fc6d5dd667 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 9 Mar 2022 11:46:32 +0100 Subject: [PATCH 219/407] dts: zynqmp-zcu102-rev10-ad9082..dual-multi-top.dts: Remove nodes Remove duplicated devicetree nodes. Those have already been added to the base devicetree included here. Signed-off-by: Michael Hennerich --- ...-204c-txmode22-rxmode23-dual-multi-top.dts | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts index b9248ebda0b72c..c050a3620f59ae 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts @@ -244,27 +244,6 @@ adi,out-clk-select = ; }; -&fpga_axi { - axi_data_offload_tx0: axi-data-offload-tx0@9c440000 { - compatible = "adi,axi-data-offload-1.0.a"; - reg = <0x9c440000 0x10000>; - // adi,bringup; - // adi,oneshot; - // adi,bypass; - // adi,sync-config = <2>; - // adi,transfer-length = /bits/ 64 <0x10000>; // 2**16 bytes - }; - - axi_data_offload_rx0: axi-data-offload-rx0@9c450000 { - compatible = "adi,axi-data-offload-1.0.a"; - reg = <0x9c450000 0x10000>; - }; -}; - -&axi_ad9081_core_tx { - adi,axi-data-offload-connected = <&axi_data_offload_tx0>; -}; - &spi1 { status = "okay"; From 1d7674874470df0ddcd74050061f3f24833ddd94 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 9 Mar 2022 16:18:01 +0100 Subject: [PATCH 220/407] dts: zynqmp-zcu102-rev10-ad9082...dual-multi-top.dts: Add FSM STOP states This patch adds optional jesd204-stop-states and jesd204 subclass support. In multi-topology use cases, where JESD204 links span across a topology, it's required to bring up the links simultaneously, by moving the FSM through critical states in parallel. This is done by adding STOP states, and resuming from them when all typologies are in sync. Signed-off-by: Michael Hennerich --- ...-204c-txmode22-rxmode23-dual-multi-top.dts | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts index c050a3620f59ae..780f4caffd0ffe 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts @@ -39,6 +39,10 @@ // TX_JESD_NP=12 #include "zynqmp-zcu102-rev10-ad9081.dts" +#include + +#define JESD204_FSM_STOP_STATES 1 +#define JESD204_SUBCLASS 1 &fpga_axi { top_device: jesd204-top-device { @@ -50,6 +54,13 @@ jesd204-link-ids = ; //jesd204-ignore-errors; +#ifdef JESD204_FSM_STOP_STATES + jesd204-stop-states = < + JESD204_FSM_STATE_LINK_SETUP + JESD204_FSM_STATE_CLOCKS_ENABLE + JESD204_FSM_STATE_LINK_ENABLE>; +#endif + jesd204-inputs = <&axi_ad9081_rx_jesd2 1 FRAMER_LINK1_RX>, <&axi_ad9081_core_tx2 1 DEFRAMER_LINK1_TX>; @@ -63,7 +74,7 @@ adi,sample-rate = /bits/ 64 <960000000>; - adi,subclass = <0>; /* JESD SUBCLASS 0,1,2 */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ adi,version = <2>; /* JESD VERSION 0=204A,1=204B,2=204C */ adi,dual-link = <1>; /* JESD Dual Link Mode */ adi,converters-per-device = <2>; /* JESD M */ @@ -85,7 +96,7 @@ adi,sample-rate = /bits/ 64 <960000000>; - adi,subclass = <0>; /* JESD SUBCLASS 0,1,2 */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ adi,version = <2>; /* JESD VERSION 0=204A,1=204B,2=204C */ adi,dual-link = <1>; /* JESD Dual Link Mode */ adi,converters-per-device = <2>; /* JESD M */ @@ -320,8 +331,11 @@ adi,extended-name = "DEV_SYSREF"; adi,divider = <768>; adi,driver-mode = ; - //adi,jesd204-sysref-chan; +#if (JESD204_SUBCLASS == 1) + adi,jesd204-sysref-chan; +#else adi,disable; /* Completely disable channel */ +#endif }; hmc7044_c6: channel@6 { @@ -357,8 +371,11 @@ adi,extended-name = "FPGA_SYSREF"; adi,divider = <768>; adi,driver-mode = ; - //adi,jesd204-sysref-chan; +#if (JESD204_SUBCLASS == 1) + adi,jesd204-sysref-chan; +#else adi,disable; /* Completely disable channel */ +#endif }; }; }; @@ -388,11 +405,20 @@ jesd204-link-ids = ; //jesd204-ignore-errors; +#ifdef JESD204_FSM_STOP_STATES + jesd204-stop-states = < + JESD204_FSM_STATE_LINK_SETUP + JESD204_FSM_STATE_CLOCKS_ENABLE + JESD204_FSM_STATE_LINK_ENABLE>; +#endif + jesd204-inputs = <&axi_ad9081_core_rx 0 FRAMER_LINK0_RX>, <&axi_ad9081_core_tx 0 DEFRAMER_LINK0_TX>; +#if (JESD204_SUBCLASS == 0) adi,continuous-sysref-mode-disable; +#endif adi,dual-link-use-separate-tpl-enable; @@ -454,7 +480,7 @@ adi,logical-lane-mapping = /bits/ 8 <0 2 7 7 1 7 7 3>; adi,link-mode = <22>; /* JESD Quick Configuration Mode */ - adi,subclass = <0>; /* JESD SUBCLASS 0,1,2 */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ adi,version = <2>; /* JESD VERSION 0=204A,1=204B,2=204C */ adi,dual-link = <1>; /* JESD Dual Link Mode */ @@ -485,7 +511,7 @@ adi,logical-lane-mapping = /bits/ 8 <7 7 7 7 7 1 0 7>; adi,link-mode = <22>; /* JESD Quick Configuration Mode */ - adi,subclass = <0>; /* JESD SUBCLASS 0,1,2 */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ adi,version = <2>; /* JESD VERSION 0=204A,1=204B,2=204C */ adi,dual-link = <1>; /* JESD Dual Link Mode */ @@ -561,7 +587,7 @@ adi,logical-lane-mapping = /bits/ 8 <7 0 7 7 7 7 7 1>; adi,link-mode = <23>; /* JESD Quick Configuration Mode */ - adi,subclass = <0>; /* JESD SUBCLASS 0,1,2 */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ adi,version = <2>; /* JESD VERSION 0=204A,1=204B,2=204C */ adi,dual-link = <1>; /* JESD Dual Link Mode */ @@ -585,7 +611,7 @@ adi,logical-lane-mapping = /bits/ 8 <7 7 7 7 1 0 7 7>; adi,link-mode = <23>; /* JESD Quick Configuration Mode */ - adi,subclass = <0>; /* JESD SUBCLASS 0,1,2 */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ adi,version = <2>; /* JESD VERSION 0=204A,1=204B,2=204C */ adi,dual-link = <1>; /* JESD Dual Link Mode */ From 554beb79e10f98bebad951aaf896371487263b59 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 9 Mar 2022 16:19:57 +0100 Subject: [PATCH 221/407] jesd204: jesd204_top_device: Add jesd204-fsm user controls This patch adds jesd204-fsm controls. In multi-topology use cases, where JESD204 links span across a topology, it's required to bring up the links simultaneously, by moving the FSM through critical states in parallel. This is done by adding STOP states, and resuming from them when all typologies are in sync. This patch adds the required sysfs attributes/controls. Signed-off-by: Michael Hennerich --- drivers/jesd204/jesd204_top_device.c | 230 +++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) diff --git a/drivers/jesd204/jesd204_top_device.c b/drivers/jesd204/jesd204_top_device.c index 11a3b5bd57ef98..928afb5471262e 100644 --- a/drivers/jesd204/jesd204_top_device.c +++ b/drivers/jesd204/jesd204_top_device.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -21,8 +22,11 @@ struct jesd204_top_device_data { struct device *dev; + struct jesd204_dev *jdev; struct jesd204_dev_data jesd204_dev_data; + struct mutex lock; /* Protect against concurrent accesses to the device */ struct jesd204_link links[JESD204_TOP_DEVICE_MAX_NUM_LINKS]; + bool link_init_done; u32 d; /* dummy */ }; @@ -96,6 +100,220 @@ static int jesd204_link_init(struct jesd204_dev *jdev, return JESD204_STATE_CHANGE_DONE; } +static int jesd204_link_post_running(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason, + struct jesd204_link *lnk) +{ + struct device *dev = jesd204_dev_to_device(jdev); + struct jesd204_top_device_data *tdev = dev_get_drvdata(dev); + + dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, + lnk->link_id, jesd204_state_op_reason_str(reason)); + + if (lnk->link_id > JESD204_TOP_DEVICE_MAX_NUM_LINKS) + return -EFAULT; + + WRITE_ONCE(tdev->link_init_done, reason == JESD204_STATE_OP_REASON_INIT); + + return JESD204_STATE_CHANGE_DONE; +} + +static ssize_t jesd204_fsm_error_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct jesd204_top_device_data *tdev = dev_get_drvdata(dev); + struct jesd204_link *links[JESD204_TOP_DEVICE_MAX_NUM_LINKS]; + int i, err, num_links, ret; + + if (!tdev->jdev) + return -EOPNOTSUPP; + + mutex_lock(&tdev->lock); + + num_links = jesd204_get_active_links_num(tdev->jdev); + if (num_links < 0) { + ret = num_links; + goto out; + } + + ret = jesd204_get_links_data(tdev->jdev, links, num_links); + if (ret) + goto out; + + err = 0; + for (i = 0; i < num_links; i++) { + if (links[i]->error) { + err = links[i]->error; + break; + } + } + + ret = sysfs_emit(buf, "%d\n", err); +out: + mutex_unlock(&tdev->lock); + + return ret; +} + +static ssize_t jesd204_fsm_paused_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct jesd204_top_device_data *tdev = dev_get_drvdata(dev); + struct jesd204_link *links[JESD204_TOP_DEVICE_MAX_NUM_LINKS]; + int i, num_links, ret; + bool paused; + + if (!tdev->jdev) + return -EOPNOTSUPP; + + mutex_lock(&tdev->lock); + + num_links = jesd204_get_active_links_num(tdev->jdev); + if (num_links < 0) { + ret = num_links; + goto out; + } + ret = jesd204_get_links_data(tdev->jdev, links, num_links); + if (ret) + goto out; + /* + * Take the slowest link; if there are N links and one is paused, all are paused. + * Not sure if this can happen yet, but best design it like this here. + */ + + paused = false; + for (i = 0; i < num_links; i++) { + if (jesd204_link_get_paused(links[i])) { + paused = true; + break; + } + } + + ret = sysfs_emit(buf, "%d\n", paused); +out: + mutex_unlock(&tdev->lock); + + return ret; +} + +static ssize_t jesd204_fsm_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct jesd204_top_device_data *tdev = dev_get_drvdata(dev); + struct jesd204_link *links[JESD204_TOP_DEVICE_MAX_NUM_LINKS]; + int num_links, ret; + + if (!tdev->jdev) + return -EOPNOTSUPP; + + mutex_lock(&tdev->lock); + + num_links = jesd204_get_active_links_num(tdev->jdev); + if (num_links < 0) { + ret = num_links; + goto out; + } + + ret = jesd204_get_links_data(tdev->jdev, links, num_links); + if (ret) + goto out; + + ret = sysfs_emit(buf, "%s\n", jesd204_link_get_state_str(links[0])); +out: + mutex_unlock(&tdev->lock); + + return ret; +} + +static ssize_t jesd204_fsm_ctrl_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct jesd204_top_device_data *tdev = dev_get_drvdata(dev); + + if (!tdev->jdev) + return -EOPNOTSUPP; + + return sysfs_emit(buf, "%d\n", READ_ONCE(tdev->link_init_done)); +} + +static ssize_t jesd204_fsm_ctrl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct jesd204_top_device_data *tdev = dev_get_drvdata(dev); + int ret; + bool enable; + + if (!tdev->jdev) + return -EOPNOTSUPP; + + ret = strtobool(buf, &enable); + if (ret) + return ret; + + mutex_lock(&tdev->lock); + if (enable) { + jesd204_fsm_stop(tdev->jdev, JESD204_LINKS_ALL); + jesd204_fsm_clear_errors(tdev->jdev, JESD204_LINKS_ALL); + ret = jesd204_fsm_start(tdev->jdev, JESD204_LINKS_ALL); + } else { + jesd204_fsm_stop(tdev->jdev, JESD204_LINKS_ALL); + jesd204_fsm_clear_errors(tdev->jdev, JESD204_LINKS_ALL); + ret = 0; + } + mutex_unlock(&tdev->lock); + + return ret ? ret : len; +} + +static ssize_t jesd204_fsm_resume_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct jesd204_top_device_data *tdev = dev_get_drvdata(dev); + int ret; + bool enable; + + if (!tdev->jdev) + return -EOPNOTSUPP; + + ret = strtobool(buf, &enable); + if (ret) + return ret; + + if (!enable) + return 0; + + mutex_lock(&tdev->lock); + ret = jesd204_fsm_resume(tdev->jdev, JESD204_LINKS_ALL); + mutex_unlock(&tdev->lock); + + return ret ? ret : len; +} + +static DEVICE_ATTR_RO(jesd204_fsm_error); +static DEVICE_ATTR_RO(jesd204_fsm_paused); +static DEVICE_ATTR_RO(jesd204_fsm_state); +static DEVICE_ATTR_WO(jesd204_fsm_resume); +static DEVICE_ATTR_RW(jesd204_fsm_ctrl); + +static struct attribute *jesd204_fsm_attributes[] = { + &dev_attr_jesd204_fsm_error.attr, + &dev_attr_jesd204_fsm_state.attr, + &dev_attr_jesd204_fsm_paused.attr, + &dev_attr_jesd204_fsm_resume.attr, + &dev_attr_jesd204_fsm_ctrl.attr, + NULL, +}; + +static const struct attribute_group jesd204_fsm_attributes_group = { + .attrs = jesd204_fsm_attributes, +}; + /* Match table for of_platform binding */ static const struct of_device_id jesd204_top_device_of_match[] = { { .compatible = "adi,jesd204-top-device-1.0", }, @@ -141,13 +359,25 @@ static int jesd204_top_device_probe(struct platform_device *pdev) tdev->jesd204_dev_data.state_ops[JESD204_OP_LINK_INIT].per_link = jesd204_link_init; + tdev->jesd204_dev_data.state_ops[JESD204_OP_OPT_POST_RUNNING_STAGE].per_link = + jesd204_link_post_running; dev_set_drvdata(&pdev->dev, tdev); + mutex_init(&tdev->lock); jdev = devm_jesd204_dev_register(&pdev->dev, &tdev->jesd204_dev_data); if (IS_ERR(jdev)) return PTR_ERR(jdev); + tdev->jdev = jdev; + + ret = devm_device_add_group(&pdev->dev, &jesd204_fsm_attributes_group); + if (ret != 0) { + dev_err(&pdev->dev, + "Failed to create attribute group: %d\n", ret); + return ret; + } + dev_info(&pdev->dev, "JESD204-GENERIC-TOP-DEVICE probed %d links\n", tdev->jesd204_dev_data.max_num_links); From 388a06725aac9b346aed8ad2ad26ccbc98b4b569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 10 Mar 2022 13:55:59 +0100 Subject: [PATCH 222/407] ci: detach xcomm_zynq merge from syncing other branches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The xcomm_zynq is a complete mirror of the master/main branch and that can be used in our advantage to properly sync the other branches. This is an introdutory change to make things easier later on when updating the sync_jobs function. Signed-off-by: Nuno Sá --- ci/travis/run-build.sh | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index aeb06df661b911..42963d274aadea 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -323,6 +323,24 @@ __push_back_to_github() { } } +MAIN_MIRROR="xcomm_zynq" + +__update_main_mirror() { + __update_git_ref "$MAIN_MIRROR" "$MAIN_MIRROR" || { + echo_red "Could not fetch branch '$MAIN_BRANCH'" + return 1 + } + + git checkout "$MAIN_MIRROR" + git merge --ff-only ${ORIGIN}/${MAIN_BRANCH} || { + echo_red "Failed while syncing ${ORIGIN}/${MAIN_BRANCH} over '$MAIN_MIRROR'" + return 1 + } + + __push_back_to_github "$MAIN_MIRROR" + return $? +} + __handle_sync_with_main() { local dst_branch="$1" local method="$2" @@ -332,16 +350,6 @@ __handle_sync_with_main() { return 1 } - if [ "$method" = "fast-forward" ] ; then - git checkout FETCH_HEAD - git merge --ff-only ${ORIGIN}/${MAIN_BRANCH} || { - echo_red "Failed while syncing ${ORIGIN}/${MAIN_BRANCH} over '$dst_branch'" - return 1 - } - __push_back_to_github "$dst_branch" || return 1 - return 0 - fi - if [ "$method" = "cherry-pick" ] ; then local depth if [ "$GIT_FETCH_DEPTH" = "disabled" ] ; then @@ -400,14 +408,15 @@ __handle_sync_with_main() { build_sync_branches_with_main() { GIT_FETCH_DEPTH=50 - BRANCHES="xcomm_zynq:fast-forward adi-5.10.0:cherry-pick" - BRANCHES="$BRANCHES rpi-5.10.y:cherry-pick" + BRANCHES="adi-5.10.0:cherry-pick rpi-5.10.y:cherry-pick" __update_git_ref "$MAIN_BRANCH" "$MAIN_BRANCH" || { echo_red "Could not fetch branch '$MAIN_BRANCH'" return 1 } + __update_main_mirror "$MAIN_MIRROR" + for branch in $BRANCHES ; do local dst_branch="$(echo $branch | cut -d: -f1)" [ -n "$dst_branch" ] || break From 390f30d88a49c0e15bd78357f27b54609b031ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 10 Mar 2022 14:05:35 +0100 Subject: [PATCH 223/407] ci: remove $method variable from sync_jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the mirror branch update is done independent of syncing the other branches, there's no point in having the method being passed as an argument to __handle_sync_with_main(). Just assume cherry-pick. Signed-off-by: Nuno Sá --- ci/travis/run-build.sh | 109 +++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 58 deletions(-) diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index 42963d274aadea..ec14ea0f0022a1 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -343,72 +343,69 @@ __update_main_mirror() { __handle_sync_with_main() { local dst_branch="$1" - local method="$2" + local depth __update_git_ref "$dst_branch" || { echo_red "Could not fetch branch '$dst_branch'" return 1 } - if [ "$method" = "cherry-pick" ] ; then - local depth - if [ "$GIT_FETCH_DEPTH" = "disabled" ] ; then - depth=50 - else - GIT_FETCH_DEPTH=${GIT_FETCH_DEPTH:-50} - depth=$((GIT_FETCH_DEPTH - 1)) - fi - # FIXME: kind of dumb, the code below; maybe do this a bit neater - local cm="$(git log "FETCH_HEAD~${depth}..FETCH_HEAD" | grep "cherry picked from commit" | head -1 | awk '{print $5}' | cut -d')' -f1)" - [ -n "$cm" ] || { - echo_red "Top commit in branch '${dst_branch}' is not cherry-picked" - return 1 - } - branch_contains_commit "$cm" "${ORIGIN}/${MAIN_BRANCH}" || { - echo_red "Commit '$cm' is not in branch '${MAIN_BRANCH}'" - return 1 - } - # Make sure that we are adding something new, or cherry-pick complains - if git diff --quiet "$cm" "${ORIGIN}/${MAIN_BRANCH}" ; then - return 0 - fi - - tmpfile=$(mktemp) + if [ "$GIT_FETCH_DEPTH" = "disabled" ] ; then + depth=50 + else + GIT_FETCH_DEPTH=${GIT_FETCH_DEPTH:-50} + depth=$((GIT_FETCH_DEPTH - 1)) + fi + # FIXME: kind of dumb, the code below; maybe do this a bit neater + local cm="$(git log "FETCH_HEAD~${depth}..FETCH_HEAD" | grep "cherry picked from commit" | head -1 | awk '{print $5}' | cut -d')' -f1)" + [ -n "$cm" ] || { + echo_red "Top commit in branch '${dst_branch}' is not cherry-picked" + return 1 + } + branch_contains_commit "$cm" "${ORIGIN}/${MAIN_BRANCH}" || { + echo_red "Commit '$cm' is not in branch '${MAIN_BRANCH}'" + return 1 + } + # Make sure that we are adding something new, or cherry-pick complains + if git diff --quiet "$cm" "${ORIGIN}/${MAIN_BRANCH}" ; then + return 0 + fi - if [ "$CI" = "true" ] ; then - # setup an email account so that we can cherry-pick stuff - git config user.name "CSE CI" - git config user.email "cse-ci-notifications@analog.com" - fi + tmpfile=$(mktemp) - git checkout FETCH_HEAD - # cherry-pick until all commits; if we get a merge-commit, handle it - git cherry-pick -x "${cm}..${ORIGIN}/${MAIN_BRANCH}" 1>/dev/null 2>$tmpfile || { - was_a_merge=0 - while grep -q "is a merge" $tmpfile ; do - was_a_merge=1 - # clear file - cat /dev/null > $tmpfile - # retry ; we may have a new merge commit - git cherry-pick --continue 1>/dev/null 2>$tmpfile || { - was_a_merge=0 - continue - } - done - if [ "$was_a_merge" != "1" ]; then - echo_red "Failed to cherry-pick commits '$cm..${ORIGIN}/${MAIN_BRANCH}'" - echo_red "$(cat $tmpfile)" - return 1 - fi - } - __push_back_to_github "$dst_branch" || return 1 - return 0 + if [ "$CI" = "true" ] ; then + # setup an email account so that we can cherry-pick stuff + git config user.name "CSE CI" + git config user.email "cse-ci-notifications@analog.com" fi + + git checkout FETCH_HEAD + # cherry-pick until all commits; if we get a merge-commit, handle it + git cherry-pick -x "${cm}..${ORIGIN}/${MAIN_BRANCH}" 1>/dev/null 2>$tmpfile || { + was_a_merge=0 + while grep -q "is a merge" $tmpfile ; do + was_a_merge=1 + # clear file + cat /dev/null > $tmpfile + # retry ; we may have a new merge commit + git cherry-pick --continue 1>/dev/null 2>$tmpfile || { + was_a_merge=0 + continue + } + done + if [ "$was_a_merge" != "1" ]; then + echo_red "Failed to cherry-pick commits '$cm..${ORIGIN}/${MAIN_BRANCH}'" + echo_red "$(cat $tmpfile)" + return 1 + fi + } + __push_back_to_github "$dst_branch" || return 1 + return 0 } build_sync_branches_with_main() { GIT_FETCH_DEPTH=50 - BRANCHES="adi-5.10.0:cherry-pick rpi-5.10.y:cherry-pick" + BRANCHES="adi-5.10.0 rpi-5.10.y" __update_git_ref "$MAIN_BRANCH" "$MAIN_BRANCH" || { echo_red "Could not fetch branch '$MAIN_BRANCH'" @@ -418,11 +415,7 @@ build_sync_branches_with_main() { __update_main_mirror "$MAIN_MIRROR" for branch in $BRANCHES ; do - local dst_branch="$(echo $branch | cut -d: -f1)" - [ -n "$dst_branch" ] || break - local method="$(echo $branch | cut -d: -f2)" - [ -n "$method" ] || break - __handle_sync_with_main "$dst_branch" "$method" + __handle_sync_with_main "$branch" done } From 55859f1802b39f9972e1fabb54aa8ebb5becbd2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 11 Mar 2022 12:57:44 +0100 Subject: [PATCH 224/407] ci: improve sync_branches_with_main handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To automatically sync the current ADI rebased and rpi branches, the CI script was looking for the line '(cherry picked from commit $some_hash)' in the last commit of the destiny branch to see the last commit that was cherry-picked from master. With this, it was assuming that all commits after this one were new commits to cherry-pick. There are, at least, two main flaws with this approach: 1) When something is cherry-picked to the master branch (eg: from upstream kernel). In this case, the wrong commit hash might be read and the script will bail out saying that the commit does not exist in our tree; 2) When we move to a newer xilinx tag and after the last cherry picked commit, we have a merge with tons of new commits. To improve this, let's take advantage of the master mirror branch that we already have (xcomm_zynq). We just need to make sure that this branch is only merged with master in the end of the job and hence, we can safely assume (unless someone updates it) that the differences between them are the commits that we need to cherry-pick to the other branches. We also need to be careful on error paths of the cherry-pick process so that our mirror always gets updated. Signed-off-by: Nuno Sá --- ci/travis/run-build.sh | 59 +++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index ec14ea0f0022a1..7433787832cc9b 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -326,11 +326,6 @@ __push_back_to_github() { MAIN_MIRROR="xcomm_zynq" __update_main_mirror() { - __update_git_ref "$MAIN_MIRROR" "$MAIN_MIRROR" || { - echo_red "Could not fetch branch '$MAIN_BRANCH'" - return 1 - } - git checkout "$MAIN_MIRROR" git merge --ff-only ${ORIGIN}/${MAIN_BRANCH} || { echo_red "Failed while syncing ${ORIGIN}/${MAIN_BRANCH} over '$MAIN_MIRROR'" @@ -343,33 +338,17 @@ __update_main_mirror() { __handle_sync_with_main() { local dst_branch="$1" - local depth + local cm=$(git log --reverse --oneline ${MAIN_MIRROR}..${MAIN_BRANCH} | awk '{print $1}' | head -1) - __update_git_ref "$dst_branch" || { - echo_red "Could not fetch branch '$dst_branch'" - return 1 - } - - if [ "$GIT_FETCH_DEPTH" = "disabled" ] ; then - depth=50 - else - GIT_FETCH_DEPTH=${GIT_FETCH_DEPTH:-50} - depth=$((GIT_FETCH_DEPTH - 1)) - fi - # FIXME: kind of dumb, the code below; maybe do this a bit neater - local cm="$(git log "FETCH_HEAD~${depth}..FETCH_HEAD" | grep "cherry picked from commit" | head -1 | awk '{print $5}' | cut -d')' -f1)" [ -n "$cm" ] || { - echo_red "Top commit in branch '${dst_branch}' is not cherry-picked" + echo_red "No commits to cherry-pick... Was "${MAIN_MIRROR}" manually updated?!" return 1 } - branch_contains_commit "$cm" "${ORIGIN}/${MAIN_BRANCH}" || { - echo_red "Commit '$cm' is not in branch '${MAIN_BRANCH}'" + + __update_git_ref "$dst_branch" || { + echo_red "Could not fetch branch '$dst_branch'" return 1 } - # Make sure that we are adding something new, or cherry-pick complains - if git diff --quiet "$cm" "${ORIGIN}/${MAIN_BRANCH}" ; then - return 0 - fi tmpfile=$(mktemp) @@ -380,8 +359,9 @@ __handle_sync_with_main() { fi git checkout FETCH_HEAD - # cherry-pick until all commits; if we get a merge-commit, handle it - git cherry-pick -x "${cm}..${ORIGIN}/${MAIN_BRANCH}" 1>/dev/null 2>$tmpfile || { + # cherry-pick until all commits; if we get a merge-commit, handle it. Note that + # ~1 is because we also want ${cm} to be cherry-picked! + git cherry-pick -x "${cm}~1..${ORIGIN}/${MAIN_BRANCH}" 1>/dev/null 2>$tmpfile || { was_a_merge=0 while grep -q "is a merge" $tmpfile ; do was_a_merge=1 @@ -396,6 +376,7 @@ __handle_sync_with_main() { if [ "$was_a_merge" != "1" ]; then echo_red "Failed to cherry-pick commits '$cm..${ORIGIN}/${MAIN_BRANCH}'" echo_red "$(cat $tmpfile)" + git cherry-pick --abort return 1 fi } @@ -412,11 +393,29 @@ build_sync_branches_with_main() { return 1 } - __update_main_mirror "$MAIN_MIRROR" + # needed for __handle_sync_with_main() so we can properly get the list + # of commits to cherry-pick + __update_git_ref "$MAIN_MIRROR" "$MAIN_MIRROR" || { + echo_red "Could not fetch branch '$MAIN_MIRROR'" + return 1 + } for branch in $BRANCHES ; do - __handle_sync_with_main "$branch" + __handle_sync_with_main "$branch" || { + # In case cherry-picking fails, we need to still make sure that our mirror + # get's updated. Otherwise in the next time this job is called, we will + # have commits to cherry-pick that do not belong to this call... Furthermore + # at this stage the cherry-pick needs to be handled manually. Note that, + # in theory, the cherry-pick should never fail for the ADI rebased branch + # (adi-${kernerversion}) but that is not true for the pi branch where it can + # fail and where it might actually be acceptable to fail (when touching in + # xilinx specific code that we do not care in pi platforms). + __update_main_mirror "$MAIN_MIRROR" + return 1 + } done + + __update_main_mirror "$MAIN_MIRROR" } ORIGIN=${ORIGIN:-origin} From 13b010367b1c3808c5c3e9d50f9a39355624c297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 11 Mar 2022 13:09:14 +0100 Subject: [PATCH 225/407] ci: install dependencies for 'build_checkpatch()' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Install ply module. This is needed by checkpatch, otherwise we keep seeing: " Traceback (most recent call last): File "scripts/spdxcheck.py", line 6, in from ply import lex, yacc ModuleNotFoundError: No module named 'ply' Traceback (most recent call last): File "scripts/spdxcheck.py", line 6, in from ply import lex, yacc ModuleNotFoundError: No module named 'ply' Traceback (most recent call last): File "scripts/spdxcheck.py", line 6, in from ply import lex, yacc ModuleNotFoundError: No module named 'ply' " Signed-off-by: Nuno Sá --- ci/travis/run-build.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index 7433787832cc9b..e1170204ab516e 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -224,6 +224,9 @@ build_checkpatch() { exit 1 fi + # install checkpatch dependencies + sudo pip install ply + __update_git_ref "${ref_branch}" "${ref_branch}" scripts/checkpatch.pl --git "${ref_branch}.." \ From 492deaa25860937a11c7f5fee1f487642bb63717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 11 Mar 2022 15:27:05 +0100 Subject: [PATCH 226/407] iio: adrv9002: make use of 'device_create_bin_file()' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should not be calling 'sysfs_create_bin_file()' and accessing kobjects directly from drivers. Even more when there are proper helpers to use. Signed-off-by: Nuno Sá --- drivers/iio/adc/navassa/adrv9002.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/navassa/adrv9002.c b/drivers/iio/adc/navassa/adrv9002.c index 2dc10b3b0ae670..e16645eb71c3df 100644 --- a/drivers/iio/adc/navassa/adrv9002.c +++ b/drivers/iio/adc/navassa/adrv9002.c @@ -4579,7 +4579,7 @@ int adrv9002_post_init(struct adrv9002_rf_phy *phy) if (!phy->bin_attr_buf) return -ENOMEM; - ret = sysfs_create_bin_file(&indio_dev->dev.kobj, &bin_attr_profile_config); + ret = device_create_bin_file(&indio_dev->dev, &bin_attr_profile_config); if (ret < 0) return ret; @@ -4587,12 +4587,12 @@ int adrv9002_post_init(struct adrv9002_rf_phy *phy) if (!phy->stream_buf) return -ENOMEM; - ret = sysfs_create_bin_file(&indio_dev->dev.kobj, &bin_attr_stream_config); + ret = device_create_bin_file(&indio_dev->dev, &bin_attr_stream_config); if (ret < 0) return ret; for (c = 0; c < ARRAY_SIZE(hop_attrs); c++) { - ret = sysfs_create_bin_file(&indio_dev->dev.kobj, hop_attrs[c]); + ret = device_create_bin_file(&indio_dev->dev, hop_attrs[c]); if (ret < 0) return ret; } From c6565baa194791b1853856a8332bb7194c33fedd Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 15 Mar 2022 13:07:04 +0200 Subject: [PATCH 227/407] arch:arm:dts:fmcadc2: remove extra i2c node According to the hdl, there is no support for the LPC connector. Fixes eeprom error: `i2c: Timeout waiting at Tx empty` Signed-off-by: Antoniu Miclaus --- .../arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc2.dts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc2.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc2.dts index df9aba19c72e16..3500a1d5a7afe3 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc2.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9625-fmcadc2.dts @@ -59,16 +59,6 @@ reg = <0x50>; }; }; - - i2c@6 { /* LPC IIC */ - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - eeprom@50 { - compatible = "at24,24c02"; - reg = <0x50>; - }; - }; }; &fpga_axi { From 480f507720a07f7f2c9e932ccbfe1ee7a49a35d3 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 15 Mar 2022 13:11:30 +0200 Subject: [PATCH 228/407] arch:arm:dts:ad6676: remove extra i2c node According to the hdl, there is no support for the LPC connector. Fixes eeprom error: `i2c: Timeout waiting at Tx empty` Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-ad6676-fmc.dts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad6676-fmc.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad6676-fmc.dts index f1c2e19f9f251f..457ce94c9a0a58 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad6676-fmc.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad6676-fmc.dts @@ -85,16 +85,6 @@ reg = <0x50>; }; }; - - i2c@6 { /* LPC IIC */ - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - eeprom@50 { - compatible = "at24,24c02"; - reg = <0x50>; - }; - }; }; &fpga_axi { From 0ca6842c122c4184f8febc88267aeb06ace0f5f6 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 15 Mar 2022 13:12:23 +0200 Subject: [PATCH 229/407] arch:arm:dts:fmclidar1: update slave address Slave address 0x50 is valid for the eeprom node. Fixes eeprom error: `i2c: Timeout waiting at Tx empty` Fixes: 0e85205 ("arch:arm:dts:fmclidar1: remove extra eeprom") Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts index ae6f9fa61ed4a6..d0d1f3d02b4455 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-fmclidar1.dts @@ -20,9 +20,9 @@ #size-cells = <0>; reg = <5>; - eeprom@54 { + eeprom@50 { compatible = "at24,24c02"; - reg = <0x54>; + reg = <0x50>; }; }; }; From c4bd94fa25a929817e95d388499911c49c8e79d6 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 14 Feb 2022 09:38:06 +0200 Subject: [PATCH 230/407] iio: introduce mag_referenced Some accelerometers that support activity and inactivity events also support a referenced mode, in which the gravitational acceleration is taken as a point of reference before comparing the acceleration to the specified activity and inactivity magnitude. For example, in the case of the ADXL367, for activity detection, the formula is: abs(acceleration - reference) > magnitude Add a new event type that makes this behavior clear. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220214073810.781016-2-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron (cherry picked from commit a1a5cfe70cd29a59a9a85290dfe95ed1c8df1193) --- drivers/iio/industrialio-event.c | 1 + include/uapi/linux/iio/types.h | 1 + tools/iio/iio_event_monitor.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 99ba657b856865..e3b3cdd7da2ca2 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -228,6 +228,7 @@ static const char * const iio_ev_type_text[] = { [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", [IIO_EV_TYPE_CHANGE] = "change", + [IIO_EV_TYPE_MAG_REFERENCED] = "mag_referenced", }; static const char * const iio_ev_dir_text[] = { diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index f591e090be6d05..2bf0ab09c7f588 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -106,6 +106,7 @@ enum iio_event_type { IIO_EV_TYPE_THRESH_ADAPTIVE, IIO_EV_TYPE_MAG_ADAPTIVE, IIO_EV_TYPE_CHANGE, + IIO_EV_TYPE_MAG_REFERENCED, }; enum iio_event_direction { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index d1e72d99d19496..3503200875d9b0 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -68,6 +68,7 @@ static const char * const iio_ev_type_text[] = { [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", [IIO_EV_TYPE_CHANGE] = "change", + [IIO_EV_TYPE_MAG_REFERENCED] = "mag_referenced", }; static const char * const iio_ev_dir_text[] = { From 3628336570480d1b17c9e5835b684190d80aaca1 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 14 Feb 2022 09:38:07 +0200 Subject: [PATCH 231/407] iio: ABI: document mag_referenced Some accelerometers that support activity and inactivity events also support a referenced mode, in which the gravitational acceleration is taken as a point of reference before comparing the acceleration to the specified activity and inactivity magnitude. For example, in the case of the ADXL367, for activity detection, the formula is: abs(acceleration - reference) > magnitude Add a new event type that makes this behavior clear. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220214073810.781016-3-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron (cherry picked from commit 89d185848633db2aa811131ac5db795d5366da78) --- Documentation/ABI/testing/sysfs-bus-iio | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index df42bed09f25d8..de64f0c2308dd9 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1089,6 +1089,32 @@ Description: number or direction is not specified, applies to all channels of this type. +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_en +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_rising_en +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_falling_en +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_en +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_rising_en +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_falling_en +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Similar to in_accel_mag[_y][_rising|_falling]_en, but the event + value is relative to a reference magnitude. The reference magnitude + includes the graviational acceleration. + +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_value +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_rising_value +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_falling_value +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_value +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_rising_value +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_falling_value +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + The value to which the reference magnitude of the channel is + compared. If the axis is not specified, it applies to all channels + of this type. + What: /sys/.../events/in_steps_change_en KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org From b4119029aa21dc8228331db22657fdbd45c4cbf6 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 14 Feb 2022 09:38:08 +0200 Subject: [PATCH 232/407] iio: ABI: add note about configuring other attributes during buffer capture It might be impossible to configure other attributes (e.g.: events, scale, sampling rate) if they impact the currently active buffer capture session. On ADXL367, writing to register before 0x2E requires the device to be placed in standby mode, otherwise the changes might be effective for only part of a measurement. To ensure this requirement, the configuration attributes of the IIO device try to claim direct mode before switching to standby mode. During a buffer capture, direct mode cannot be claimed, and the attribute write callback returns -EBUSY. Describe this behavior in the buffer/enable attribute description. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220214073810.781016-4-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron (cherry picked from commit 06a4a0cf698474ce5a19eb2854edcb6af51b8055) --- Documentation/ABI/testing/sysfs-bus-iio | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index de64f0c2308dd9..ca1e7fc3cf7948 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1154,6 +1154,10 @@ Description: Actually start the buffer capture up. Will start trigger if first device and appropriate. + Note that it might be impossible to configure other attributes, + (e.g.: events, scale, sampling rate) if they impact the currently + active buffer capture session. + What: /sys/bus/iio/devices/iio:deviceX/scan_elements KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org From ecb3e77ab8aa35071a653918861a700572173032 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 14 Feb 2022 09:38:09 +0200 Subject: [PATCH 233/407] dt-bindings: iio: accel: add ADXL367 The ADXL367 is an ultralow power, 3-axis MEMS accelerometer. The ADXL367 does not alias input signals to achieve ultralow power consumption, it samples the full bandwidth of the sensor at all data rates. Measurement ranges of +-2g, +-4g, and +-8g are available, with a resolution of 0.25mg/LSB on the +-2 g range. In addition to its ultralow power consumption, the ADXL367 has many features to enable true system level power reduction. It includes a deep multimode output FIFO, a built-in micropower temperature sensor, and an internal ADC for synchronous conversion of an additional analog input. Signed-off-by: Cosmin Tanislav Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220214073810.781016-5-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron (cherry picked from commit 27ae7f9d923885b6380c60dbe45d3bb19e885c5f) --- .../bindings/iio/accel/adi,adxl367.yaml | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml new file mode 100644 index 00000000000000..d259e796c1d688 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/accel/adi,adxl367.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADXL367 3-Axis Digital Accelerometer + +maintainers: + - Cosmin Tanislav + +description: | + The ADXL367 is an ultralow power, 3-axis MEMS accelerometer. + + The ADXL367 does not alias input signals by to achieve ultralow power + consumption, it samples the full bandwidth of the sensor at all + data rates. Measurement ranges of +-2g, +-4g, and +-8g are available, + with a resolution of 0.25mg/LSB on the +-2 g range. + + In addition to its ultralow power consumption, the ADXL367 + has many features to enable true system level power reduction. + It includes a deep multimode output FIFO, a built-in micropower + temperature sensor, and an internal ADC for synchronous conversion + of an additional analog input. + https://www.analog.com/en/products/adxl367.html + +properties: + compatible: + enum: + - adi,adxl367 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + spi-max-frequency: true + + vdd-supply: true + vddio-supply: true + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + accelerometer@53 { + compatible = "adi,adxl367"; + reg = <0x53>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + }; + }; + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + accelerometer@0 { + compatible = "adi,adxl367"; + reg = <0>; + spi-max-frequency = <1000000>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + }; + }; From da398388cd01d1b7929f955faa9bf6ae0c147e1e Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 14 Feb 2022 09:38:10 +0200 Subject: [PATCH 234/407] iio: accel: add ADXL367 driver The ADXL367 is an ultralow power, 3-axis MEMS accelerometer. The ADXL367 does not alias input signals to achieve ultralow power consumption, it samples the full bandwidth of the sensor at all data rates. Measurement ranges of +-2g, +-4g, and +-8g are available, with a resolution of 0.25mg/LSB on the +-2 g range. In addition to its ultralow power consumption, the ADXL367 has many features to enable true system level power reduction. It includes a deep multimode output FIFO, a built-in micropower temperature sensor, and an internal ADC for synchronous conversion of an additional analog input. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220214073810.781016-6-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron (cherry picked from commit cbab791c5e2a58c123d84bd9202c054e5449bc96) --- MAINTAINERS | 8 + drivers/iio/accel/Kconfig | 27 + drivers/iio/accel/Makefile | 3 + drivers/iio/accel/adxl367.c | 1592 +++++++++++++++++++++++++++++++ drivers/iio/accel/adxl367.h | 23 + drivers/iio/accel/adxl367_i2c.c | 90 ++ drivers/iio/accel/adxl367_spi.c | 164 ++++ 7 files changed, 1907 insertions(+) create mode 100644 drivers/iio/accel/adxl367.c create mode 100644 drivers/iio/accel/adxl367.h create mode 100644 drivers/iio/accel/adxl367_i2c.c create mode 100644 drivers/iio/accel/adxl367_spi.c diff --git a/MAINTAINERS b/MAINTAINERS index 39da035ef71614..50e0c96e47762b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -588,6 +588,14 @@ F: drivers/iio/accel/adxl355_core.c F: drivers/iio/accel/adxl355_i2c.c F: drivers/iio/accel/adxl355_spi.c +ADXL367 THREE-AXIS DIGITAL ACCELEROMETER DRIVER +M: Cosmin Tanislav +L: linux-iio@vger.kernel.org +S: Supported +W: http://ez.analog.com/community/linux-device-drivers +F: Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml +F: drivers/iio/accel/adxl367* + ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER M: Michael Hennerich S: Supported diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 46641ae499f7ed..2a97f80fd5dfa1 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -94,6 +94,33 @@ config ADXL355_SPI will be called adxl355_spi and you will also get adxl355_core for the core module. +config ADXL367 + tristate + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + +config ADXL367_SPI + tristate "Analog Devices ADXL367 3-Axis Accelerometer SPI Driver" + depends on SPI + select ADXL367 + select REGMAP_SPI + help + Say yes here to add support for the Analog Devices ADXL367 triaxial + acceleration sensor. + To compile this driver as a module, choose M here: the + module will be called adxl367_spi. + +config ADXL367_I2C + tristate "Analog Devices ADXL367 3-Axis Accelerometer I2C Driver" + depends on I2C + select ADXL367 + select REGMAP_I2C + help + Say yes here to add support for the Analog Devices ADXL367 triaxial + acceleration sensor. + To compile this driver as a module, choose M here: the + module will be called adxl367_i2c. + config ADXL372 tristate select IIO_BUFFER diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 9cafe4f7a647d8..b9abd58531a5ef 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -12,6 +12,9 @@ obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o obj-$(CONFIG_ADXL355) += adxl355_core.o obj-$(CONFIG_ADXL355_I2C) += adxl355_i2c.o obj-$(CONFIG_ADXL355_SPI) += adxl355_spi.o +obj-$(CONFIG_ADXL367) += adxl367.o +obj-$(CONFIG_ADXL367_I2C) += adxl367_i2c.o +obj-$(CONFIG_ADXL367_SPI) += adxl367_spi.o obj-$(CONFIG_ADXL372) += adxl372.o obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c new file mode 100644 index 00000000000000..91bb36181e2554 --- /dev/null +++ b/drivers/iio/accel/adxl367.c @@ -0,0 +1,1592 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Analog Devices, Inc. + * Author: Cosmin Tanislav + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adxl367.h" + +#define ADXL367_REG_DEVID 0x00 +#define ADXL367_DEVID_AD 0xAD + +#define ADXL367_REG_STATUS 0x0B +#define ADXL367_STATUS_INACT_MASK BIT(5) +#define ADXL367_STATUS_ACT_MASK BIT(4) +#define ADXL367_STATUS_FIFO_FULL_MASK BIT(2) + +#define ADXL367_FIFO_ENT_H_MASK GENMASK(1, 0) + +#define ADXL367_REG_X_DATA_H 0x0E +#define ADXL367_REG_Y_DATA_H 0x10 +#define ADXL367_REG_Z_DATA_H 0x12 +#define ADXL367_REG_TEMP_DATA_H 0x14 +#define ADXL367_REG_EX_ADC_DATA_H 0x16 +#define ADXL367_DATA_MASK GENMASK(15, 2) + +#define ADXL367_TEMP_25C 165 +#define ADXL367_TEMP_PER_C 54 + +#define ADXL367_VOLTAGE_OFFSET 8192 +#define ADXL367_VOLTAGE_MAX_MV 1000 +#define ADXL367_VOLTAGE_MAX_RAW GENMASK(13, 0) + +#define ADXL367_REG_RESET 0x1F +#define ADXL367_RESET_CODE 0x52 + +#define ADXL367_REG_THRESH_ACT_H 0x20 +#define ADXL367_REG_THRESH_INACT_H 0x23 +#define ADXL367_THRESH_MAX GENMASK(12, 0) +#define ADXL367_THRESH_VAL_H_MASK GENMASK(12, 6) +#define ADXL367_THRESH_H_MASK GENMASK(6, 0) +#define ADXL367_THRESH_VAL_L_MASK GENMASK(5, 0) +#define ADXL367_THRESH_L_MASK GENMASK(7, 2) + +#define ADXL367_REG_TIME_ACT 0x22 +#define ADXL367_REG_TIME_INACT_H 0x25 +#define ADXL367_TIME_ACT_MAX GENMASK(7, 0) +#define ADXL367_TIME_INACT_MAX GENMASK(15, 0) +#define ADXL367_TIME_INACT_VAL_H_MASK GENMASK(15, 8) +#define ADXL367_TIME_INACT_H_MASK GENMASK(7, 0) +#define ADXL367_TIME_INACT_VAL_L_MASK GENMASK(7, 0) +#define ADXL367_TIME_INACT_L_MASK GENMASK(7, 0) + +#define ADXL367_REG_ACT_INACT_CTL 0x27 +#define ADXL367_ACT_EN_MASK GENMASK(1, 0) +#define ADXL367_ACT_LINKLOOP_MASK GENMASK(5, 4) + +#define ADXL367_REG_FIFO_CTL 0x28 +#define ADXL367_FIFO_CTL_FORMAT_MASK GENMASK(6, 3) +#define ADXL367_FIFO_CTL_MODE_MASK GENMASK(1, 0) + +#define ADXL367_REG_FIFO_SAMPLES 0x29 +#define ADXL367_FIFO_SIZE 512 +#define ADXL367_FIFO_MAX_WATERMARK 511 + +#define ADXL367_SAMPLES_VAL_H_MASK BIT(8) +#define ADXL367_SAMPLES_H_MASK BIT(2) +#define ADXL367_SAMPLES_VAL_L_MASK GENMASK(7, 0) +#define ADXL367_SAMPLES_L_MASK GENMASK(7, 0) + +#define ADXL367_REG_INT1_MAP 0x2A +#define ADXL367_INT_INACT_MASK BIT(5) +#define ADXL367_INT_ACT_MASK BIT(4) +#define ADXL367_INT_FIFO_WATERMARK_MASK BIT(2) + +#define ADXL367_REG_FILTER_CTL 0x2C +#define ADXL367_FILTER_CTL_RANGE_MASK GENMASK(7, 6) +#define ADXL367_2G_RANGE_1G 4095 +#define ADXL367_2G_RANGE_100MG 409 +#define ADXL367_FILTER_CTL_ODR_MASK GENMASK(2, 0) + +#define ADXL367_REG_POWER_CTL 0x2D +#define ADXL367_POWER_CTL_MODE_MASK GENMASK(1, 0) + +#define ADXL367_REG_ADC_CTL 0x3C +#define ADXL367_REG_TEMP_CTL 0x3D +#define ADXL367_ADC_EN_MASK BIT(0) + +enum adxl367_range { + ADXL367_2G_RANGE, + ADXL367_4G_RANGE, + ADXL367_8G_RANGE, +}; + +enum adxl367_fifo_mode { + ADXL367_FIFO_MODE_DISABLED = 0b00, + ADXL367_FIFO_MODE_STREAM = 0b10, +}; + +enum adxl367_fifo_format { + ADXL367_FIFO_FORMAT_XYZ, + ADXL367_FIFO_FORMAT_X, + ADXL367_FIFO_FORMAT_Y, + ADXL367_FIFO_FORMAT_Z, + ADXL367_FIFO_FORMAT_XYZT, + ADXL367_FIFO_FORMAT_XT, + ADXL367_FIFO_FORMAT_YT, + ADXL367_FIFO_FORMAT_ZT, + ADXL367_FIFO_FORMAT_XYZA, + ADXL367_FIFO_FORMAT_XA, + ADXL367_FIFO_FORMAT_YA, + ADXL367_FIFO_FORMAT_ZA, +}; + +enum adxl367_op_mode { + ADXL367_OP_STANDBY = 0b00, + ADXL367_OP_MEASURE = 0b10, +}; + +enum adxl367_act_proc_mode { + ADXL367_LOOPED = 0b11, +}; + +enum adxl367_act_en_mode { + ADXL367_ACT_DISABLED = 0b00, + ADCL367_ACT_REF_ENABLED = 0b11, +}; + +enum adxl367_activity_type { + ADXL367_ACTIVITY, + ADXL367_INACTIVITY, +}; + +enum adxl367_odr { + ADXL367_ODR_12P5HZ, + ADXL367_ODR_25HZ, + ADXL367_ODR_50HZ, + ADXL367_ODR_100HZ, + ADXL367_ODR_200HZ, + ADXL367_ODR_400HZ, +}; + +struct adxl367_state { + const struct adxl367_ops *ops; + void *context; + + struct device *dev; + struct regmap *regmap; + + struct regulator_bulk_data regulators[2]; + + /* + * Synchronize access to members of driver state, and ensure atomicity + * of consecutive regmap operations. + */ + struct mutex lock; + + enum adxl367_odr odr; + enum adxl367_range range; + + unsigned int act_threshold; + unsigned int act_time_ms; + unsigned int inact_threshold; + unsigned int inact_time_ms; + + unsigned int fifo_set_size; + unsigned int fifo_watermark; + + __be16 fifo_buf[ADXL367_FIFO_SIZE] ____cacheline_aligned; + __be16 sample_buf; + u8 act_threshold_buf[2]; + u8 inact_time_buf[2]; + u8 status_buf[3]; +}; + +static const unsigned int adxl367_threshold_h_reg_tbl[] = { + [ADXL367_ACTIVITY] = ADXL367_REG_THRESH_ACT_H, + [ADXL367_INACTIVITY] = ADXL367_REG_THRESH_INACT_H, +}; + +static const unsigned int adxl367_act_en_shift_tbl[] = { + [ADXL367_ACTIVITY] = 0, + [ADXL367_INACTIVITY] = 2, +}; + +static const unsigned int adxl367_act_int_mask_tbl[] = { + [ADXL367_ACTIVITY] = ADXL367_INT_ACT_MASK, + [ADXL367_INACTIVITY] = ADXL367_INT_INACT_MASK, +}; + +static const int adxl367_samp_freq_tbl[][2] = { + [ADXL367_ODR_12P5HZ] = {12, 500000}, + [ADXL367_ODR_25HZ] = {25, 0}, + [ADXL367_ODR_50HZ] = {50, 0}, + [ADXL367_ODR_100HZ] = {100, 0}, + [ADXL367_ODR_200HZ] = {200, 0}, + [ADXL367_ODR_400HZ] = {400, 0}, +}; + +/* (g * 2) * 9.80665 * 1000000 / (2^14 - 1) */ +static const int adxl367_range_scale_tbl[][2] = { + [ADXL367_2G_RANGE] = {0, 2394347}, + [ADXL367_4G_RANGE] = {0, 4788695}, + [ADXL367_8G_RANGE] = {0, 9577391}, +}; + +static const int adxl367_range_scale_factor_tbl[] = { + [ADXL367_2G_RANGE] = 1, + [ADXL367_4G_RANGE] = 2, + [ADXL367_8G_RANGE] = 4, +}; + +enum { + ADXL367_X_CHANNEL_INDEX, + ADXL367_Y_CHANNEL_INDEX, + ADXL367_Z_CHANNEL_INDEX, + ADXL367_TEMP_CHANNEL_INDEX, + ADXL367_EX_ADC_CHANNEL_INDEX +}; + +#define ADXL367_X_CHANNEL_MASK BIT(ADXL367_X_CHANNEL_INDEX) +#define ADXL367_Y_CHANNEL_MASK BIT(ADXL367_Y_CHANNEL_INDEX) +#define ADXL367_Z_CHANNEL_MASK BIT(ADXL367_Z_CHANNEL_INDEX) +#define ADXL367_TEMP_CHANNEL_MASK BIT(ADXL367_TEMP_CHANNEL_INDEX) +#define ADXL367_EX_ADC_CHANNEL_MASK BIT(ADXL367_EX_ADC_CHANNEL_INDEX) + +static const enum adxl367_fifo_format adxl367_fifo_formats[] = { + ADXL367_FIFO_FORMAT_X, + ADXL367_FIFO_FORMAT_Y, + ADXL367_FIFO_FORMAT_Z, + ADXL367_FIFO_FORMAT_XT, + ADXL367_FIFO_FORMAT_YT, + ADXL367_FIFO_FORMAT_ZT, + ADXL367_FIFO_FORMAT_XA, + ADXL367_FIFO_FORMAT_YA, + ADXL367_FIFO_FORMAT_ZA, + ADXL367_FIFO_FORMAT_XYZ, + ADXL367_FIFO_FORMAT_XYZT, + ADXL367_FIFO_FORMAT_XYZA, +}; + +static const unsigned long adxl367_channel_masks[] = { + ADXL367_X_CHANNEL_MASK, + ADXL367_Y_CHANNEL_MASK, + ADXL367_Z_CHANNEL_MASK, + ADXL367_X_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK, + ADXL367_Y_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK, + ADXL367_Z_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK, + ADXL367_X_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK, + ADXL367_Y_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK, + ADXL367_Z_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK, + ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK, + ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK | + ADXL367_TEMP_CHANNEL_MASK, + ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK | + ADXL367_EX_ADC_CHANNEL_MASK, + 0, +}; + +static int adxl367_set_measure_en(struct adxl367_state *st, bool en) +{ + enum adxl367_op_mode op_mode = en ? ADXL367_OP_MEASURE + : ADXL367_OP_STANDBY; + int ret; + + ret = regmap_update_bits(st->regmap, ADXL367_REG_POWER_CTL, + ADXL367_POWER_CTL_MODE_MASK, + FIELD_PREP(ADXL367_POWER_CTL_MODE_MASK, + op_mode)); + if (ret) + return ret; + + /* + * Wait for acceleration output to settle after entering + * measure mode. + */ + if (en) + msleep(100); + + return 0; +} + +static void adxl367_scale_act_thresholds(struct adxl367_state *st, + enum adxl367_range old_range, + enum adxl367_range new_range) +{ + st->act_threshold = st->act_threshold + * adxl367_range_scale_factor_tbl[old_range] + / adxl367_range_scale_factor_tbl[new_range]; + st->inact_threshold = st->inact_threshold + * adxl367_range_scale_factor_tbl[old_range] + / adxl367_range_scale_factor_tbl[new_range]; +} + +static int _adxl367_set_act_threshold(struct adxl367_state *st, + enum adxl367_activity_type act, + unsigned int threshold) +{ + u8 reg = adxl367_threshold_h_reg_tbl[act]; + int ret; + + if (threshold > ADXL367_THRESH_MAX) + return -EINVAL; + + st->act_threshold_buf[0] = FIELD_PREP(ADXL367_THRESH_H_MASK, + FIELD_GET(ADXL367_THRESH_VAL_H_MASK, + threshold)); + st->act_threshold_buf[1] = FIELD_PREP(ADXL367_THRESH_L_MASK, + FIELD_GET(ADXL367_THRESH_VAL_L_MASK, + threshold)); + + ret = regmap_bulk_write(st->regmap, reg, st->act_threshold_buf, + sizeof(st->act_threshold_buf)); + if (ret) + return ret; + + if (act == ADXL367_ACTIVITY) + st->act_threshold = threshold; + else + st->inact_threshold = threshold; + + return 0; +} + +static int adxl367_set_act_threshold(struct adxl367_state *st, + enum adxl367_activity_type act, + unsigned int threshold) +{ + int ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = _adxl367_set_act_threshold(st, act, threshold); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static int adxl367_set_act_proc_mode(struct adxl367_state *st, + enum adxl367_act_proc_mode mode) +{ + return regmap_update_bits(st->regmap, ADXL367_REG_ACT_INACT_CTL, + ADXL367_ACT_LINKLOOP_MASK, + FIELD_PREP(ADXL367_ACT_LINKLOOP_MASK, + mode)); +} + +static int adxl367_set_act_interrupt_en(struct adxl367_state *st, + enum adxl367_activity_type act, + bool en) +{ + unsigned int mask = adxl367_act_int_mask_tbl[act]; + + return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP, + mask, en ? mask : 0); +} + +static int adxl367_get_act_interrupt_en(struct adxl367_state *st, + enum adxl367_activity_type act, + bool *en) +{ + unsigned int mask = adxl367_act_int_mask_tbl[act]; + unsigned int val; + int ret; + + ret = regmap_read(st->regmap, ADXL367_REG_INT1_MAP, &val); + if (ret) + return ret; + + *en = !!(val & mask); + + return 0; +} + +static int adxl367_set_act_en(struct adxl367_state *st, + enum adxl367_activity_type act, + enum adxl367_act_en_mode en) +{ + unsigned int ctl_shift = adxl367_act_en_shift_tbl[act]; + + return regmap_update_bits(st->regmap, ADXL367_REG_ACT_INACT_CTL, + ADXL367_ACT_EN_MASK << ctl_shift, + en << ctl_shift); +} + +static int adxl367_set_fifo_watermark_interrupt_en(struct adxl367_state *st, + bool en) +{ + return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP, + ADXL367_INT_FIFO_WATERMARK_MASK, + en ? ADXL367_INT_FIFO_WATERMARK_MASK : 0); +} + +static int adxl367_get_fifo_mode(struct adxl367_state *st, + enum adxl367_fifo_mode *fifo_mode) +{ + unsigned int val; + int ret; + + ret = regmap_read(st->regmap, ADXL367_REG_FIFO_CTL, &val); + if (ret) + return ret; + + *fifo_mode = FIELD_GET(ADXL367_FIFO_CTL_MODE_MASK, val); + + return 0; +} + +static int adxl367_set_fifo_mode(struct adxl367_state *st, + enum adxl367_fifo_mode fifo_mode) +{ + return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL, + ADXL367_FIFO_CTL_MODE_MASK, + FIELD_PREP(ADXL367_FIFO_CTL_MODE_MASK, + fifo_mode)); +} + +static int adxl367_set_fifo_format(struct adxl367_state *st, + enum adxl367_fifo_format fifo_format) +{ + return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL, + ADXL367_FIFO_CTL_FORMAT_MASK, + FIELD_PREP(ADXL367_FIFO_CTL_FORMAT_MASK, + fifo_format)); +} + +static int adxl367_set_fifo_samples(struct adxl367_state *st, + unsigned int fifo_watermark, + unsigned int fifo_set_size) +{ + unsigned int fifo_samples = fifo_watermark * fifo_set_size; + unsigned int fifo_samples_h, fifo_samples_l; + int ret; + + if (fifo_samples > ADXL367_FIFO_MAX_WATERMARK) + fifo_samples = ADXL367_FIFO_MAX_WATERMARK; + + if (fifo_set_size == 0) + return 0; + + fifo_samples /= fifo_set_size; + + fifo_samples_h = FIELD_PREP(ADXL367_SAMPLES_H_MASK, + FIELD_GET(ADXL367_SAMPLES_VAL_H_MASK, + fifo_samples)); + fifo_samples_l = FIELD_PREP(ADXL367_SAMPLES_L_MASK, + FIELD_GET(ADXL367_SAMPLES_VAL_L_MASK, + fifo_samples)); + + ret = regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL, + ADXL367_SAMPLES_H_MASK, fifo_samples_h); + if (ret) + return ret; + + return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_SAMPLES, + ADXL367_SAMPLES_L_MASK, fifo_samples_l); +} + +static int adxl367_set_fifo_set_size(struct adxl367_state *st, + unsigned int fifo_set_size) +{ + int ret; + + ret = adxl367_set_fifo_samples(st, st->fifo_watermark, fifo_set_size); + if (ret) + return ret; + + st->fifo_set_size = fifo_set_size; + + return 0; +} + +static int adxl367_set_fifo_watermark(struct adxl367_state *st, + unsigned int fifo_watermark) +{ + int ret; + + ret = adxl367_set_fifo_samples(st, fifo_watermark, st->fifo_set_size); + if (ret) + return ret; + + st->fifo_watermark = fifo_watermark; + + return 0; +} + +static int adxl367_set_range(struct iio_dev *indio_dev, + enum adxl367_range range) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL, + ADXL367_FILTER_CTL_RANGE_MASK, + FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK, + range)); + if (ret) + goto out; + + adxl367_scale_act_thresholds(st, st->range, range); + + /* Activity thresholds depend on range */ + ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY, + st->act_threshold); + if (ret) + goto out; + + ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY, + st->inact_threshold); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + if (ret) + goto out; + + st->range = range; + +out: + mutex_unlock(&st->lock); + + iio_device_release_direct_mode(indio_dev); + + return ret; +} + +static int adxl367_time_ms_to_samples(struct adxl367_state *st, unsigned int ms) +{ + int freq_hz = adxl367_samp_freq_tbl[st->odr][0]; + int freq_microhz = adxl367_samp_freq_tbl[st->odr][1]; + /* Scale to decihertz to prevent precision loss in 12.5Hz case. */ + int freq_dhz = freq_hz * 10 + freq_microhz / 100000; + + return DIV_ROUND_CLOSEST(ms * freq_dhz, 10000); +} + +static int _adxl367_set_act_time_ms(struct adxl367_state *st, unsigned int ms) +{ + unsigned int val = adxl367_time_ms_to_samples(st, ms); + int ret; + + if (val > ADXL367_TIME_ACT_MAX) + val = ADXL367_TIME_ACT_MAX; + + ret = regmap_write(st->regmap, ADXL367_REG_TIME_ACT, val); + if (ret) + return ret; + + st->act_time_ms = ms; + + return 0; +} + +static int _adxl367_set_inact_time_ms(struct adxl367_state *st, unsigned int ms) +{ + unsigned int val = adxl367_time_ms_to_samples(st, ms); + int ret; + + if (val > ADXL367_TIME_INACT_MAX) + val = ADXL367_TIME_INACT_MAX; + + st->inact_time_buf[0] = FIELD_PREP(ADXL367_TIME_INACT_H_MASK, + FIELD_GET(ADXL367_TIME_INACT_VAL_H_MASK, + val)); + st->inact_time_buf[1] = FIELD_PREP(ADXL367_TIME_INACT_L_MASK, + FIELD_GET(ADXL367_TIME_INACT_VAL_L_MASK, + val)); + + ret = regmap_bulk_write(st->regmap, ADXL367_REG_TIME_INACT_H, + st->inact_time_buf, sizeof(st->inact_time_buf)); + if (ret) + return ret; + + st->inact_time_ms = ms; + + return 0; +} + +static int adxl367_set_act_time_ms(struct adxl367_state *st, + enum adxl367_activity_type act, + unsigned int ms) +{ + int ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + if (act == ADXL367_ACTIVITY) + ret = _adxl367_set_act_time_ms(st, ms); + else + ret = _adxl367_set_inact_time_ms(st, ms); + + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr) +{ + int ret; + + ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL, + ADXL367_FILTER_CTL_ODR_MASK, + FIELD_PREP(ADXL367_FILTER_CTL_ODR_MASK, + odr)); + if (ret) + return ret; + + /* Activity timers depend on ODR */ + ret = _adxl367_set_act_time_ms(st, st->act_time_ms); + if (ret) + return ret; + + ret = _adxl367_set_inact_time_ms(st, st->inact_time_ms); + if (ret) + return ret; + + st->odr = odr; + + return 0; +} + +static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = _adxl367_set_odr(st, odr); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + iio_device_release_direct_mode(indio_dev); + + return ret; +} + +static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg, + bool en) +{ + return regmap_update_bits(st->regmap, reg, ADXL367_ADC_EN_MASK, + en ? ADXL367_ADC_EN_MASK : 0); +} + +static int adxl367_set_temp_adc_reg_en(struct adxl367_state *st, + unsigned int reg, bool en) +{ + int ret; + + switch (reg) { + case ADXL367_REG_TEMP_DATA_H: + ret = adxl367_set_temp_adc_en(st, ADXL367_REG_TEMP_CTL, en); + break; + case ADXL367_REG_EX_ADC_DATA_H: + ret = adxl367_set_temp_adc_en(st, ADXL367_REG_ADC_CTL, en); + break; + default: + return 0; + } + + if (ret) + return ret; + + if (en) + msleep(100); + + return 0; +} + +static int adxl367_set_temp_adc_mask_en(struct adxl367_state *st, + const unsigned long *active_scan_mask, + bool en) +{ + if (*active_scan_mask & ADXL367_TEMP_CHANNEL_MASK) + return adxl367_set_temp_adc_en(st, ADXL367_REG_TEMP_CTL, en); + else if (*active_scan_mask & ADXL367_EX_ADC_CHANNEL_MASK) + return adxl367_set_temp_adc_en(st, ADXL367_REG_ADC_CTL, en); + + return 0; +} + +static int adxl367_find_odr(struct adxl367_state *st, int val, int val2, + enum adxl367_odr *odr) +{ + size_t size = ARRAY_SIZE(adxl367_samp_freq_tbl); + int i; + + for (i = 0; i < size; i++) + if (val == adxl367_samp_freq_tbl[i][0] && + val2 == adxl367_samp_freq_tbl[i][1]) + break; + + if (i == size) + return -EINVAL; + + *odr = i; + + return 0; +} + +static int adxl367_find_range(struct adxl367_state *st, int val, int val2, + enum adxl367_range *range) +{ + size_t size = ARRAY_SIZE(adxl367_range_scale_tbl); + int i; + + for (i = 0; i < size; i++) + if (val == adxl367_range_scale_tbl[i][0] && + val2 == adxl367_range_scale_tbl[i][1]) + break; + + if (i == size) + return -EINVAL; + + *range = i; + + return 0; +} + +static int adxl367_read_sample(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val) +{ + struct adxl367_state *st = iio_priv(indio_dev); + u16 sample; + int ret; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_temp_adc_reg_en(st, chan->address, true); + if (ret) + goto out; + + ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf, + sizeof(st->sample_buf)); + if (ret) + goto out; + + sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf)); + *val = sign_extend32(sample, chan->scan_type.realbits - 1); + + ret = adxl367_set_temp_adc_reg_en(st, chan->address, false); + +out: + mutex_unlock(&st->lock); + + iio_device_release_direct_mode(indio_dev); + + return ret ?: IIO_VAL_INT; +} + +static int adxl367_get_status(struct adxl367_state *st, u8 *status, + u16 *fifo_entries) +{ + int ret; + + /* Read STATUS, FIFO_ENT_L and FIFO_ENT_H */ + ret = regmap_bulk_read(st->regmap, ADXL367_REG_STATUS, + st->status_buf, sizeof(st->status_buf)); + if (ret) + return ret; + + st->status_buf[2] &= ADXL367_FIFO_ENT_H_MASK; + + *status = st->status_buf[0]; + *fifo_entries = get_unaligned_le16(&st->status_buf[1]); + + return 0; +} + +static bool adxl367_push_event(struct iio_dev *indio_dev, u8 status) +{ + unsigned int ev_dir; + + if (FIELD_GET(ADXL367_STATUS_ACT_MASK, status)) + ev_dir = IIO_EV_DIR_RISING; + else if (FIELD_GET(ADXL367_STATUS_INACT_MASK, status)) + ev_dir = IIO_EV_DIR_FALLING; + else + return false; + + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_THRESH, ev_dir), + iio_get_time_ns(indio_dev)); + + return true; +} + +static bool adxl367_push_fifo_data(struct iio_dev *indio_dev, u8 status, + u16 fifo_entries) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + int i; + + if (!FIELD_GET(ADXL367_STATUS_FIFO_FULL_MASK, status)) + return false; + + fifo_entries -= fifo_entries % st->fifo_set_size; + + ret = st->ops->read_fifo(st->context, st->fifo_buf, fifo_entries); + if (ret) { + dev_err(st->dev, "Failed to read FIFO: %d\n", ret); + return true; + } + + for (i = 0; i < fifo_entries; i += st->fifo_set_size) + iio_push_to_buffers(indio_dev, &st->fifo_buf[i]); + + return true; +} + +static irqreturn_t adxl367_irq_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct adxl367_state *st = iio_priv(indio_dev); + u16 fifo_entries; + bool handled; + u8 status; + int ret; + + ret = adxl367_get_status(st, &status, &fifo_entries); + if (ret) + return IRQ_NONE; + + handled |= adxl367_push_event(indio_dev, status); + handled |= adxl367_push_fifo_data(indio_dev, status, fifo_entries); + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static int adxl367_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct adxl367_state *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + else + return regmap_write(st->regmap, reg, writeval); +} + +static int adxl367_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct adxl367_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + return adxl367_read_sample(indio_dev, chan, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ACCEL: + mutex_lock(&st->lock); + *val = adxl367_range_scale_tbl[st->range][0]; + *val2 = adxl367_range_scale_tbl[st->range][1]; + mutex_unlock(&st->lock); + return IIO_VAL_INT_PLUS_NANO; + case IIO_TEMP: + *val = 1000; + *val2 = ADXL367_TEMP_PER_C; + return IIO_VAL_FRACTIONAL; + case IIO_VOLTAGE: + *val = ADXL367_VOLTAGE_MAX_MV; + *val2 = ADXL367_VOLTAGE_MAX_RAW; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_TEMP: + *val = 25 * ADXL367_TEMP_PER_C - ADXL367_TEMP_25C; + return IIO_VAL_INT; + case IIO_VOLTAGE: + *val = ADXL367_VOLTAGE_OFFSET; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&st->lock); + *val = adxl367_samp_freq_tbl[st->odr][0]; + *val2 = adxl367_samp_freq_tbl[st->odr][1]; + mutex_unlock(&st->lock); + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int adxl367_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: { + enum adxl367_odr odr; + + ret = adxl367_find_odr(st, val, val2, &odr); + if (ret) + return ret; + + return adxl367_set_odr(indio_dev, odr); + } + case IIO_CHAN_INFO_SCALE: { + enum adxl367_range range; + + ret = adxl367_find_range(st, val, val2, &range); + if (ret) + return ret; + + return adxl367_set_range(indio_dev, range); + } + default: + return -EINVAL; + } +} + +static int adxl367_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long info) +{ + switch (info) { + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_ACCEL) + return -EINVAL; + + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } +} + +static int adxl367_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + switch (info) { + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_ACCEL) + return -EINVAL; + + *vals = (int *)adxl367_range_scale_tbl; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(adxl367_range_scale_tbl) * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = (int *)adxl367_samp_freq_tbl; + *type = IIO_VAL_INT_PLUS_MICRO; + *length = ARRAY_SIZE(adxl367_samp_freq_tbl) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int adxl367_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct adxl367_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_EV_INFO_VALUE: { + switch (dir) { + case IIO_EV_DIR_RISING: + mutex_lock(&st->lock); + *val = st->act_threshold; + mutex_unlock(&st->lock); + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + mutex_lock(&st->lock); + *val = st->inact_threshold; + mutex_unlock(&st->lock); + return IIO_VAL_INT; + default: + return -EINVAL; + } + } + case IIO_EV_INFO_PERIOD: + switch (dir) { + case IIO_EV_DIR_RISING: + mutex_lock(&st->lock); + *val = st->act_time_ms; + mutex_unlock(&st->lock); + *val2 = 1000; + return IIO_VAL_FRACTIONAL; + case IIO_EV_DIR_FALLING: + mutex_lock(&st->lock); + *val = st->inact_time_ms; + mutex_unlock(&st->lock); + *val2 = 1000; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl367_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct adxl367_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_EV_INFO_VALUE: + if (val < 0) + return -EINVAL; + + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl367_set_act_threshold(st, ADXL367_ACTIVITY, val); + case IIO_EV_DIR_FALLING: + return adxl367_set_act_threshold(st, ADXL367_INACTIVITY, val); + default: + return -EINVAL; + } + case IIO_EV_INFO_PERIOD: + if (val < 0) + return -EINVAL; + + val = val * 1000 + DIV_ROUND_UP(val2, 1000); + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl367_set_act_time_ms(st, ADXL367_ACTIVITY, val); + case IIO_EV_DIR_FALLING: + return adxl367_set_act_time_ms(st, ADXL367_INACTIVITY, val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl367_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct adxl367_state *st = iio_priv(indio_dev); + bool en; + int ret; + + switch (dir) { + case IIO_EV_DIR_RISING: + ret = adxl367_get_act_interrupt_en(st, ADXL367_ACTIVITY, &en); + return ret ?: en; + case IIO_EV_DIR_FALLING: + ret = adxl367_get_act_interrupt_en(st, ADXL367_INACTIVITY, &en); + return ret ?: en; + default: + return -EINVAL; + } +} + +static int adxl367_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct adxl367_state *st = iio_priv(indio_dev); + enum adxl367_activity_type act; + int ret; + + switch (dir) { + case IIO_EV_DIR_RISING: + act = ADXL367_ACTIVITY; + break; + case IIO_EV_DIR_FALLING: + act = ADXL367_INACTIVITY; + break; + default: + return -EINVAL; + } + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_act_interrupt_en(st, act, state); + if (ret) + goto out; + + ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED + : ADXL367_ACT_DISABLED); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + iio_device_release_direct_mode(indio_dev); + + return ret; +} + +static ssize_t adxl367_get_fifo_enabled(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev)); + enum adxl367_fifo_mode fifo_mode; + int ret; + + ret = adxl367_get_fifo_mode(st, &fifo_mode); + if (ret) + return ret; + + return sysfs_emit(buf, "%d\n", fifo_mode != ADXL367_FIFO_MODE_DISABLED); +} + +static ssize_t adxl367_get_fifo_watermark(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev)); + unsigned int fifo_watermark; + + mutex_lock(&st->lock); + fifo_watermark = st->fifo_watermark; + mutex_unlock(&st->lock); + + return sysfs_emit(buf, "%d\n", fifo_watermark); +} + +static IIO_CONST_ATTR(hwfifo_watermark_min, "1"); +static IIO_CONST_ATTR(hwfifo_watermark_max, + __stringify(ADXL367_FIFO_MAX_WATERMARK)); +static IIO_DEVICE_ATTR(hwfifo_watermark, 0444, + adxl367_get_fifo_watermark, NULL, 0); +static IIO_DEVICE_ATTR(hwfifo_enabled, 0444, + adxl367_get_fifo_enabled, NULL, 0); + +static const struct attribute *adxl367_fifo_attributes[] = { + &iio_const_attr_hwfifo_watermark_min.dev_attr.attr, + &iio_const_attr_hwfifo_watermark_max.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark.dev_attr.attr, + &iio_dev_attr_hwfifo_enabled.dev_attr.attr, + NULL, +}; + +static int adxl367_set_watermark(struct iio_dev *indio_dev, unsigned int val) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + if (val > ADXL367_FIFO_MAX_WATERMARK) + return -EINVAL; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_fifo_watermark(st, val); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static bool adxl367_find_mask_fifo_format(const unsigned long *scan_mask, + enum adxl367_fifo_format *fifo_format) +{ + size_t size = ARRAY_SIZE(adxl367_fifo_formats); + int i; + + for (i = 0; i < size; i++) + if (*scan_mask == adxl367_channel_masks[i]) + break; + + if (i == size) + return false; + + *fifo_format = adxl367_fifo_formats[i]; + + return true; +} + +static int adxl367_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *active_scan_mask) +{ + struct adxl367_state *st = iio_priv(indio_dev); + enum adxl367_fifo_format fifo_format; + unsigned int fifo_set_size; + int ret; + + if (!adxl367_find_mask_fifo_format(active_scan_mask, &fifo_format)) + return -EINVAL; + + fifo_set_size = bitmap_weight(active_scan_mask, indio_dev->masklength); + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_fifo_format(st, fifo_format); + if (ret) + goto out; + + ret = adxl367_set_fifo_set_size(st, fifo_set_size); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static int adxl367_buffer_postenable(struct iio_dev *indio_dev) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, + true); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_fifo_watermark_interrupt_en(st, true); + if (ret) + goto out; + + ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_STREAM); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static int adxl367_buffer_predisable(struct iio_dev *indio_dev) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_DISABLED); + if (ret) + goto out; + + ret = adxl367_set_fifo_watermark_interrupt_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + if (ret) + return ret; + + ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, + false); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static const struct iio_buffer_setup_ops adxl367_buffer_ops = { + .postenable = adxl367_buffer_postenable, + .predisable = adxl367_buffer_predisable, +}; + +static const struct iio_info adxl367_info = { + .read_raw = adxl367_read_raw, + .write_raw = adxl367_write_raw, + .write_raw_get_fmt = adxl367_write_raw_get_fmt, + .read_avail = adxl367_read_avail, + .read_event_config = adxl367_read_event_config, + .write_event_config = adxl367_write_event_config, + .read_event_value = adxl367_read_event_value, + .write_event_value = adxl367_write_event_value, + .debugfs_reg_access = adxl367_reg_access, + .hwfifo_set_watermark = adxl367_set_watermark, + .update_scan_mode = adxl367_update_scan_mode, +}; + +static const struct iio_event_spec adxl367_events[] = { + { + .type = IIO_EV_TYPE_MAG_REFERENCED, + .dir = IIO_EV_DIR_RISING, + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_PERIOD) | + BIT(IIO_EV_INFO_VALUE), + }, + { + .type = IIO_EV_TYPE_MAG_REFERENCED, + .dir = IIO_EV_DIR_FALLING, + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_PERIOD) | + BIT(IIO_EV_INFO_VALUE), + }, +}; + +#define ADXL367_ACCEL_CHANNEL(index, reg, axis) { \ + .type = IIO_ACCEL, \ + .address = (reg), \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .event_spec = adxl367_events, \ + .num_event_specs = ARRAY_SIZE(adxl367_events), \ + .scan_index = (index), \ + .scan_type = { \ + .sign = 's', \ + .realbits = 14, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ +} + +#define ADXL367_CHANNEL(index, reg, _type) { \ + .type = (_type), \ + .address = (reg), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = (index), \ + .scan_type = { \ + .sign = 's', \ + .realbits = 14, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ +} + +static const struct iio_chan_spec adxl367_channels[] = { + ADXL367_ACCEL_CHANNEL(ADXL367_X_CHANNEL_INDEX, ADXL367_REG_X_DATA_H, X), + ADXL367_ACCEL_CHANNEL(ADXL367_Y_CHANNEL_INDEX, ADXL367_REG_Y_DATA_H, Y), + ADXL367_ACCEL_CHANNEL(ADXL367_Z_CHANNEL_INDEX, ADXL367_REG_Z_DATA_H, Z), + ADXL367_CHANNEL(ADXL367_TEMP_CHANNEL_INDEX, ADXL367_REG_TEMP_DATA_H, + IIO_TEMP), + ADXL367_CHANNEL(ADXL367_EX_ADC_CHANNEL_INDEX, ADXL367_REG_EX_ADC_DATA_H, + IIO_VOLTAGE), +}; + +static int adxl367_verify_devid(struct adxl367_state *st) +{ + unsigned int val; + int ret; + + ret = regmap_read_poll_timeout(st->regmap, ADXL367_REG_DEVID, val, + val == ADXL367_DEVID_AD, 1000, 10000); + if (ret) + return dev_err_probe(st->dev, -ENODEV, + "Invalid dev id 0x%02X, expected 0x%02X\n", + val, ADXL367_DEVID_AD); + + return 0; +} + +static int adxl367_setup(struct adxl367_state *st) +{ + int ret; + + ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY, + ADXL367_2G_RANGE_1G); + if (ret) + return ret; + + ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY, + ADXL367_2G_RANGE_100MG); + if (ret) + return ret; + + ret = adxl367_set_act_proc_mode(st, ADXL367_LOOPED); + if (ret) + return ret; + + ret = _adxl367_set_odr(st, ADXL367_ODR_400HZ); + if (ret) + return ret; + + ret = _adxl367_set_act_time_ms(st, 10); + if (ret) + return ret; + + ret = _adxl367_set_inact_time_ms(st, 10000); + if (ret) + return ret; + + return adxl367_set_measure_en(st, true); +} + +static void adxl367_disable_regulators(void *data) +{ + struct adxl367_state *st = data; + + regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators); +} + +int adxl367_probe(struct device *dev, const struct adxl367_ops *ops, + void *context, struct regmap *regmap, int irq) +{ + struct iio_buffer *buffer; + struct iio_dev *indio_dev; + struct adxl367_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->dev = dev; + st->regmap = regmap; + st->context = context; + st->ops = ops; + + mutex_init(&st->lock); + + indio_dev->channels = adxl367_channels; + indio_dev->num_channels = ARRAY_SIZE(adxl367_channels); + indio_dev->available_scan_masks = adxl367_channel_masks; + indio_dev->name = "adxl367"; + indio_dev->info = &adxl367_info; + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + + st->regulators[0].supply = "vdd"; + st->regulators[1].supply = "vddio"; + + ret = devm_regulator_bulk_get(st->dev, ARRAY_SIZE(st->regulators), + st->regulators); + if (ret) + return dev_err_probe(st->dev, ret, + "Failed to get regulators\n"); + + ret = regulator_bulk_enable(ARRAY_SIZE(st->regulators), st->regulators); + if (ret) + return dev_err_probe(st->dev, ret, + "Failed to enable regulators\n"); + + ret = devm_add_action_or_reset(st->dev, adxl367_disable_regulators, st); + if (ret) + return dev_err_probe(st->dev, ret, + "Failed to add regulators disable action\n"); + + ret = regmap_write(st->regmap, ADXL367_REG_RESET, ADXL367_RESET_CODE); + if (ret) + return ret; + + ret = adxl367_verify_devid(st); + if (ret) + return ret; + + ret = adxl367_setup(st); + if (ret) + return ret; + + buffer = devm_iio_kfifo_allocate(st->dev); + if (!buffer) + return -ENOMEM; + + iio_device_attach_buffer(indio_dev, buffer); + + indio_dev->setup_ops = &adxl367_buffer_ops; + /* devm_iio_kfifo_buffer_setup_ext is not available before 5.13 */ + iio_buffer_set_attrs(indio_dev->buffer, adxl367_fifo_attributes); + + ret = devm_request_threaded_irq(st->dev, irq, NULL, + adxl367_irq_handler, IRQF_ONESHOT, + indio_dev->name, indio_dev); + if (ret) + return dev_err_probe(st->dev, ret, "Failed to request irq\n"); + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_NS_GPL(adxl367_probe, IIO_ADXL367); + +MODULE_AUTHOR("Cosmin Tanislav "); +MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/adxl367.h b/drivers/iio/accel/adxl367.h new file mode 100644 index 00000000000000..4a42622149b1bf --- /dev/null +++ b/drivers/iio/accel/adxl367.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2021 Analog Devices, Inc. + * Author: Cosmin Tanislav + */ + +#ifndef _ADXL367_H_ +#define _ADXL367_H_ + +#include + +struct device; +struct regmap; + +struct adxl367_ops { + int (*read_fifo)(void *context, __be16 *fifo_buf, + unsigned int fifo_entries); +}; + +int adxl367_probe(struct device *dev, const struct adxl367_ops *ops, + void *context, struct regmap *regmap, int irq); + +#endif /* _ADXL367_H_ */ diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c new file mode 100644 index 00000000000000..3606efa25835ea --- /dev/null +++ b/drivers/iio/accel/adxl367_i2c.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Analog Devices, Inc. + * Author: Cosmin Tanislav + */ + +#include +#include +#include +#include + +#include "adxl367.h" + +#define ADXL367_I2C_FIFO_DATA 0x42 + +struct adxl367_i2c_state { + struct regmap *regmap; +}; + +static bool adxl367_readable_noinc_reg(struct device *dev, unsigned int reg) +{ + return reg == ADXL367_I2C_FIFO_DATA; +} + +static int adxl367_i2c_read_fifo(void *context, __be16 *fifo_buf, + unsigned int fifo_entries) +{ + struct adxl367_i2c_state *st = context; + + return regmap_noinc_read(st->regmap, ADXL367_I2C_FIFO_DATA, fifo_buf, + fifo_entries * sizeof(*fifo_buf)); +} + +static const struct regmap_config adxl367_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .readable_noinc_reg = adxl367_readable_noinc_reg, +}; + +static const struct adxl367_ops adxl367_i2c_ops = { + .read_fifo = adxl367_i2c_read_fifo, +}; + +static int adxl367_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adxl367_i2c_state *st; + struct regmap *regmap; + + st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(client, &adxl367_i2c_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + st->regmap = regmap; + + return adxl367_probe(&client->dev, &adxl367_i2c_ops, st, regmap, + client->irq); +} + +static const struct i2c_device_id adxl367_i2c_id[] = { + { "adxl367", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id); + +static const struct of_device_id adxl367_of_match[] = { + { .compatible = "adi,adxl367" }, + { }, +}; +MODULE_DEVICE_TABLE(of, adxl367_of_match); + +static struct i2c_driver adxl367_i2c_driver = { + .driver = { + .name = "adxl367_i2c", + .of_match_table = adxl367_of_match, + }, + .probe = adxl367_i2c_probe, + .id_table = adxl367_i2c_id, +}; + +module_i2c_driver(adxl367_i2c_driver); + +MODULE_IMPORT_NS(IIO_ADXL367); +MODULE_AUTHOR("Cosmin Tanislav "); +MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/adxl367_spi.c b/drivers/iio/accel/adxl367_spi.c new file mode 100644 index 00000000000000..26dfc821ebbe0a --- /dev/null +++ b/drivers/iio/accel/adxl367_spi.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Analog Devices, Inc. + * Author: Cosmin Tanislav + */ + +#include +#include +#include +#include + +#include "adxl367.h" + +#define ADXL367_SPI_WRITE_COMMAND 0x0A +#define ADXL367_SPI_READ_COMMAND 0x0B +#define ADXL367_SPI_FIFO_COMMAND 0x0D + +struct adxl367_spi_state { + struct spi_device *spi; + + struct spi_message reg_write_msg; + struct spi_transfer reg_write_xfer[2]; + + struct spi_message reg_read_msg; + struct spi_transfer reg_read_xfer[2]; + + struct spi_message fifo_msg; + struct spi_transfer fifo_xfer[2]; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + u8 reg_write_tx_buf[1] ____cacheline_aligned; + u8 reg_read_tx_buf[2]; + u8 fifo_tx_buf[1]; +}; + +static int adxl367_read_fifo(void *context, __be16 *fifo_buf, + unsigned int fifo_entries) +{ + struct adxl367_spi_state *st = context; + + st->fifo_xfer[1].rx_buf = fifo_buf; + st->fifo_xfer[1].len = fifo_entries * sizeof(*fifo_buf); + + return spi_sync(st->spi, &st->fifo_msg); +} + +static int adxl367_read(void *context, const void *reg_buf, size_t reg_size, + void *val_buf, size_t val_size) +{ + struct adxl367_spi_state *st = context; + u8 reg = ((const u8 *)reg_buf)[0]; + + st->reg_read_tx_buf[1] = reg; + st->reg_read_xfer[1].rx_buf = val_buf; + st->reg_read_xfer[1].len = val_size; + + return spi_sync(st->spi, &st->reg_read_msg); +} + +static int adxl367_write(void *context, const void *val_buf, size_t val_size) +{ + struct adxl367_spi_state *st = context; + + st->reg_write_xfer[1].tx_buf = val_buf; + st->reg_write_xfer[1].len = val_size; + + return spi_sync(st->spi, &st->reg_write_msg); +} + +static struct regmap_bus adxl367_spi_regmap_bus = { + .read = adxl367_read, + .write = adxl367_write, +}; + +static const struct regmap_config adxl367_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static const struct adxl367_ops adxl367_spi_ops = { + .read_fifo = adxl367_read_fifo, +}; + +static int adxl367_spi_probe(struct spi_device *spi) +{ + struct adxl367_spi_state *st; + struct regmap *regmap; + + st = devm_kzalloc(&spi->dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + st->spi = spi; + + /* + * Xfer: [XFR1] [ XFR2 ] + * Master: 0x0A ADDR DATA0 DATA1 ... DATAN + * Slave: .... .......................... + */ + st->reg_write_tx_buf[0] = ADXL367_SPI_WRITE_COMMAND; + st->reg_write_xfer[0].tx_buf = st->reg_write_tx_buf; + st->reg_write_xfer[0].len = sizeof(st->reg_write_tx_buf); + spi_message_init_with_transfers(&st->reg_write_msg, + st->reg_write_xfer, 2); + + /* + * Xfer: [ XFR1 ] [ XFR2 ] + * Master: 0x0B ADDR ..................... + * Slave: ......... DATA0 DATA1 ... DATAN + */ + st->reg_read_tx_buf[0] = ADXL367_SPI_READ_COMMAND; + st->reg_read_xfer[0].tx_buf = st->reg_read_tx_buf; + st->reg_read_xfer[0].len = sizeof(st->reg_read_tx_buf); + spi_message_init_with_transfers(&st->reg_read_msg, + st->reg_read_xfer, 2); + + /* + * Xfer: [XFR1] [ XFR2 ] + * Master: 0x0D ..................... + * Slave: .... DATA0 DATA1 ... DATAN + */ + st->fifo_tx_buf[0] = ADXL367_SPI_FIFO_COMMAND; + st->fifo_xfer[0].tx_buf = st->fifo_tx_buf; + st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf); + spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, 2); + + regmap = devm_regmap_init(&spi->dev, &adxl367_spi_regmap_bus, st, + &adxl367_spi_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return adxl367_probe(&spi->dev, &adxl367_spi_ops, st, regmap, spi->irq); +} + +static const struct spi_device_id adxl367_spi_id[] = { + { "adxl367", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(spi, adxl367_spi_id); + +static const struct of_device_id adxl367_of_match[] = { + { .compatible = "adi,adxl367" }, + { }, +}; +MODULE_DEVICE_TABLE(of, adxl367_of_match); + +static struct spi_driver adxl367_spi_driver = { + .driver = { + .name = "adxl367_spi", + .of_match_table = adxl367_of_match, + }, + .probe = adxl367_spi_probe, + .id_table = adxl367_spi_id, +}; + +module_spi_driver(adxl367_spi_driver); + +MODULE_IMPORT_NS(IIO_ADXL367); +MODULE_AUTHOR("Cosmin Tanislav "); +MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer SPI driver"); +MODULE_LICENSE("GPL"); From 3fece4e6c8cb1ae93a64e82fef06e02585c9c79b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 24 Feb 2022 18:02:28 +0300 Subject: [PATCH 235/407] iio: accel: adxl367: unlock on error in adxl367_buffer_predisable() This error path needs to call the mutex_unlock(&st->lock) before returning. Fixes: cbab791c5e2a ("iio: accel: add ADXL367 driver") Signed-off-by: Dan Carpenter Reviewed-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220224150228.GB6856@kili Signed-off-by: Jonathan Cameron (cherry picked from commit 7948d301c24887a27ff560ca91f8b4cf4cd8e0c8) --- drivers/iio/accel/adxl367.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index 91bb36181e2554..b02e23eff6177b 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -1359,7 +1359,7 @@ static int adxl367_buffer_predisable(struct iio_dev *indio_dev) ret = adxl367_set_measure_en(st, true); if (ret) - return ret; + goto out; ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, false); From 412cd3ad7f9d86a0142a2fa2961f60c338c41885 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 24 Feb 2022 14:10:34 -0700 Subject: [PATCH 236/407] iio: accel: adxl367: Fix handled initialization in adxl367_irq_handler() Clang warns: drivers/iio/accel/adxl367.c:887:2: error: variable 'handled' is uninitialized when used here [-Werror,-Wuninitialized] handled |= adxl367_push_event(indio_dev, status); ^~~~~~~ drivers/iio/accel/adxl367.c:879:14: note: initialize the variable 'handled' to silence this warning bool handled; ^ = 0 1 error generated. This should have used '=' instead of '|='; make that change to resolve the warning. Fixes: cbab791c5e2a ("iio: accel: add ADXL367 driver") Link: https://github.com/ClangBuiltLinux/linux/issues/1605 Reported-by: kernel test robot Reported-by: Colin Ian King Signed-off-by: Nathan Chancellor Link: https://lore.kernel.org/r/20220224211034.625130-1-nathan@kernel.org Signed-off-by: Jonathan Cameron (cherry picked from commit 185897d03ca3c4c98eff5cbf151671c5f88165fb) --- drivers/iio/accel/adxl367.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index b02e23eff6177b..b7a1675aaea178 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -884,7 +884,7 @@ static irqreturn_t adxl367_irq_handler(int irq, void *private) if (ret) return IRQ_NONE; - handled |= adxl367_push_event(indio_dev, status); + handled = adxl367_push_event(indio_dev, status); handled |= adxl367_push_fifo_data(indio_dev, status, fifo_entries); return handled ? IRQ_HANDLED : IRQ_NONE; From 3f43cd027ee1ad36d76f5630781e6900930540bc Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 8 Nov 2021 12:38:40 +0200 Subject: [PATCH 237/407] Kconfig.adi: select ADXL367 SPI & I2C The ADXL367 is an ultralow power, 3-axis MEMS accelerometer. The ADXL367 does not alias input signals to achieve ultralow power consumption, it samples the full bandwidth of the sensor at all data rates. Measurement ranges of +-2g, +-4g, and +-8g are available, with a resolution of 0.25mg/LSB on the +-2 g range. In addition to its ultralow power consumption, the ADXL367 has many features to enable true system level power reduction. It includes a deep multimode output FIFO, a built-in micropower temperature sensor, and an internal ADC for synchronous conversion of an additional analog input. Signed-off-by: Cosmin Tanislav --- drivers/iio/Kconfig.adi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/Kconfig.adi b/drivers/iio/Kconfig.adi index 4338428fdfb5b3..b95eeef83bcd15 100644 --- a/drivers/iio/Kconfig.adi +++ b/drivers/iio/Kconfig.adi @@ -27,6 +27,8 @@ config IIO_ALL_ADI_DRIVERS select ADXL345_SPI if SPI select ADXL355_I2C if I2C select ADXL355_SPI if SPI + select ADXL367_I2C if I2C + select ADXL367_SPI if SPI select ADXL372_I2C if I2C select ADXL372_SPI if SPI select AD400X From 353a7ef821ab18858eb6978403a9e8e20c7032d0 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 17 Mar 2022 16:40:37 +0100 Subject: [PATCH 238/407] iio: frequency: hmc7044: REG_CH_OUT_CRTL_0 always set reserved bit4 According to the register default, this bit should be set. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/hmc7044.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/iio/frequency/hmc7044.c b/drivers/iio/frequency/hmc7044.c index d688004f5dc545..88a458d24dc487 100644 --- a/drivers/iio/frequency/hmc7044.c +++ b/drivers/iio/frequency/hmc7044.c @@ -271,7 +271,6 @@ struct hmc7044_chan_spec { bool high_performance_mode_dis; bool start_up_mode_dynamic_enable; bool dynamic_driver_enable; - bool output_control0_rb4_enable; bool force_mute_enable; bool is_sysref; unsigned int divider; @@ -1282,8 +1281,7 @@ static int hmc7044_setup(struct iio_dev *indio_dev) return ret; ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_0(chan->num), (chan->start_up_mode_dynamic_enable ? - HMC7044_START_UP_MODE_DYN_EN : 0) | - (chan->output_control0_rb4_enable ? BIT(4) : 0) | + HMC7044_START_UP_MODE_DYN_EN : 0) | BIT(4) | (chan->high_performance_mode_dis ? 0 : HMC7044_HI_PERF_MODE) | HMC7044_SYNC_EN | HMC7044_CH_EN); @@ -1485,8 +1483,7 @@ static int hmc7043_setup(struct iio_dev *indio_dev) ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_0(chan->num), (chan->start_up_mode_dynamic_enable ? - HMC7044_START_UP_MODE_DYN_EN : 0) | - (chan->output_control0_rb4_enable ? BIT(4) : 0) | + HMC7044_START_UP_MODE_DYN_EN : 0) | BIT(4) | (chan->high_performance_mode_dis ? 0 : HMC7044_HI_PERF_MODE) | HMC7044_SYNC_EN | HMC7044_CH_EN); @@ -1727,9 +1724,6 @@ static int hmc7044_parse_dt(struct device *dev, hmc->channels[cnt].dynamic_driver_enable = of_property_read_bool(chan_np, "adi,dynamic-driver-enable"); - hmc->channels[cnt].output_control0_rb4_enable = - of_property_read_bool(chan_np, - "adi,control0-rb4-enable"); hmc->channels[cnt].force_mute_enable = of_property_read_bool(chan_np, "adi,force-mute-enable"); @@ -1862,8 +1856,7 @@ static int hmc7044_continuous_chan_sync_enable(struct iio_dev *indio_dev, bool e ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_0(chan->num), (chan->start_up_mode_dynamic_enable ? - HMC7044_START_UP_MODE_DYN_EN : 0) | - (chan->output_control0_rb4_enable ? BIT(4) : 0) | + HMC7044_START_UP_MODE_DYN_EN : 0) | BIT(4) | (chan->high_performance_mode_dis ? 0 : HMC7044_HI_PERF_MODE) | ((enable || chan->start_up_mode_dynamic_enable) ? From 10ff1ca66e17bb3bcc903480684db251ad6e5954 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 17 Mar 2022 16:43:45 +0100 Subject: [PATCH 239/407] dts: hmc7044: Remove adi,control0-rb4-enable; This option is now always enabled in the hmc7044 driver. Signed-off-by: Michael Hennerich --- arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts | 4 ---- arch/arm64/boot/dts/xilinx/adi-fmcomms8.dtsi | 4 ---- ...b-sync-fmcomms8-jesd204-fsm-multisom-primary-clockdist.dts | 2 -- ...crr-fmc-revb-sync-fmcomms8-jesd204-fsm-using-clockdist.dts | 2 -- arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb.dtsi | 4 ---- 5 files changed, 16 deletions(-) diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts index 6aa2bf28f3e693..d808739ac0b957 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts @@ -327,13 +327,11 @@ &hmc7044_fmc_c1 { adi,driver-mode = ; - adi,control0-rb4-enable; adi,force-mute-enable; }; &hmc7044_fmc_c3 { adi,driver-mode = ; - adi,control0-rb4-enable; adi,force-mute-enable; }; @@ -359,7 +357,6 @@ adi,driver-mode = ; adi,startup-mode-dynamic-enable; adi,high-performance-mode-disable; - adi,control0-rb4-enable; adi,force-mute-enable; }; @@ -369,7 +366,6 @@ adi,driver-mode = ; adi,startup-mode-dynamic-enable; adi,high-performance-mode-disable; - adi,control0-rb4-enable; adi,force-mute-enable; }; diff --git a/arch/arm64/boot/dts/xilinx/adi-fmcomms8.dtsi b/arch/arm64/boot/dts/xilinx/adi-fmcomms8.dtsi index 0a73e5ee345a73..73ca2634f9b9c5 100644 --- a/arch/arm64/boot/dts/xilinx/adi-fmcomms8.dtsi +++ b/arch/arm64/boot/dts/xilinx/adi-fmcomms8.dtsi @@ -766,7 +766,6 @@ adi,extended-name = "DEV_SYSREF_C"; adi,divider = <3840>; // 768000 adi,driver-mode = ; - adi,control0-rb4-enable; adi,force-mute-enable; adi,startup-mode-dynamic-enable; adi,high-performance-mode-disable; @@ -784,7 +783,6 @@ adi,extended-name = "DEV_SYSREF_D"; adi,divider = <3840>; // 768000 adi,driver-mode = ; - adi,control0-rb4-enable; adi,force-mute-enable; adi,startup-mode-dynamic-enable; adi,high-performance-mode-disable; @@ -807,7 +805,6 @@ adi,extended-name = "FPGA_SYSREF_TX_OBS_CD"; adi,divider = <3840>; // 768000 adi,driver-mode = ; - adi,control0-rb4-enable; adi,force-mute-enable; adi,startup-mode-dynamic-enable; adi,high-performance-mode-disable; @@ -817,7 +814,6 @@ adi,extended-name = "FPGA_SYSREF_RX_CD"; adi,divider = <3840>; // 768000 adi,driver-mode = ; - adi,control0-rb4-enable; adi,force-mute-enable; adi,startup-mode-dynamic-enable; adi,high-performance-mode-disable; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8-jesd204-fsm-multisom-primary-clockdist.dts b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8-jesd204-fsm-multisom-primary-clockdist.dts index 4b415a810dbdd9..06046d87ecace6 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8-jesd204-fsm-multisom-primary-clockdist.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8-jesd204-fsm-multisom-primary-clockdist.dts @@ -154,7 +154,6 @@ adi,startup-mode-dynamic-enable; adi,high-performance-mode-disable; adi,force-mute-enable; - adi,control0-rb4-enable; }; hmc7044_car_c2: channel@2 { @@ -172,7 +171,6 @@ adi,startup-mode-dynamic-enable; adi,high-performance-mode-disable; adi,force-mute-enable; - adi,control0-rb4-enable; }; hmc7044_car_c9: channel@9 { diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8-jesd204-fsm-using-clockdist.dts b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8-jesd204-fsm-using-clockdist.dts index 4667650c91b2ea..a6e2999e8eef72 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8-jesd204-fsm-using-clockdist.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-sync-fmcomms8-jesd204-fsm-using-clockdist.dts @@ -125,7 +125,6 @@ adi,startup-mode-dynamic-enable; adi,high-performance-mode-disable; adi,force-mute-enable; - adi,control0-rb4-enable; }; hmc7044_car_c2: channel@2 { @@ -143,7 +142,6 @@ adi,startup-mode-dynamic-enable; adi,high-performance-mode-disable; adi,force-mute-enable; - adi,control0-rb4-enable; }; hmc7044_car_c9: channel@9 { diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb.dtsi index 26745bbbe7df76..1d0001ab0ffdfa 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb.dtsi @@ -17,25 +17,21 @@ &hmc7044_c1 { adi,force-mute-enable; adi,driver-mode = ; - adi,control0-rb4-enable; }; &hmc7044_c3 { adi,force-mute-enable; adi,driver-mode = ; - adi,control0-rb4-enable; }; &hmc7044_c8 { adi,force-mute-enable; adi,driver-mode = ; - adi,control0-rb4-enable; }; &hmc7044_c9 { adi,force-mute-enable; adi,driver-mode = ; - adi,control0-rb4-enable; }; &hmc7044_c6 { From 73ec379ef0872ec46763f7e6b0aaa055d89f7683 Mon Sep 17 00:00:00 2001 From: Raluca Chis Date: Tue, 15 Mar 2022 12:46:05 +0200 Subject: [PATCH 240/407] CI: sync master with rpi-5.10.y Add on master branch files used on rpi-5.10.y to sync branches. Signed-off-by: Raluca Chis --- azure-pipelines-rpi.yml | 2 +- ci/travis/prepare_artifacts.sh | 50 +++++++++++ ci/travis/upload_to_artifactory.py | 138 +++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 ci/travis/prepare_artifacts.sh create mode 100644 ci/travis/upload_to_artifactory.py diff --git a/azure-pipelines-rpi.yml b/azure-pipelines-rpi.yml index cb472767dc7608..8ce0b0fa43a307 100644 --- a/azure-pipelines-rpi.yml +++ b/azure-pipelines-rpi.yml @@ -110,4 +110,4 @@ stages: env: ARTIFACTORY_PATH: $(PATH) ARTIFACTORY_TOKEN: $(TOKEN) - displayName: "Push to Artifactory" + displayName: "Push to Artifactory" \ No newline at end of file diff --git a/ci/travis/prepare_artifacts.sh b/ci/travis/prepare_artifacts.sh new file mode 100644 index 00000000000000..6083427f7eed8b --- /dev/null +++ b/ci/travis/prepare_artifacts.sh @@ -0,0 +1,50 @@ +#!/bin/bash -e +# SPDX-License-Identifier: (GPL-1.0-only OR BSD-2-Clause) + +timestamp=$(date +%Y_%m_%d-%H_%M) +bcm_types='bcm2709 bcm2711 bcmrpi' + +#prepare the structure of the folder containing artifacts +artifacts_structure() { + cd ${SOURCE_DIRECTORY} + mkdir ${timestamp} + + GIT_SHA=$(git rev-parse --short HEAD) + GIT_SHA_DATE=$(git show -s --format="%ci" ${GIT_SHA} | sed -e "s/ \|\:/-/g") + echo "git_sha=${GIT_SHA}" >> ${timestamp}/properties.txt + echo "git_sha_date=${GIT_SHA_DATE}" >> ${timestamp}/properties.txt + + for bcm in $bcm_types; do + cd adi_${bcm}_defconfig + mkdir overlays + mv ./*.dtbo ./overlays + if [ "${bcm}" = "bcm2709" ]; then + mv ./zImage ./kernel7.img + elif [ "${bcm}" = "bcm2711" ]; then + mv ./zImage ./kernel7l.img + elif [ "${bcm}" = "bcmrpi" ]; then + mv ./zImage ./kernel.img + fi + cd ../ + mv ./adi_${bcm}_defconfig ./${timestamp}/adi_${bcm}_defconfig + done +} + +#upload artifacts to Artifactory +artifacts_artifactory() { + cd ${SOURCE_DIRECTORY} + python /root/myagent/_work/1/s/ci/travis/upload_to_artifactory.py --base_path="${ARTIFACTORY_PATH}" --server_path="linux_rpi/${BUILD_SOURCEBRANCHNAME}" --local_path="./${timestamp}" --token="${ARTIFACTORY_TOKEN}" +} + +#archive artifacts and upload to SWDownloads +artifacts_swdownloads() { + cd ${SOURCE_DIRECTORY}/${timestamp} + chmod 600 ${KEY_FILE} + for bcm in $bcm_types; do + tar -zcvf adi_${bcm}_defconfig.tar adi_${bcm}_defconfig + scp -2 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o HostKeyAlgorithms=+ssh-dss \ + -i ${KEY_FILE} -r ${SOURCE_DIRECTORY}/${timestamp}/adi_${bcm}_defconfig.tar ${DEST_SERVER} + done +} + +artifacts_${1} diff --git a/ci/travis/upload_to_artifactory.py b/ci/travis/upload_to_artifactory.py new file mode 100644 index 00000000000000..9212662e779733 --- /dev/null +++ b/ci/travis/upload_to_artifactory.py @@ -0,0 +1,138 @@ +# SPDX-License-Identifier: (GPL-1.0-only OR BSD-2-Clause) + +######################################################################## +# +# File name: upload_to_artifactory.py +# Author: Raus Stefan +# +# This script is used to upload files to ADI internal artifactory server +# +# Copyright (C) 2019-2022 Analog Devices Inc. +# +####################################################################### + +#!/usr/bin/python3.6 + +import os +import argparse +import glob +import shutil +import sys +from glob import glob + +LOCAL_PATHS_LIST = [] +# If you try to upload files in a different folder than the ones in below list, there will be printed a message and files won't be uploaded +SERVER_FOLDERS_LIST = [ "hdl", "linux", "linux_rpi", "arm_trusted_firmware", "boot_partition", "rootfs", "u-boot", "HighSpeedConverterToolbox", "TransceiverToolbox", "SD_card_image"] + +########### Define arguments and help section ################# + +parser = argparse.ArgumentParser( + description='This script is uploading files or folders to artifactory server.Parameter order doesn\'t matter.', \ + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog='Examples: '\ + + '\n-> "./upload_to_artifactory.py --server_path="hdl/master/2020_12_12/pluto" --local_path="../projects/pluto/log_file.txt"'\ + + ' --properties="git_sha=928ggraf;git_commmit_date=2020_12_12" --no_rel_path" will upload file "log_file.txt" to '\ + + ' /hdl/master/2020_12_12/pluto/log_file.txt and add properties git_sha=928ggraf and git_commit_date=2010_12_12 on it.'\ + + '\n-> "./upload_to_artifactory.py --server_path="linux" --local_path="master/2020_11_25/arm/zynq_zed_adv7511.dtb"" will upload dtb'\ + + ' file to /linux/master/2020_11_25/arm/zynq_zed_adv7511.dtb') +parser.add_argument("--base_path", help="Artifactory Base Path - Internal ADI Artifactory server and development folder") +parser.add_argument("--server_path", help="Artifactory folder where the files/folders will be saved, for example 'hdl' or 'linux'.") +parser.add_argument("--local_path", help="Local path to file/folder to upload. It can be relative or absolute.") +parser.add_argument("--properties", help="Properties to be added to file/folder. If multiple ones, split them by ';'.") +parser.add_argument("--no_rel_path", help="If this exists, the relative path until local file will be appended to artifactory path", action="store_true") +parser.add_argument("--props_level", help="Set for how many levels of folders to set specified properties, by default just on file.") +parser.add_argument("--token", help="Artifactory authentication token. Otherwise you can export API_TOKEN in terminal before calling this script.") +args = parser.parse_args() +parser.parse_args() + +########## Check if required and optional arguments are set ################# +if args.token: + API_TOKEN = args.token +else: + if "API_TOKEN" in os.environ: + API_TOKEN = os.environ['API_TOKEN'] + else: + print('\nParameter "--token" is not set. This is Artifactory Authentication Token and can be set even using parameter "--token" on upload command, even by exporting API_TOKEN variable in terminal, before calling upload script.') + quit() + +if args.base_path: + UPLOAD_BASE_PATH = args.base_path +else: + if "UPLOAD_BASE_PATH" in os.environ: + UPLOAD_BASE_PATH = os.environ['UPLOAD_BASE_PATH'] + else: + print('\nParameter "--base_path" is not set. This is ADI Internal Artifactory Server plus first level of folders. It can be set even using parameter "--base_path" on upload command, even by exporting UPLOAD_BASE_PATH variable in terminal, before calling upload script.') + quit() + + +if args.server_path: + # take first folder from server path and check if matches with folders from artifactory server (hdl, linux, SD_card_image etc) + SERVER_PATH = args.server_path + SERVER_PATH = SERVER_PATH[1:] if SERVER_PATH.startswith('/') else SERVER_PATH + SERVER_FOLDER = SERVER_PATH.split("/", 1)[0] + if SERVER_FOLDER not in SERVER_FOLDERS_LIST: + print('\nParameter "--server_path" must contain an already existing folder, for example "hdl", "linux", "SD_card_image" etc.' + + 'If you want to add new folders, please edit "upload_to_artifactory.py" or contact script owner.') + quit() +else: + print('\nParameter "--server_path" is required. It should be set to server location where the files/folder will be uploaded. Check help section.') + quit() + +if args.local_path: + LOCAL_PATH = os.path.abspath(args.local_path) if '../' in args.local_path else args.local_path + # if there was given a dir as local_path parameter, get all the files inside it in a list + if os.path.isdir(LOCAL_PATH): + for dpath, dnames, fnames in os.walk(LOCAL_PATH): + for i, FILE_NAME in enumerate([os.path.join(dpath, fname) for fname in fnames]): + LOCAL_PATHS_LIST.append(str(FILE_NAME)) + elif os.path.isfile(LOCAL_PATH): + LOCAL_PATHS_LIST = [LOCAL_PATH] + else: + print('\nIt looks that parameter "--LOCAL_PATH" is wrong defined/does not exists. Plese check: ' + local_path) + quit() +else: + print('\nParameter "--local_path" is required. It should point to local file/folder to upload.') + quit() + +if args.properties: + PROPS = args.properties +else: + PROPS = '' + +if args.no_rel_path: + NO_REL_PATH = True +else: + NO_REL_PATH = False + +if args.props_level: + PROP_LEVEL = int(args.props_level) +else: + PROP_LEVEL = 0 + +########## Upload files ########## +# If files with same name already exists at specified server path, they will be overwritten + +for FILE in LOCAL_PATHS_LIST: + if NO_REL_PATH: + FILE_NAME = os.path.basename(FILE) + ART_PATH = UPLOAD_BASE_PATH + "/" + SERVER_PATH + "/" + FILE_NAME + else: + ART_PATH = UPLOAD_BASE_PATH + "/" + SERVER_PATH + "/" + FILE + upload_cmd = "curl -H \"X-JFrog-Art-Api:" + API_TOKEN + "\" -X PUT \"" + ART_PATH + ";" + PROPS + "\" -T \"" + FILE + "\"" + os.system(upload_cmd) + +########## Upload properties on folders ######### + +if NO_REL_PATH: + ART_PATH = UPLOAD_BASE_PATH + "/" + SERVER_PATH +else: + ART_PATH = UPLOAD_BASE_PATH + "/" + SERVER_PATH + "/" + os.path.split(LOCAL_PATHS_LIST[0])[0] + +i = 0 +while ( i < int(PROP_LEVEL)): + set_folder_props_cmd = "curl -H \"X-JFrog-Art-Api:" + API_TOKEN + "\" -X PUT \"" + ART_PATH + "/;" + PROPS + "\"" + os.system(set_folder_props_cmd) + i = i + 1 + ART_PATH = os.path.split(ART_PATH)[0] + +################################################# From 0760fe9c263294b5b9181179712fc4d42981c2eb Mon Sep 17 00:00:00 2001 From: Raluca Chis Date: Thu, 17 Mar 2022 08:36:47 +0200 Subject: [PATCH 241/407] CI: change artifacts structure The structure of artifacts deployed to Artifactory and SWDownloads was changed and to deployed artifacts was added an archive rpi_modules.tar.gz containing modules files. Signed-off-by: Raluca Chis --- azure-pipelines-rpi.yml | 4 +++ ci/travis/prepare_artifacts.sh | 55 +++++++++++++++++++++------------- ci/travis/run-build-docker.sh | 2 +- ci/travis/run-build.sh | 10 +++++-- 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/azure-pipelines-rpi.yml b/azure-pipelines-rpi.yml index 8ce0b0fa43a307..c55a0372bbb532 100644 --- a/azure-pipelines-rpi.yml +++ b/azure-pipelines-rpi.yml @@ -49,6 +49,10 @@ stages: clean: true - script: ./ci/travis/run-build-docker.sh displayName: "Build test for '$(DEFCONFIG)'" + - script: | + cd $(Build.ArtifactStagingDirectory) + tar -C /home/vsts/work/1/s/modules/lib/modules/./ -cvf /home/vsts/work/1/a/rpi_modules.tar.gz . + displayName: 'Copy modules' - task: CopyFiles@2 inputs: sourceFolder: '$(Agent.BuildDirectory)/s/arch/arm/boot/dts/overlays' diff --git a/ci/travis/prepare_artifacts.sh b/ci/travis/prepare_artifacts.sh index 6083427f7eed8b..1445ca1b8fbce7 100644 --- a/ci/travis/prepare_artifacts.sh +++ b/ci/travis/prepare_artifacts.sh @@ -1,8 +1,7 @@ -#!/bin/bash -e # SPDX-License-Identifier: (GPL-1.0-only OR BSD-2-Clause) +#!/bin/bash -e timestamp=$(date +%Y_%m_%d-%H_%M) -bcm_types='bcm2709 bcm2711 bcmrpi' #prepare the structure of the folder containing artifacts artifacts_structure() { @@ -11,40 +10,54 @@ artifacts_structure() { GIT_SHA=$(git rev-parse --short HEAD) GIT_SHA_DATE=$(git show -s --format="%ci" ${GIT_SHA} | sed -e "s/ \|\:/-/g") - echo "git_sha=${GIT_SHA}" >> ${timestamp}/properties.txt - echo "git_sha_date=${GIT_SHA_DATE}" >> ${timestamp}/properties.txt + echo "git_sha=${GIT_SHA}" >> ${timestamp}/rpi_git_properties.txt + echo "git_sha_date=${GIT_SHA_DATE}" >> ${timestamp}/rpi_git_properties.txt - for bcm in $bcm_types; do - cd adi_${bcm}_defconfig - mkdir overlays + typeBCM=( "bcm2709" "bcm2711" "bcmrpi" ) + typeKERNEL=( "kernel7" "kernel7l" "kernel" ) + for index in "${!typeBCM[@]}"; do + cd adi_"${typeBCM[$index]}"_defconfig + mkdir overlays modules mv ./*.dtbo ./overlays - if [ "${bcm}" = "bcm2709" ]; then - mv ./zImage ./kernel7.img - elif [ "${bcm}" = "bcm2711" ]; then - mv ./zImage ./kernel7l.img - elif [ "${bcm}" = "bcmrpi" ]; then - mv ./zImage ./kernel.img - fi + tar -xf rpi_modules.tar.gz -C modules + rm rpi_modules.tar.gz + mv ./zImage ./"${typeKERNEL[$index]}".img cd ../ - mv ./adi_${bcm}_defconfig ./${timestamp}/adi_${bcm}_defconfig + cp -r ./adi_"${typeBCM[$index]}"_defconfig/* ./${timestamp} done + tar -C ${SOURCE_DIRECTORY}/${timestamp}/modules -cvf ${SOURCE_DIRECTORY}/${timestamp}/rpi_modules.tar.gz . + rm -r ${SOURCE_DIRECTORY}/${timestamp}/modules } #upload artifacts to Artifactory artifacts_artifactory() { cd ${SOURCE_DIRECTORY} - python /root/myagent/_work/1/s/ci/travis/upload_to_artifactory.py --base_path="${ARTIFACTORY_PATH}" --server_path="linux_rpi/${BUILD_SOURCEBRANCHNAME}" --local_path="./${timestamp}" --token="${ARTIFACTORY_TOKEN}" + python /root/myagent/_work/1/s/ci/travis/upload_to_artifactory.py --base_path="${ARTIFACTORY_PATH}" \ + --server_path="linux_rpi/${BUILD_SOURCEBRANCHNAME}" --local_path="./${timestamp}" --token="${ARTIFACTORY_TOKEN}" } #archive artifacts and upload to SWDownloads artifacts_swdownloads() { cd ${SOURCE_DIRECTORY}/${timestamp} chmod 600 ${KEY_FILE} - for bcm in $bcm_types; do - tar -zcvf adi_${bcm}_defconfig.tar adi_${bcm}_defconfig - scp -2 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o HostKeyAlgorithms=+ssh-dss \ - -i ${KEY_FILE} -r ${SOURCE_DIRECTORY}/${timestamp}/adi_${bcm}_defconfig.tar ${DEST_SERVER} - done + scp -2 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o HostKeyAlgorithms=+ssh-dss \ + -i ${KEY_FILE} -r *.tar.gz ${DEST_SERVER} + md5_modules=($(md5sum rpi_modules.tar.gz| cut -d ' ' -f 1)) + + rm rpi_modules.tar.gz rpi_git_properties.txt + tar -C ${PWD} -cvf rpi_latest_boot.tar.gz * + md5_boot=($(md5sum rpi_latest_boot.tar.gz| cut -d ' ' -f 1)) + scp -2 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o HostKeyAlgorithms=+ssh-dss \ + -i ${KEY_FILE} -r rpi_latest_boot.tar.gz ${DEST_SERVER} + + echo "boot_date=${timestamp}" >> rpi_archives_properties.txt + echo "https://swdownloads.analog.com/cse/linux_rpi/${BUILD_SOURCEBRANCHNAME}/rpi_modules.tar.gz" >> rpi_archives_properties.txt + echo "https://swdownloads.analog.com/cse/linux_rpi/${BUILD_SOURCEBRANCHNAME}/rpi_latest_boot.tar.gz" >> rpi_archives_properties.txt + echo "checksum_modules=${md5_modules}" >> rpi_archives_properties.txt + echo "checksum_boot_files=${md5_boot}" >> rpi_archives_properties.txt + + scp -2 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o HostKeyAlgorithms=+ssh-dss \ + -i ${KEY_FILE} -r rpi_archives_properties.txt ${DEST_SERVER} } artifacts_${1} diff --git a/ci/travis/run-build-docker.sh b/ci/travis/run-build-docker.sh index 16a99e854300df..43dc220b935e72 100755 --- a/ci/travis/run-build-docker.sh +++ b/ci/travis/run-build-docker.sh @@ -3,7 +3,7 @@ set -e . ./ci/travis/lib.sh -ENV_VARS="BUILD_TYPE DEFCONFIG ARCH CROSS_COMPILE DTS_FILES IMAGE" +ENV_VARS="BUILD_TYPE DEFCONFIG ARCH CROSS_COMPILE DTS_FILES IMAGE BUILD_SOURCEBRANCH" ENV_VARS="$ENV_VARS TRAVIS_COMMIT TRAVIS_PULL_REQUEST CHECK_ALL_ADI_DRIVERS_HAVE_BEEN_BUILT" if [ "$DO_NOT_DOCKERIZE" = "1" ] ; then diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index e1170204ab516e..8a45fa6eec510f 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -56,7 +56,7 @@ adjust_kcflags_against_gcc() { export KCFLAGS } -APT_LIST="make bc u-boot-tools flex bison libssl-dev" +APT_LIST="make bc u-boot-tools flex bison libssl-dev tar kmod" if [ "$ARCH" = "arm64" ] ; then if [ -z "$CROSS_COMPILE" ] ; then @@ -190,7 +190,13 @@ build_default() { apt_update_install $APT_LIST make ${DEFCONFIG} - make -j$NUM_JOBS $IMAGE UIMAGE_LOADADDR=0x8000 + if [[ "${BUILD_SOURCEBRANCH}" =~ ^rpi-.* || "${BUILD_SOURCEBRANCH}" =~ staging-rpi ]]; then + make -j$NUM_JOBS zImage modules dtbs + make INSTALL_MOD_PATH="${PWD}/modules" modules_install + else + # normal build + make -j$NUM_JOBS $IMAGE UIMAGE_LOADADDR=0x8000 + fi if [ "$CHECK_ALL_ADI_DRIVERS_HAVE_BEEN_BUILT" = "1" ] ; then check_all_adi_files_have_been_built From 6a3acca8134c8f6996a66039e8bb13fa8f643d3f Mon Sep 17 00:00:00 2001 From: Raluca Chis Date: Fri, 18 Mar 2022 15:52:17 +0200 Subject: [PATCH 242/407] CI:fix rpi build conditions Fix build conditions for rpi branch Signed-off-by: Raluca Chis --- ci/travis/run-build-docker.sh | 2 +- ci/travis/run-build.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ci/travis/run-build-docker.sh b/ci/travis/run-build-docker.sh index 43dc220b935e72..31cc7c4e427e09 100755 --- a/ci/travis/run-build-docker.sh +++ b/ci/travis/run-build-docker.sh @@ -3,7 +3,7 @@ set -e . ./ci/travis/lib.sh -ENV_VARS="BUILD_TYPE DEFCONFIG ARCH CROSS_COMPILE DTS_FILES IMAGE BUILD_SOURCEBRANCH" +ENV_VARS="BUILD_TYPE DEFCONFIG ARCH CROSS_COMPILE DTS_FILES IMAGE BUILD_SOURCEBRANCH SYSTEM_PULLREQUEST_TARGETBRANCH" ENV_VARS="$ENV_VARS TRAVIS_COMMIT TRAVIS_PULL_REQUEST CHECK_ALL_ADI_DRIVERS_HAVE_BEEN_BUILT" if [ "$DO_NOT_DOCKERIZE" = "1" ] ; then diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index 8a45fa6eec510f..69611c3d320778 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -190,7 +190,8 @@ build_default() { apt_update_install $APT_LIST make ${DEFCONFIG} - if [[ "${BUILD_SOURCEBRANCH}" =~ ^rpi-.* || "${BUILD_SOURCEBRANCH}" =~ staging-rpi ]]; then + if [[ "${SYSTEM_PULLREQUEST_TARGETBRANCH}" =~ ^rpi-.* || "${BUILD_SOURCEBRANCH}" =~ ^refs/heads/rpi-.* \ + || "${BUILD_SOURCEBRANCH}" =~ ^refs/heads/staging-rpi ]]; then make -j$NUM_JOBS zImage modules dtbs make INSTALL_MOD_PATH="${PWD}/modules" modules_install else From 7c88c94d0b527dbff5d1110f8aab2003c739df15 Mon Sep 17 00:00:00 2001 From: Raluca Chis Date: Mon, 21 Mar 2022 14:48:52 +0200 Subject: [PATCH 243/407] CI:add echo to check builds Add echo command in order to see in log file which option is followed for build. Signed-off-by: Raluca Chis --- ci/travis/run-build.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index 69611c3d320778..3cd404dd24c327 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -192,10 +192,11 @@ build_default() { make ${DEFCONFIG} if [[ "${SYSTEM_PULLREQUEST_TARGETBRANCH}" =~ ^rpi-.* || "${BUILD_SOURCEBRANCH}" =~ ^refs/heads/rpi-.* \ || "${BUILD_SOURCEBRANCH}" =~ ^refs/heads/staging-rpi ]]; then + echo "Rpi build" make -j$NUM_JOBS zImage modules dtbs make INSTALL_MOD_PATH="${PWD}/modules" modules_install else - # normal build + echo "Normal build" make -j$NUM_JOBS $IMAGE UIMAGE_LOADADDR=0x8000 fi From 715d9b938b1af3ca4de63715fafdb7aa86e6162a Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Mon, 21 Mar 2022 22:57:48 +0200 Subject: [PATCH 244/407] iio: jesd204: axi_jesd204_[rx|tx]: Use devm_clk_get_optional() For conv2 and link optional clocks. Unlike devm_clk_get(), that returns -ENOENT when there is no clock producer, devm_clk_get_optional() returns NULL. Since in this case this is the exact expected behavior, use devm_clk_get_optional() instead. There are no functional changes, but the code will be simplified. Signed-off-by: Dragos Bogdan --- drivers/iio/jesd204/axi_jesd204_rx.c | 18 ++++++------------ drivers/iio/jesd204/axi_jesd204_tx.c | 18 ++++++------------ 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/drivers/iio/jesd204/axi_jesd204_rx.c b/drivers/iio/jesd204/axi_jesd204_rx.c index 07007c495bf3c1..5cb71ecd9fb060 100644 --- a/drivers/iio/jesd204/axi_jesd204_rx.c +++ b/drivers/iio/jesd204/axi_jesd204_rx.c @@ -1168,19 +1168,13 @@ static int axi_jesd204_rx_probe(struct platform_device *pdev) * This is used in axi_jesd204_rx_jesd204_link_setup() where the * main REFCLK is the parent of jesd->lane_clk. */ - jesd->conv2_clk = devm_clk_get(&pdev->dev, "conv2"); - if (IS_ERR(jesd->conv2_clk)) { - if (PTR_ERR(jesd->conv2_clk) != -ENOENT) - return PTR_ERR(jesd->conv2_clk); - jesd->conv2_clk = NULL; - } + jesd->conv2_clk = devm_clk_get_optional(&pdev->dev, "conv2"); + if (IS_ERR(jesd->conv2_clk)) + return PTR_ERR(jesd->conv2_clk); - jesd->link_clk = devm_clk_get(&pdev->dev, "link_clk"); - if (IS_ERR(jesd->link_clk)) { - if (PTR_ERR(jesd->link_clk) != -ENOENT) - return PTR_ERR(jesd->link_clk); - jesd->link_clk = NULL; - } + jesd->link_clk = devm_clk_get_optional(&pdev->dev, "link_clk"); + if (IS_ERR(jesd->link_clk)) + return PTR_ERR(jesd->link_clk); ret = clk_prepare_enable(jesd->axi_clk); if (ret) diff --git a/drivers/iio/jesd204/axi_jesd204_tx.c b/drivers/iio/jesd204/axi_jesd204_tx.c index 8cce050d754600..d816da5ba854b1 100644 --- a/drivers/iio/jesd204/axi_jesd204_tx.c +++ b/drivers/iio/jesd204/axi_jesd204_tx.c @@ -916,19 +916,13 @@ static int axi_jesd204_tx_probe(struct platform_device *pdev) * This is used in axi_jesd204_rx_jesd204_link_setup() where the * main REFCLK is the parent of jesd->lane_clk. */ - jesd->conv2_clk = devm_clk_get(&pdev->dev, "conv2"); - if (IS_ERR(jesd->conv2_clk)) { - if (PTR_ERR(jesd->conv2_clk) != -ENOENT) - return PTR_ERR(jesd->conv2_clk); - jesd->conv2_clk = NULL; - } + jesd->conv2_clk = devm_clk_get_optional(&pdev->dev, "conv2"); + if (IS_ERR(jesd->conv2_clk)) + return PTR_ERR(jesd->conv2_clk); - jesd->link_clk = devm_clk_get(&pdev->dev, "link_clk"); - if (IS_ERR(jesd->link_clk)) { - if (PTR_ERR(jesd->link_clk) != -ENOENT) - return PTR_ERR(jesd->link_clk); - jesd->link_clk = NULL; - } + jesd->link_clk = devm_clk_get_optional(&pdev->dev, "link_clk"); + if (IS_ERR(jesd->link_clk)) + return PTR_ERR(jesd->link_clk); ret = clk_prepare_enable(jesd->axi_clk); if (ret) From a1dc4f0014d640020f277d2926ca7d858094116f Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Mon, 21 Mar 2022 23:25:52 +0200 Subject: [PATCH 245/407] iio: jesd204: axi_adxcvr: Use devm_clk_get_optional() for conv2 Unlike devm_clk_get(), that returns -ENOENT when there is no clock producer, devm_clk_get_optional() returns NULL. Since in this case this is the exact expected behavior, use devm_clk_get_optional() instead. There are no functional changes, but the code will be simplified. Signed-off-by: Dragos Bogdan --- drivers/iio/jesd204/axi_adxcvr.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/iio/jesd204/axi_adxcvr.c b/drivers/iio/jesd204/axi_adxcvr.c index 9668ad6589ac41..e429881a8b9455 100644 --- a/drivers/iio/jesd204/axi_adxcvr.c +++ b/drivers/iio/jesd204/axi_adxcvr.c @@ -1024,12 +1024,9 @@ static int adxcvr_probe(struct platform_device *pdev) * Otional CPLL/QPLL REFCLK from a difference source * which rate and state must be in sync with the conv clk */ - st->conv2_clk = devm_clk_get(&pdev->dev, "conv2"); - if (IS_ERR(st->conv2_clk)) { - if (PTR_ERR(st->conv2_clk) != -ENOENT) - return PTR_ERR(st->conv2_clk); - st->conv2_clk = NULL; - } + st->conv2_clk = devm_clk_get_optional(&pdev->dev, "conv2"); + if (IS_ERR(st->conv2_clk)) + return PTR_ERR(st->conv2_clk); st->lane_rate_div40_clk = devm_clk_get(&pdev->dev, "div40"); if (IS_ERR(st->lane_rate_div40_clk)) { From 2aa7ac113716f339ecfb57d5a9ea016d47cd7a46 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Tue, 22 Mar 2022 15:25:59 +0200 Subject: [PATCH 246/407] arch: arm64: dts: stingray: Move adf4371 to axi_spi_fmc This change makes adar1000s and adf4371 able to run at different clock rates. "spi-max-frequency" was also updated to reflect the axi_spi_fmc configuration. Signed-off-by: Dragos Bogdan --- .../dts/xilinx/zynqmp-zcu102-rev10-stingray.dts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts index 089eb5289dc57a..3b8056c106d7e5 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts @@ -160,6 +160,19 @@ xlnx,spi-mode = <0>; }; + axi_spi_fmc: spi@85300000 { + #address-cells = <1>; + #size-cells = <0>; + bits-per-word = <8>; + compatible = "xlnx,xps-spi-2.00.a"; + fifo-size = <16>; + interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>; + num-cs = <0x8>; + reg = <0x85300000 0x10000>; + xlnx,num-ss-bits = <0x8>; + xlnx,spi-mode = <0>; + }; + axi_i2c_pmod: i2c@85100000 { #address-cells = <1>; #size-cells = <0>; @@ -312,7 +325,9 @@ spi-max-frequency = <12500000>; vcc-supply = <&vcc_ltc2314>; }; +}; +&axi_spi_fmc { adf4371_clk0: adf4371-0@6 { compatible = "adi,adf4371"; reg = <6>; @@ -321,7 +336,7 @@ #clock-cells = <1>; #size-cells = <0>; - spi-max-frequency = <12500000>; + spi-max-frequency = <6250000>; clocks = <&adf4371_clkin>; clock-names = "clkin"; clock-output-names = "pll0-clk-rf8", "pll0-clk-rfaux8", From 8ec0a617bdb002fd97dded9f2e40e401d778f9d5 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Wed, 23 Mar 2022 14:11:10 +0200 Subject: [PATCH 247/407] arch: arm64: dts: stingray: Set HMC7044 EXT_REF to 100 MHz According to the application requirements. Signed-off-by: Dragos Bogdan --- .../boot/dts/xilinx/zynqmp-zcu102-rev10-stingray-vcxo100.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray-vcxo100.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray-vcxo100.dts index 738018465c2fee..0ef1705b4c7af6 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray-vcxo100.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray-vcxo100.dts @@ -22,6 +22,6 @@ */ &hmc7044 { - adi,pll1-clkin-frequencies = <100000000 10000000 0 0>; + adi,pll1-clkin-frequencies = <100000000 100000000 0 0>; adi,vcxo-frequency = <100000000>; }; From e929a78f89626ced48b1cab675891be026252d56 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Wed, 23 Mar 2022 14:16:40 +0200 Subject: [PATCH 248/407] arch: arm64: dts: stingray: Enable autorevertive reference switching Revert to HMC7044 PLL1 best clock option if it becomes available again. Signed-off-by: Dragos Bogdan --- arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts index 3b8056c106d7e5..6c2f0e2c9a38fd 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts @@ -346,6 +346,7 @@ &hmc7044 { adi,pll1-ref-prio-ctrl = <0xE1>; /* prefer CLKIN1 -> CLKIN0 -> CLKIN2 -> CLKIN3 */ + adi,pll1-ref-autorevert-enable; }; &i2c1 { From 0c7b219130356061a7ad18c1df184f96f783f62a Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Thu, 24 Mar 2022 14:12:52 +0200 Subject: [PATCH 249/407] arch: arm64: dts: stingray: Enable direct clocking For AD9081, using a 12 GHz signal provided on EXT_CLK. According to the application requirements. Signed-off-by: Dragos Bogdan --- .../zynqmp-zcu102-rev10-stingray-vcxo100.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray-vcxo100.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray-vcxo100.dts index 0ef1705b4c7af6..e8c1c1f6db8e63 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray-vcxo100.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray-vcxo100.dts @@ -25,3 +25,19 @@ adi,pll1-clkin-frequencies = <100000000 100000000 0 0>; adi,vcxo-frequency = <100000000>; }; + +/ { + clocks { + direct_clk_12000m: clock@1 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <1200000000>; /* DAC_FREQUENCY / 10 */ + clock-output-names = "direct_clk_12000m"; + }; + }; +}; + +&trx0_ad9081 { + clocks = <&direct_clk_12000m>; /* dev_clk */ + dev_clk-clock-scales = <1 10>; +}; From fc176b258187b67bb0e5f24cc7ff78039c7e28e1 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Thu, 24 Mar 2022 16:18:47 +0200 Subject: [PATCH 250/407] arch: arm: socfpga_adi_defconfig: Enable DEBUG_FS For being able to access the debugging files. Signed-off-by: Dragos Bogdan --- arch/arm/configs/socfpga_adi_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/socfpga_adi_defconfig b/arch/arm/configs/socfpga_adi_defconfig index 0d5dc65d262fe5..71cc26db69ac6b 100644 --- a/arch/arm/configs/socfpga_adi_defconfig +++ b/arch/arm/configs/socfpga_adi_defconfig @@ -147,6 +147,7 @@ CONFIG_CMA_SIZE_MBYTES=128 CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y CONFIG_DETECT_HUNG_TASK=y # CONFIG_SCHED_DEBUG is not set CONFIG_FUNCTION_TRACER=y From 40a36cca77dcd388226270fc657625f3d6357269 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 24 Mar 2022 10:45:46 +0200 Subject: [PATCH 251/407] arch: arm: dts: zed-adv7511 add eeprom label Add label for the eeprom device such that it can be disabled for the zynq-zed-adv7511 based projects that do not have one. Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zed-adv7511.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/zynq-zed-adv7511.dtsi b/arch/arm/boot/dts/zynq-zed-adv7511.dtsi index 67c1d257334960..a43ce2cd58b8f3 100644 --- a/arch/arm/boot/dts/zynq-zed-adv7511.dtsi +++ b/arch/arm/boot/dts/zynq-zed-adv7511.dtsi @@ -69,7 +69,7 @@ #size-cells = <0>; #address-cells = <1>; - eeprom@50 { + eeprom1: eeprom@50 { compatible = "at24,24c02"; reg = <0x50>; }; From 407d8ffd6be1f4d801b453193ebf192337a5db23 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 24 Mar 2022 10:48:55 +0200 Subject: [PATCH 252/407] arch: arm: dts: zynq-zed-adv7511: disable EEPROM No eeprom is available for the zynq-zed-adv7511. Fixes error: `Timeout waiting at Tx empty`. Fixes: d52c2e5 ("Add ZED + ADV7511 device tree") Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zed-adv7511.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/zynq-zed-adv7511.dts b/arch/arm/boot/dts/zynq-zed-adv7511.dts index f5c77dad921890..dc487359f8091d 100644 --- a/arch/arm/boot/dts/zynq-zed-adv7511.dts +++ b/arch/arm/boot/dts/zynq-zed-adv7511.dts @@ -14,3 +14,7 @@ #include "zynq-zed.dtsi" #include "zynq-zed-adv7511.dtsi" + +&eeprom1 { + status = "disabled"; +}; From e5c55731d6e2a9121bdf81532e18a82e7db0fc08 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 24 Mar 2022 10:53:05 +0200 Subject: [PATCH 253/407] arch: dts: zynq-zed-adv7511-cn0363: disable EEPROM No eeprom is available for the zynq-zed-adv7511-cn0363. Fixes error: `Timeout waiting at Tx empty`. Fixes: 149d69d ("Add dts file for the CN0363 project") Signed-off-by: Antoniu Miclaus --- arch/arm/boot/dts/zynq-zed-adv7511-cn0363.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/zynq-zed-adv7511-cn0363.dts b/arch/arm/boot/dts/zynq-zed-adv7511-cn0363.dts index 49cf9ed969b046..3bd7ea6855aa1b 100644 --- a/arch/arm/boot/dts/zynq-zed-adv7511-cn0363.dts +++ b/arch/arm/boot/dts/zynq-zed-adv7511-cn0363.dts @@ -13,3 +13,7 @@ #include "zynq-zed.dtsi" #include "zynq-zed-adv7511.dtsi" #include "adi-zynq-cn0363.dtsi" + +&eeprom1 { + status = "disabled"; +}; From ee23e6341e1b44805a299f9a5d66db5e85637167 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Thu, 24 Mar 2022 22:17:11 +0200 Subject: [PATCH 254/407] arch: arm64: dts: stingray: Make vcxo100/122.88 distinction Since zynqmp-zcu102-rev10-stingray-vcxo100.dts was explicitly created to be used with the VCXO = 100.000 MHz version of AD9081-FMC-EBZ, make zynqmp-zcu102-rev10-stingray.dts not being dependent on the default setting from zynqmp-zcu102-rev10-ad9081-m8-l4.dts either. Signed-off-by: Dragos Bogdan --- arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts index 6c2f0e2c9a38fd..ace93e9c172201 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-stingray.dts @@ -345,6 +345,9 @@ }; &hmc7044 { + adi,pll1-clkin-frequencies = <122880000 30720000 0 0>; + adi,vcxo-frequency = <122880000>; + adi,pll1-ref-prio-ctrl = <0xE1>; /* prefer CLKIN1 -> CLKIN0 -> CLKIN2 -> CLKIN3 */ adi,pll1-ref-autorevert-enable; }; From 367e584078965b48655e0f7550b70b22dd918d34 Mon Sep 17 00:00:00 2001 From: "Liviu.Iacob" Date: Thu, 24 Mar 2022 09:30:16 +0000 Subject: [PATCH 255/407] iio: adc: ad9208: Fix ad9695 Add custom configuration for the ad9695 device. Fixes: 647846c ("iio: adc: Support AD6684, AD6688, AD9689, AD9694, AD9695, AD9697") Signed-off-by: Liviu.Iacob --- drivers/iio/adc/ad9208.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad9208.c b/drivers/iio/adc/ad9208.c index b481d74942c945..8ca8a174b08015 100644 --- a/drivers/iio/adc/ad9208.c +++ b/drivers/iio/adc/ad9208.c @@ -1549,7 +1549,6 @@ static int ad9208_probe(struct spi_device *spi) case CHIPID_AD6684: case CHIPID_AD9689: case CHIPID_AD9694: - case CHIPID_AD9695: phy->ad9208.model = 0x9208; phy->ad9208.input_clk_min_hz = 2500000000ULL; phy->ad9208.input_clk_max_hz = 6000000000ULL; @@ -1559,6 +1558,16 @@ static int ad9208_probe(struct spi_device *spi) phy->ad9208.slr_min_mbps = 390; chan_id = (spi_id & ID_DUAL) ? ID_AD9208_X2 : ID_AD9208; break; + case CHIPID_AD9695: + phy->ad9208.model = 0x9208; + phy->ad9208.input_clk_min_hz = 625000000ULL; + phy->ad9208.input_clk_max_hz = 1300000000ULL; + phy->ad9208.adc_clk_min_hz = 625000000ULL; + phy->ad9208.adc_clk_max_hz = 3100000000ULL; + phy->ad9208.slr_max_mbps = 16000; + phy->ad9208.slr_min_mbps = 1687; + chan_id = (spi_id & ID_DUAL) ? ID_AD9208_X2 : ID_AD9208; + break; case CHIPID_AD9680: phy->ad9208.model = 0x9680; phy->ad9208.input_clk_min_hz = 300000000ULL; From 4f111abe6f76bd93be56fcd6fab65b4579b12707 Mon Sep 17 00:00:00 2001 From: "Liviu.Iacob" Date: Fri, 18 Mar 2022 13:50:47 +0000 Subject: [PATCH 256/407] arch: arm64: dts: add zynqmp-zcu102-rev10-ad9695 dts Add devicetree support for ad9695 with zcu102 carrier. Signed-off-by: Liviu.Iacob --- .../dts/xilinx/zynqmp-zcu102-rev10-ad9695.dts | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9695.dts diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9695.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9695.dts new file mode 100644 index 00000000000000..918bf88f8cc684 --- /dev/null +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9695.dts @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD9695 / AD9689 ANALOG-TO-DIGITAL CONVERTER + * https://wiki.analog.com/resources/eval/ad9208-3000ebz + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/ad9208 + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2019-2022 Analog Devices Inc. + */ + +#include "zynqmp-zcu102-rev1.0.dts" +#include +#include +#include + +&i2c1 { + i2c-mux@75 { + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + eeprom@50 { + compatible = "at24,24c02"; + reg = <0x50>; + }; + }; + }; +}; + +/ { + clocks { + ad9695_clkin: clock@0 { + #clock-cells = <0>; + compatible = "adjustable-clock"; + clock-frequency = <1300000000>; + clock-accuracy = <1000000000>; + clock-output-names = "ad9695_clk"; + }; + device_clk: clock@1 { + #clock-cells = <0>; + compatible = "adjustable-clock"; + clock-frequency = <325000000>; + clock-accuracy = <1000000000>; + clock-output-names = "dev_clk"; + }; + }; + fpga_axi: fpga-axi@0 { + interrupt-parent = <&gic>; + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges = <0 0 0 0xffffffff>; + + rx_dma: rx-dmac@9c400000 { + #dma-cells = <1>; + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x9c400000 0x1000>; + interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zynqmp_clk 71>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <128>; + adi,source-bus-type = <1>; + adi,destination-bus-width = <128>; + adi,destination-bus-type = <0>; + }; + }; + }; + + axi_ad9695_core: axi-ad9695-hpc@84a00000 { + compatible = "adi,axi-ad9208-1.0"; + reg = <0x84a00000 0x2000>; + dmas = <&rx_dma 0>; + dma-names = "rx"; + spibus-connected = <&adc0_ad9695>; + }; + + axi_ad9695_jesd: axi-jesd204-rx@84aa0000 { + compatible = "adi,axi-jesd204-rx-1.0"; + reg = <0x84aa0000 0x4000>; + interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; + + clocks = <&zynqmp_clk 71>, <&device_clk>, <&axi_ad9695_adxcvr 0>; + clock-names = "s_axi_aclk", "device_clk", "lane_clk"; + + adi,octets-per-frame = <1>; + adi,frames-per-multiframe = <32>; + adi,subclass = <0>; + + #clock-cells = <0>; + clock-output-names = "jesd_adc_lane_clk"; + }; + + axi_ad9695_adxcvr: axi-adxcvr-rx@84a60000 { + compatible = "adi,axi-adxcvr-1.0"; + reg = <0x84a60000 0x10000>; + + clocks = <&device_clk>, <&device_clk>; + clock-names = "conv", "div40"; + + adi,sys-clk-select = ; + adi,out-clk-select = ; + adi,use-lpm-enable; + + #clock-cells = <1>; + clock-output-names = "adc_gt_clk", "rx_out_clk"; + }; + + axi_sysid_0: axi-sysid-0@85000000 { + compatible = "adi,axi-sysid-1.00.a"; + reg = <0x85000000 0x2000>; + }; + }; +}; + +&spi0 { + status = "okay"; + + adc0_ad9695: ad9695@0 { + compatible = "adi,ad9695"; + + powerdown-gpios = <&gpio 116 0>; + fastdetect-a-gpios = <&gpio 113 0>; + fastdetect-b-gpios = <&gpio 114 0>; + + spi-cpol; + spi-cpha; + spi-max-frequency = <5000000>; + reg = <0>; + + clocks = <&axi_ad9695_jesd>, <&ad9695_clkin>; + clock-names = "jesd_adc_clk", "adc_clk"; + + adi,powerdown-mode = ; + + adi,sampling-frequency = /bits/ 64 <1300000000>; + adi,input-clock-divider-ratio = <1>; + adi,duty-cycle-stabilizer-enable; + + adi,analog-input-neg-buffer-current = ; + adi,analog-input-pos-buffer-current = ; + + adi,sysref-lmfc-offset = <0>; + adi,sysref-pos-window-skew = <0>; + adi,sysref-neg-window-skew = <0>; + adi,sysref-mode = ; + adi,sysref-nshot-ignore-count = <0>; + + /* JESD204 parameters */ + + adi,octets-per-frame = <1>; + adi,frames-per-multiframe = <32>; + adi,converter-resolution = <16>; + adi,bits-per-sample = <16>; + adi,converters-per-device = <2>; + adi,control-bits-per-sample = <0>; + adi,lanes-per-device = <4>; + adi,subclass = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + }; +}; From 2c7abe4b1c5c6f66fe16f0d0f8223cf671ff42b1 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 28 Mar 2022 09:47:17 +0200 Subject: [PATCH 257/407] iio: frequency: ad9528: jesd204-fsm add clock synchronization state This adds the JESD204_OP_CLK_SYNC_STAGE1 per device callback. In this state we check the PLL2 lock status and synchronize the output divider network. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/ad9528.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/iio/frequency/ad9528.c b/drivers/iio/frequency/ad9528.c index 307d8685bb48d7..cbe80e1b1ab9ca 100644 --- a/drivers/iio/frequency/ad9528.c +++ b/drivers/iio/frequency/ad9528.c @@ -1395,6 +1395,26 @@ static int ad9528_jesd204_link_pre_setup(struct jesd204_dev *jdev, return JESD204_STATE_CHANGE_DONE; } +static int ad9528_jesd204_clks_sync(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason) +{ + struct device *dev = jesd204_dev_to_device(jdev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + int ret; + + if (reason != JESD204_STATE_OP_REASON_INIT) + return JESD204_STATE_CHANGE_DONE; + + dev_dbg(dev, "%s:%d reason %s\n", __func__, __LINE__, + jesd204_state_op_reason_str(reason)); + + ret = ad9528_sync(indio_dev); + if (ret) + return ret; + + return JESD204_STATE_CHANGE_DONE; +} + static const struct jesd204_dev_data jesd204_ad9528_init = { .sysref_cb = ad9528_jesd204_sysref, .state_ops = { @@ -1404,6 +1424,10 @@ static const struct jesd204_dev_data jesd204_ad9528_init = { [JESD204_OP_LINK_PRE_SETUP] = { .per_link = ad9528_jesd204_link_pre_setup, }, + [JESD204_OP_CLK_SYNC_STAGE1] = { + .per_device = ad9528_jesd204_clks_sync, + .mode = JESD204_STATE_OP_MODE_PER_DEVICE, + }, }, }; From aebc5122a41fa162ae168403a3c21e29109c43ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 25 Feb 2022 14:01:27 +0100 Subject: [PATCH 258/407] iio: dac: add support for ltc2688 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LTC2688 is a 16 channel, 16 bit, +-15V DAC with an integrated precision reference. It is guaranteed monotonic and has built in rail-to-rail output buffers that can source or sink up to 20 mA. Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20220225130129.69-2-nuno.sa@analog.com Signed-off-by: Jonathan Cameron (cherry picked from commit 832cb9eeb9312dd2e14133681d3920b773ef1eac) --- MAINTAINERS | 7 + drivers/iio/dac/Kconfig | 11 + drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ltc2688.c | 1075 +++++++++++++++++++++++++++++++++++++ 4 files changed, 1094 insertions(+) create mode 100644 drivers/iio/dac/ltc2688.c diff --git a/MAINTAINERS b/MAINTAINERS index 50e0c96e47762b..476e7e6b390e16 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10469,6 +10469,13 @@ S: Maintained F: Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml F: drivers/iio/dac/ltc1660.c +LTC2688 IIO DAC DRIVER +M: Nuno Sá +L: linux-iio@vger.kernel.org +S: Supported +W: http://ez.analog.com/community/linux-device-drivers +F: drivers/iio/dac/ltc2688.c + LTC2947 HARDWARE MONITOR DRIVER M: Nuno Sá L: linux-hwmon@vger.kernel.org diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 72e489704280c6..2717343a89d3f8 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -141,6 +141,17 @@ config AD5624R_SPI Say yes here to build support for Analog Devices AD5624R, AD5644R and AD5664R converters (DAC). This driver uses the common SPI interface. +config LTC2688 + tristate "Analog Devices LTC2688 DAC spi driver" + depends on SPI + select REGMAP + help + Say yes here to build support for Analog Devices + LTC2688 converters (DAC). + + To compile this driver as a module, choose M here: the + module will be called ltc2688. + config AD5686 tristate diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index a13a06682bd398..b4c0912fccbeb6 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_DS4424) += ds4424.o obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o obj-$(CONFIG_LTC1660) += ltc1660.o obj-$(CONFIG_LTC2632) += ltc2632.o +obj-$(CONFIG_LTC2688) += ltc2688.o obj-$(CONFIG_M62332) += m62332.o obj-$(CONFIG_MAX517) += max517.o obj-$(CONFIG_MAX5821) += max5821.o diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c new file mode 100644 index 00000000000000..0409588313704d --- /dev/null +++ b/drivers/iio/dac/ltc2688.c @@ -0,0 +1,1075 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LTC2688 16 channel, 16 bit Voltage Output SoftSpan DAC driver + * + * Copyright 2022 Analog Devices Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LTC2688_DAC_CHANNELS 16 + +#define LTC2688_CMD_CH_CODE(x) (0x00 + (x)) +#define LTC2688_CMD_CH_SETTING(x) (0x10 + (x)) +#define LTC2688_CMD_CH_OFFSET(x) (0X20 + (x)) +#define LTC2688_CMD_CH_GAIN(x) (0x30 + (x)) +#define LTC2688_CMD_CH_CODE_UPDATE(x) (0x40 + (x)) + +#define LTC2688_CMD_CONFIG 0x70 +#define LTC2688_CMD_POWERDOWN 0x71 +#define LTC2688_CMD_A_B_SELECT 0x72 +#define LTC2688_CMD_SW_TOGGLE 0x73 +#define LTC2688_CMD_TOGGLE_DITHER_EN 0x74 +#define LTC2688_CMD_THERMAL_STAT 0x77 +#define LTC2688_CMD_UPDATE_ALL 0x7C +#define LTC2688_CMD_NOOP 0xFF + +#define LTC2688_READ_OPERATION 0x80 + +/* Channel Settings */ +#define LTC2688_CH_SPAN_MSK GENMASK(2, 0) +#define LTC2688_CH_OVERRANGE_MSK BIT(3) +#define LTC2688_CH_TD_SEL_MSK GENMASK(5, 4) +#define LTC2688_CH_TGP_MAX 3 +#define LTC2688_CH_DIT_PER_MSK GENMASK(8, 6) +#define LTC2688_CH_DIT_PH_MSK GENMASK(10, 9) +#define LTC2688_CH_MODE_MSK BIT(11) + +#define LTC2688_DITHER_RAW_MASK GENMASK(15, 2) +#define LTC2688_CH_CALIBBIAS_MASK GENMASK(15, 2) +#define LTC2688_DITHER_RAW_MAX_VAL (BIT(14) - 1) +#define LTC2688_CH_CALIBBIAS_MAX_VAL (BIT(14) - 1) + +/* Configuration register */ +#define LTC2688_CONFIG_RST BIT(15) +#define LTC2688_CONFIG_EXT_REF BIT(1) + +#define LTC2688_DITHER_FREQ_AVAIL_N 5 + +enum { + LTC2688_SPAN_RANGE_0V_5V, + LTC2688_SPAN_RANGE_0V_10V, + LTC2688_SPAN_RANGE_M5V_5V, + LTC2688_SPAN_RANGE_M10V_10V, + LTC2688_SPAN_RANGE_M15V_15V, + LTC2688_SPAN_RANGE_MAX +}; + +enum { + LTC2688_MODE_DEFAULT, + LTC2688_MODE_DITHER_TOGGLE, +}; + +struct ltc2688_chan { + long dither_frequency[LTC2688_DITHER_FREQ_AVAIL_N]; + bool overrange; + bool toggle_chan; + u8 mode; +}; + +struct ltc2688_state { + struct spi_device *spi; + struct regmap *regmap; + struct regulator_bulk_data regulators[2]; + struct ltc2688_chan channels[LTC2688_DAC_CHANNELS]; + struct iio_chan_spec *iio_chan; + /* lock to protect against multiple access to the device and shared data */ + struct mutex lock; + int vref; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + u8 tx_data[6] ____cacheline_aligned; + u8 rx_data[3]; +}; + +static int ltc2688_spi_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct ltc2688_state *st = context; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx_data, + .bits_per_word = 8, + .len = reg_size + val_size, + .cs_change = 1, + }, { + .tx_buf = st->tx_data + 3, + .rx_buf = st->rx_data, + .bits_per_word = 8, + .len = reg_size + val_size, + }, + }; + int ret; + + memcpy(st->tx_data, reg, reg_size); + + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); + if (ret) + return ret; + + memcpy(val, &st->rx_data[1], val_size); + + return 0; +} + +static int ltc2688_spi_write(void *context, const void *data, size_t count) +{ + struct ltc2688_state *st = context; + + return spi_write(st->spi, data, count); +} + +static int ltc2688_span_get(const struct ltc2688_state *st, int c) +{ + int ret, reg, span; + + ret = regmap_read(st->regmap, LTC2688_CMD_CH_SETTING(c), ®); + if (ret) + return ret; + + span = FIELD_GET(LTC2688_CH_SPAN_MSK, reg); + /* sanity check to make sure we don't get any weird value from the HW */ + if (span >= LTC2688_SPAN_RANGE_MAX) + return -EIO; + + return span; +} + +static const int ltc2688_span_helper[LTC2688_SPAN_RANGE_MAX][2] = { + {0, 5000}, {0, 10000}, {-5000, 5000}, {-10000, 10000}, {-15000, 15000}, +}; + +static int ltc2688_scale_get(const struct ltc2688_state *st, int c, int *val) +{ + const struct ltc2688_chan *chan = &st->channels[c]; + int span, fs; + + span = ltc2688_span_get(st, c); + if (span < 0) + return span; + + fs = ltc2688_span_helper[span][1] - ltc2688_span_helper[span][0]; + if (chan->overrange) + fs = mult_frac(fs, 105, 100); + + *val = DIV_ROUND_CLOSEST(fs * st->vref, 4096); + + return 0; +} + +static int ltc2688_offset_get(const struct ltc2688_state *st, int c, int *val) +{ + int span; + + span = ltc2688_span_get(st, c); + if (span < 0) + return span; + + if (ltc2688_span_helper[span][0] < 0) + *val = -32768; + else + *val = 0; + + return 0; +} + +enum { + LTC2688_INPUT_A, + LTC2688_INPUT_B, + LTC2688_INPUT_B_AVAIL, + LTC2688_DITHER_OFF, + LTC2688_DITHER_FREQ_AVAIL, +}; + +static int ltc2688_dac_code_write(struct ltc2688_state *st, u32 chan, u32 input, + u16 code) +{ + struct ltc2688_chan *c = &st->channels[chan]; + int ret, reg; + + /* 2 LSBs set to 0 if writing dither amplitude */ + if (!c->toggle_chan && input == LTC2688_INPUT_B) { + if (code > LTC2688_DITHER_RAW_MAX_VAL) + return -EINVAL; + + code = FIELD_PREP(LTC2688_DITHER_RAW_MASK, code); + } + + mutex_lock(&st->lock); + /* select the correct input register to read from */ + ret = regmap_update_bits(st->regmap, LTC2688_CMD_A_B_SELECT, BIT(chan), + input << chan); + if (ret) + goto out_unlock; + + /* + * If in dither/toggle mode the dac should be updated by an + * external signal (or sw toggle) and not here. + */ + if (c->mode == LTC2688_MODE_DEFAULT) + reg = LTC2688_CMD_CH_CODE_UPDATE(chan); + else + reg = LTC2688_CMD_CH_CODE(chan); + + ret = regmap_write(st->regmap, reg, code); +out_unlock: + mutex_unlock(&st->lock); + return ret; +} + +static int ltc2688_dac_code_read(struct ltc2688_state *st, u32 chan, u32 input, + u32 *code) +{ + struct ltc2688_chan *c = &st->channels[chan]; + int ret; + + mutex_lock(&st->lock); + ret = regmap_update_bits(st->regmap, LTC2688_CMD_A_B_SELECT, BIT(chan), + input << chan); + if (ret) + goto out_unlock; + + ret = regmap_read(st->regmap, LTC2688_CMD_CH_CODE(chan), code); +out_unlock: + mutex_unlock(&st->lock); + + if (!c->toggle_chan && input == LTC2688_INPUT_B) + *code = FIELD_GET(LTC2688_DITHER_RAW_MASK, *code); + + return ret; +} + +static const int ltc2688_raw_range[] = {0, 1, U16_MAX}; + +static int ltc2688_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + switch (info) { + case IIO_CHAN_INFO_RAW: + *vals = ltc2688_raw_range; + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; + default: + return -EINVAL; + } +} + +static int ltc2688_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long info) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + int ret; + + switch (info) { + case IIO_CHAN_INFO_RAW: + ret = ltc2688_dac_code_read(st, chan->channel, LTC2688_INPUT_A, + val); + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_OFFSET: + ret = ltc2688_offset_get(st, chan->channel, val); + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = ltc2688_scale_get(st, chan->channel, val); + if (ret) + return ret; + + *val = 16; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_CALIBBIAS: + ret = regmap_read(st->regmap, + LTC2688_CMD_CH_OFFSET(chan->channel), val); + if (ret) + return ret; + + *val = FIELD_GET(LTC2688_CH_CALIBBIAS_MASK, *val); + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBSCALE: + ret = regmap_read(st->regmap, + LTC2688_CMD_CH_GAIN(chan->channel), val); + if (ret) + return ret; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ltc2688_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long info) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + if (val > U16_MAX || val < 0) + return -EINVAL; + + return ltc2688_dac_code_write(st, chan->channel, + LTC2688_INPUT_A, val); + case IIO_CHAN_INFO_CALIBBIAS: + if (val > LTC2688_CH_CALIBBIAS_MAX_VAL) + return -EINVAL; + + return regmap_write(st->regmap, + LTC2688_CMD_CH_OFFSET(chan->channel), + FIELD_PREP(LTC2688_CH_CALIBBIAS_MASK, val)); + case IIO_CHAN_INFO_CALIBSCALE: + return regmap_write(st->regmap, + LTC2688_CMD_CH_GAIN(chan->channel), val); + default: + return -EINVAL; + } +} + +static ssize_t ltc2688_dither_toggle_set(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + struct ltc2688_chan *c = &st->channels[chan->channel]; + int ret; + bool en; + + ret = kstrtobool(buf, &en); + if (ret) + return ret; + + mutex_lock(&st->lock); + ret = regmap_update_bits(st->regmap, LTC2688_CMD_TOGGLE_DITHER_EN, + BIT(chan->channel), en << chan->channel); + if (ret) + goto out_unlock; + + c->mode = en ? LTC2688_MODE_DITHER_TOGGLE : LTC2688_MODE_DEFAULT; +out_unlock: + mutex_unlock(&st->lock); + + return ret ?: len; +} + +static ssize_t ltc2688_reg_bool_get(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + const struct ltc2688_state *st = iio_priv(indio_dev); + int ret; + u32 val; + + ret = regmap_read(st->regmap, private, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", !!(val & BIT(chan->channel))); +} + +static ssize_t ltc2688_reg_bool_set(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + const struct ltc2688_state *st = iio_priv(indio_dev); + int ret; + bool en; + + ret = kstrtobool(buf, &en); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, private, BIT(chan->channel), + en << chan->channel); + if (ret) + return ret; + + return len; +} + +static ssize_t ltc2688_dither_freq_avail(const struct ltc2688_state *st, + const struct ltc2688_chan *chan, + char *buf) +{ + int sz = 0; + u32 f; + + for (f = 0; f < ARRAY_SIZE(chan->dither_frequency); f++) + sz += sysfs_emit_at(buf, sz, "%ld ", chan->dither_frequency[f]); + + buf[sz - 1] = '\n'; + + return sz; +} + +static ssize_t ltc2688_dither_freq_get(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + const struct ltc2688_state *st = iio_priv(indio_dev); + const struct ltc2688_chan *c = &st->channels[chan->channel]; + u32 reg, freq; + int ret; + + if (private == LTC2688_DITHER_FREQ_AVAIL) + return ltc2688_dither_freq_avail(st, c, buf); + + ret = regmap_read(st->regmap, LTC2688_CMD_CH_SETTING(chan->channel), + ®); + if (ret) + return ret; + + freq = FIELD_GET(LTC2688_CH_DIT_PER_MSK, reg); + if (freq >= ARRAY_SIZE(c->dither_frequency)) + return -EIO; + + return sysfs_emit(buf, "%ld\n", c->dither_frequency[freq]); +} + +static ssize_t ltc2688_dither_freq_set(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + const struct ltc2688_state *st = iio_priv(indio_dev); + const struct ltc2688_chan *c = &st->channels[chan->channel]; + long val; + u32 freq; + int ret; + + if (private == LTC2688_DITHER_FREQ_AVAIL) + return -EINVAL; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; + + for (freq = 0; freq < ARRAY_SIZE(c->dither_frequency); freq++) { + if (val == c->dither_frequency[freq]) + break; + } + + if (freq == ARRAY_SIZE(c->dither_frequency)) + return -EINVAL; + + ret = regmap_update_bits(st->regmap, + LTC2688_CMD_CH_SETTING(chan->channel), + LTC2688_CH_DIT_PER_MSK, + FIELD_PREP(LTC2688_CH_DIT_PER_MSK, freq)); + if (ret) + return ret; + + return len; +} + +static ssize_t ltc2688_dac_input_read(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + int ret; + u32 val; + + if (private == LTC2688_INPUT_B_AVAIL) + return sysfs_emit(buf, "[%u %u %u]\n", ltc2688_raw_range[0], + ltc2688_raw_range[1], + ltc2688_raw_range[2] / 4); + + if (private == LTC2688_DITHER_OFF) + return sysfs_emit(buf, "0\n"); + + ret = ltc2688_dac_code_read(st, chan->channel, private, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t ltc2688_dac_input_write(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + int ret; + u16 val; + + if (private == LTC2688_INPUT_B_AVAIL || private == LTC2688_DITHER_OFF) + return -EINVAL; + + ret = kstrtou16(buf, 10, &val); + if (ret) + return ret; + + ret = ltc2688_dac_code_write(st, chan->channel, private, val); + if (ret) + return ret; + + return len; +} + +static int ltc2688_get_dither_phase(struct iio_dev *dev, + const struct iio_chan_spec *chan) +{ + struct ltc2688_state *st = iio_priv(dev); + int ret, regval; + + ret = regmap_read(st->regmap, LTC2688_CMD_CH_SETTING(chan->channel), + ®val); + if (ret) + return ret; + + return FIELD_GET(LTC2688_CH_DIT_PH_MSK, regval); +} + +static int ltc2688_set_dither_phase(struct iio_dev *dev, + const struct iio_chan_spec *chan, + unsigned int phase) +{ + struct ltc2688_state *st = iio_priv(dev); + + return regmap_update_bits(st->regmap, + LTC2688_CMD_CH_SETTING(chan->channel), + LTC2688_CH_DIT_PH_MSK, + FIELD_PREP(LTC2688_CH_DIT_PH_MSK, phase)); +} + +static int ltc2688_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static const char * const ltc2688_dither_phase[] = { + "0", "1.5708", "3.14159", "4.71239", +}; + +static const struct iio_enum ltc2688_dither_phase_enum = { + .items = ltc2688_dither_phase, + .num_items = ARRAY_SIZE(ltc2688_dither_phase), + .set = ltc2688_set_dither_phase, + .get = ltc2688_get_dither_phase, +}; + +#define LTC2688_CHAN_EXT_INFO(_name, _what, _shared, _read, _write) { \ + .name = _name, \ + .read = (_read), \ + .write = (_write), \ + .private = (_what), \ + .shared = (_shared), \ +} + +/* + * For toggle mode we only expose the symbol attr (sw_toggle) in case a TGPx is + * not provided in dts. + */ +static const struct iio_chan_spec_ext_info ltc2688_toggle_sym_ext_info[] = { + LTC2688_CHAN_EXT_INFO("raw0", LTC2688_INPUT_A, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("raw1", LTC2688_INPUT_B, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("toggle_en", LTC2688_CMD_TOGGLE_DITHER_EN, + IIO_SEPARATE, ltc2688_reg_bool_get, + ltc2688_dither_toggle_set), + LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE, + ltc2688_reg_bool_get, ltc2688_reg_bool_set), + LTC2688_CHAN_EXT_INFO("symbol", LTC2688_CMD_SW_TOGGLE, IIO_SEPARATE, + ltc2688_reg_bool_get, ltc2688_reg_bool_set), + {} +}; + +static const struct iio_chan_spec_ext_info ltc2688_toggle_ext_info[] = { + LTC2688_CHAN_EXT_INFO("raw0", LTC2688_INPUT_A, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("raw1", LTC2688_INPUT_B, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("toggle_en", LTC2688_CMD_TOGGLE_DITHER_EN, + IIO_SEPARATE, ltc2688_reg_bool_get, + ltc2688_dither_toggle_set), + LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE, + ltc2688_reg_bool_get, ltc2688_reg_bool_set), + {} +}; + +static struct iio_chan_spec_ext_info ltc2688_dither_ext_info[] = { + LTC2688_CHAN_EXT_INFO("dither_raw", LTC2688_INPUT_B, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("dither_raw_available", LTC2688_INPUT_B_AVAIL, + IIO_SEPARATE, ltc2688_dac_input_read, + ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("dither_offset", LTC2688_DITHER_OFF, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + /* + * Not IIO_ENUM because the available freq needs to be computed at + * probe. We could still use it, but it didn't felt much right. + */ + LTC2688_CHAN_EXT_INFO("dither_frequency", 0, IIO_SEPARATE, + ltc2688_dither_freq_get, ltc2688_dither_freq_set), + LTC2688_CHAN_EXT_INFO("dither_frequency_available", + LTC2688_DITHER_FREQ_AVAIL, IIO_SEPARATE, + ltc2688_dither_freq_get, ltc2688_dither_freq_set), + IIO_ENUM("dither_phase", IIO_SEPARATE, <c2688_dither_phase_enum), + /* + * !\note this is the only difference with upstream where this macro is + * named IIO_ENUM_AVAILABLE(). + */ + IIO_ENUM_AVAILABLE_SHARED("dither_phase", IIO_SEPARATE, + <c2688_dither_phase_enum), + LTC2688_CHAN_EXT_INFO("dither_en", LTC2688_CMD_TOGGLE_DITHER_EN, + IIO_SEPARATE, ltc2688_reg_bool_get, + ltc2688_dither_toggle_set), + LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE, + ltc2688_reg_bool_get, ltc2688_reg_bool_set), + {} +}; + +static const struct iio_chan_spec_ext_info ltc2688_ext_info[] = { + LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE, + ltc2688_reg_bool_get, ltc2688_reg_bool_set), + {} +}; + +#define LTC2688_CHANNEL(_chan) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (_chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), \ + .ext_info = ltc2688_ext_info, \ +} + +static const struct iio_chan_spec ltc2688_channels[] = { + LTC2688_CHANNEL(0), + LTC2688_CHANNEL(1), + LTC2688_CHANNEL(2), + LTC2688_CHANNEL(3), + LTC2688_CHANNEL(4), + LTC2688_CHANNEL(5), + LTC2688_CHANNEL(6), + LTC2688_CHANNEL(7), + LTC2688_CHANNEL(8), + LTC2688_CHANNEL(9), + LTC2688_CHANNEL(10), + LTC2688_CHANNEL(11), + LTC2688_CHANNEL(12), + LTC2688_CHANNEL(13), + LTC2688_CHANNEL(14), + LTC2688_CHANNEL(15), +}; + +static void ltc2688_clk_disable(void *clk) +{ + clk_disable_unprepare(clk); +} + +static const int ltc2688_period[LTC2688_DITHER_FREQ_AVAIL_N] = { + 4, 8, 16, 32, 64, +}; + +static int ltc2688_tgp_clk_setup(struct ltc2688_state *st, + struct ltc2688_chan *chan, + struct fwnode_handle *node, int tgp) +{ + unsigned long rate; + struct clk *clk; + int ret, f; + + clk = devm_get_clk_from_child(&st->spi->dev, to_of_node(node), NULL); + if (IS_ERR(clk)) + return dev_err_probe(&st->spi->dev, PTR_ERR(clk), + "failed to get tgp clk.\n"); + + ret = clk_prepare_enable(clk); + if (ret) + return dev_err_probe(&st->spi->dev, ret, + "failed to enable tgp clk.\n"); + + ret = devm_add_action_or_reset(&st->spi->dev, ltc2688_clk_disable, clk); + if (ret) + return ret; + + if (chan->toggle_chan) + return 0; + + /* calculate available dither frequencies */ + rate = clk_get_rate(clk); + for (f = 0; f < ARRAY_SIZE(chan->dither_frequency); f++) + chan->dither_frequency[f] = DIV_ROUND_CLOSEST(rate, ltc2688_period[f]); + + return 0; +} + +static int ltc2688_span_lookup(const struct ltc2688_state *st, int min, int max) +{ + u32 span; + + for (span = 0; span < ARRAY_SIZE(ltc2688_span_helper); span++) { + if (min == ltc2688_span_helper[span][0] && + max == ltc2688_span_helper[span][1]) + return span; + } + + return -EINVAL; +} + +static int ltc2688_channel_config(struct ltc2688_state *st) +{ + struct device *dev = &st->spi->dev; + struct fwnode_handle *child; + u32 reg, clk_input, val, tmp[2]; + int ret, span; + + device_for_each_child_node(dev, child) { + struct ltc2688_chan *chan; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) { + fwnode_handle_put(child); + return dev_err_probe(dev, ret, + "Failed to get reg property\n"); + } + + if (reg >= LTC2688_DAC_CHANNELS) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, + "reg bigger than: %d\n", + LTC2688_DAC_CHANNELS); + } + + val = 0; + chan = &st->channels[reg]; + if (fwnode_property_read_bool(child, "adi,toggle-mode")) { + chan->toggle_chan = true; + /* assume sw toggle ABI */ + st->iio_chan[reg].ext_info = ltc2688_toggle_sym_ext_info; + /* + * Clear IIO_CHAN_INFO_RAW bit as toggle channels expose + * out_voltage_raw{0|1} files. + */ + __clear_bit(IIO_CHAN_INFO_RAW, + &st->iio_chan[reg].info_mask_separate); + } + + ret = fwnode_property_read_u32_array(child, "adi,output-range-microvolt", + tmp, ARRAY_SIZE(tmp)); + if (!ret) { + span = ltc2688_span_lookup(st, (int)tmp[0] / 1000, + tmp[1] / 1000); + if (span < 0) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, + "output range not valid:[%d %d]\n", + tmp[0], tmp[1]); + } + + val |= FIELD_PREP(LTC2688_CH_SPAN_MSK, span); + } + + ret = fwnode_property_read_u32(child, "adi,toggle-dither-input", + &clk_input); + if (!ret) { + if (clk_input >= LTC2688_CH_TGP_MAX) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, + "toggle-dither-input inv value(%d)\n", + clk_input); + } + + ret = ltc2688_tgp_clk_setup(st, chan, child, clk_input); + if (ret) { + fwnode_handle_put(child); + return ret; + } + + /* + * 0 means software toggle which is the default mode. + * Hence the +1. + */ + val |= FIELD_PREP(LTC2688_CH_TD_SEL_MSK, clk_input + 1); + + /* + * If a TGPx is given, we automatically assume a dither + * capable channel (unless toggle is already enabled). + * On top of this we just set here the dither bit in the + * channel settings. It won't have any effect until the + * global toggle/dither bit is enabled. + */ + if (!chan->toggle_chan) { + val |= FIELD_PREP(LTC2688_CH_MODE_MSK, 1); + st->iio_chan[reg].ext_info = ltc2688_dither_ext_info; + } else { + /* wait, no sw toggle after all */ + st->iio_chan[reg].ext_info = ltc2688_toggle_ext_info; + } + } + + if (fwnode_property_read_bool(child, "adi,overrange")) { + chan->overrange = true; + val |= LTC2688_CH_OVERRANGE_MSK; + } + + if (!val) + continue; + + ret = regmap_write(st->regmap, LTC2688_CMD_CH_SETTING(reg), + val); + if (ret) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, + "failed to set chan settings\n"); + } + } + + return 0; +} + +static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref) +{ + struct gpio_desc *gpio; + int ret; + + /* + * If we have a reset pin, use that to reset the board, If not, use + * the reset bit. + */ + gpio = devm_gpiod_get_optional(&st->spi->dev, "clr", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) + return dev_err_probe(&st->spi->dev, PTR_ERR(gpio), + "Failed to get reset gpio"); + if (gpio) { + usleep_range(1000, 1200); + /* bring device out of reset */ + gpiod_set_value_cansleep(gpio, 0); + } else { + ret = regmap_update_bits(st->regmap, LTC2688_CMD_CONFIG, + LTC2688_CONFIG_RST, + LTC2688_CONFIG_RST); + if (ret) + return ret; + } + + usleep_range(10000, 12000); + + /* + * Duplicate the default channel configuration as it can change during + * @ltc2688_channel_config() + */ + st->iio_chan = devm_kmemdup(&st->spi->dev, ltc2688_channels, + sizeof(ltc2688_channels), GFP_KERNEL); + if (!st->iio_chan) + return -ENOMEM; + + ret = ltc2688_channel_config(st); + if (ret) + return ret; + + if (!vref) + return 0; + + return regmap_set_bits(st->regmap, LTC2688_CMD_CONFIG, + LTC2688_CONFIG_EXT_REF); +} + +static void ltc2688_disable_regulators(void *data) +{ + struct ltc2688_state *st = data; + + regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators); +} + +static void ltc2688_disable_regulator(void *regulator) +{ + regulator_disable(regulator); +} + +static bool ltc2688_reg_readable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case LTC2688_CMD_CH_CODE(0) ... LTC2688_CMD_CH_GAIN(15): + return true; + case LTC2688_CMD_CONFIG ... LTC2688_CMD_THERMAL_STAT: + return true; + default: + return false; + } +} + +static bool ltc2688_reg_writable(struct device *dev, unsigned int reg) +{ + /* + * There's a jump from 0x76 to 0x78 in the write codes and the thermal + * status code is 0x77 (which is read only) so that we need to check + * that special condition. + */ + if (reg <= LTC2688_CMD_UPDATE_ALL && reg != LTC2688_CMD_THERMAL_STAT) + return true; + + return false; +} + +static struct regmap_bus ltc2688_regmap_bus = { + .read = ltc2688_spi_read, + .write = ltc2688_spi_write, + .read_flag_mask = LTC2688_READ_OPERATION, + .reg_format_endian_default = REGMAP_ENDIAN_BIG, + .val_format_endian_default = REGMAP_ENDIAN_BIG, +}; + +static const struct regmap_config ltc2688_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .readable_reg = ltc2688_reg_readable, + .writeable_reg = ltc2688_reg_writable, + /* ignoring the no op command */ + .max_register = LTC2688_CMD_UPDATE_ALL, +}; + +static const struct iio_info ltc2688_info = { + .write_raw = ltc2688_write_raw, + .read_raw = ltc2688_read_raw, + .read_avail = ltc2688_read_avail, + .debugfs_reg_access = ltc2688_reg_access, +}; + +static int ltc2688_probe(struct spi_device *spi) +{ + struct ltc2688_state *st; + struct iio_dev *indio_dev; + struct regulator *vref_reg; + struct device *dev = &spi->dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + + /* Just write this once. No need to do it in every regmap read. */ + st->tx_data[3] = LTC2688_CMD_NOOP; + mutex_init(&st->lock); + + st->regmap = devm_regmap_init(dev, <c2688_regmap_bus, st, + <c2688_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "Failed to init regmap"); + + st->regulators[0].supply = "vcc"; + st->regulators[1].supply = "iovcc"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(st->regulators), + st->regulators); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ret = regulator_bulk_enable(ARRAY_SIZE(st->regulators), st->regulators); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulators\n"); + + ret = devm_add_action_or_reset(dev, ltc2688_disable_regulators, st); + if (ret) + return ret; + + vref_reg = devm_regulator_get_optional(dev, "vref"); + if (IS_ERR(vref_reg)) { + if (PTR_ERR(vref_reg) != -ENODEV) + return dev_err_probe(dev, PTR_ERR(vref_reg), + "Failed to get vref regulator"); + + vref_reg = NULL; + /* internal reference */ + st->vref = 4096; + } else { + ret = regulator_enable(vref_reg); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable vref regulators\n"); + + ret = devm_add_action_or_reset(dev, ltc2688_disable_regulator, + vref_reg); + if (ret) + return ret; + + ret = regulator_get_voltage(vref_reg); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get vref\n"); + + st->vref = ret / 1000; + } + + ret = ltc2688_setup(st, vref_reg); + if (ret) + return ret; + + indio_dev->name = "ltc2688"; + indio_dev->info = <c2688_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = st->iio_chan; + indio_dev->num_channels = ARRAY_SIZE(ltc2688_channels); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id ltc2688_of_id[] = { + { .compatible = "adi,ltc2688" }, + {} +}; +MODULE_DEVICE_TABLE(of, ltc2688_of_id); + +static const struct spi_device_id ltc2688_id[] = { + { "ltc2688" }, + {} +}; +MODULE_DEVICE_TABLE(spi, ltc2688_id); + +static struct spi_driver ltc2688_driver = { + .driver = { + .name = "ltc2688", + .of_match_table = ltc2688_of_id, + }, + .probe = ltc2688_probe, + .id_table = ltc2688_id, +}; +module_spi_driver(ltc2688_driver); + +MODULE_AUTHOR("Nuno Sá "); +MODULE_DESCRIPTION("Analog Devices LTC2688 DAC"); +MODULE_LICENSE("GPL"); From 0128931edf517b4781b6b8088596389873ba0a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 25 Feb 2022 14:01:28 +0100 Subject: [PATCH 259/407] iio: ABI: add ABI file for the LTC2688 DAC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define the sysfs interface for toggle or dither capable channels. Dither capable channels will have the extended interface: * out_voltageY_dither_en * out_voltageY_dither_raw * out_voltageY_dither_offset * out_voltageY_dither_raw_available * out_voltageY_dither_frequency * out_voltageY_dither_frequency_available * out_voltageY_dither_phase * out_voltageY_dither_phase_available Toggle enabled channels will have: * out_voltageY_toggle_en * out_voltageY_raw0 * out_voltageY_raw1 * out_voltageY_symbol The common interface present in all channels is: * out_voltageY_raw (not present in toggle enabled channels) * out_voltageY_raw_available * out_voltageY_powerdown * out_voltageY_scale * out_voltageY_offset * out_voltageY_calibbias * out_voltageY_calibscale Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20220225130129.69-3-nuno.sa@analog.com Signed-off-by: Jonathan Cameron (cherry picked from commit 52302f87d0a126a34686f40cdd4ab28f9e824a68) --- .../ABI/testing/sysfs-bus-iio-dac-ltc2688 | 86 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 87 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 diff --git a/Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 b/Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 new file mode 100644 index 00000000000000..1c35971277ba27 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 @@ -0,0 +1,86 @@ +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_en +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Dither enable. Write 1 to enable dither or 0 to disable it. This is useful + for changing the dither parameters. They way it should be done is: + + - disable dither operation; + - change dither parameters (eg: frequency, phase...); + - enabled dither operation + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_raw +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + This raw, unscaled value refers to the dither signal amplitude. + The same scale as in out_voltageY_raw applies. However, the + offset might be different as it's always 0 for this attribute. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_raw_available +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Available range for dither raw amplitude values. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_offset +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Offset applied to out_voltageY_dither_raw. Read only attribute + always set to 0. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_frequency +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Sets the dither signal frequency. Units are in Hz. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_frequency_available +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Returns the available values for the dither frequency. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_phase +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Sets the dither signal phase. Units are in Radians. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_phase_available +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Returns the available values for the dither phase. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_toggle_en +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Toggle enable. Write 1 to enable toggle or 0 to disable it. This is + useful when one wants to change the DAC output codes. The way it should + be done is: + + - disable toggle operation; + - change out_voltageY_raw0 and out_voltageY_raw1; + - enable toggle operation. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw0 +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw1 +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + It has the same meaning as out_voltageY_raw. This attribute is + specific to toggle enabled channels and refers to the DAC output + code in INPUT_A (_raw0) and INPUT_B (_raw1). The same scale and offset + as in out_voltageY_raw applies. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_symbol +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Performs a SW toggle. This attribute is specific to toggle + enabled channels and allows to toggle between out_voltageY_raw0 + and out_voltageY_raw1 through software. Writing 0 will select + out_voltageY_raw0 while 1 selects out_voltageY_raw1. diff --git a/MAINTAINERS b/MAINTAINERS index 476e7e6b390e16..d795cde541d445 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10474,6 +10474,7 @@ M: Nuno Sá L: linux-iio@vger.kernel.org S: Supported W: http://ez.analog.com/community/linux-device-drivers +F: Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 F: drivers/iio/dac/ltc2688.c LTC2947 HARDWARE MONITOR DRIVER From 4c1dc23debbb71aba19ffabb542df7008ac05f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 25 Feb 2022 14:01:29 +0100 Subject: [PATCH 260/407] dt-bindings: iio: Add ltc2688 documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the LTC2688 devicetree properties. Signed-off-by: Nuno Sá Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220225130129.69-4-nuno.sa@analog.com Signed-off-by: Jonathan Cameron (cherry picked from commit f568cbd9aef24a02b22884d92c154f3af076b383) --- .../bindings/iio/dac/adi,ltc2688.yaml | 146 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 147 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml new file mode 100644 index 00000000000000..48f9e7d2942357 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml @@ -0,0 +1,146 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,ltc2688.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices LTC2688 DAC + +maintainers: + - Nuno Sá + +description: | + Analog Devices LTC2688 16 channel, 16 bit, +-15V DAC + https://www.analog.com/media/en/technical-documentation/data-sheets/ltc2688.pdf + +properties: + compatible: + enum: + - adi,ltc2688 + + reg: + maxItems: 1 + + vcc-supply: + description: Analog Supply Voltage Input. + + iovcc-supply: + description: Digital Input/Output Supply Voltage. + + vref-supply: + description: + Reference Input/Output. The voltage at the REF pin sets the full-scale + range of all channels. If not provided the internal reference is used and + also provided on the VREF pin". + + clr-gpios: + description: + If specified, it will be asserted during driver probe. As the line is + active low, it should be marked GPIO_ACTIVE_LOW. + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + "^channel@([0-9]|1[0-5])$": + type: object + + properties: + reg: + description: The channel number representing the DAC output channel. + maximum: 15 + + adi,toggle-mode: + description: + Set the channel as a toggle enabled channel. Toggle operation enables + fast switching of a DAC output between two different DAC codes without + any SPI transaction. + type: boolean + + adi,output-range-microvolt: + description: Specify the channel output full scale range. + oneOf: + - items: + - const: 0 + - enum: [5000000, 10000000] + - items: + - const: -5000000 + - const: 5000000 + - items: + - const: -10000000 + - const: 10000000 + - items: + - const: -15000000 + - const: 15000000 + + adi,overrange: + description: Enable 5% overrange over the selected full scale range. + type: boolean + + clocks: + maxItems: 1 + + adi,toggle-dither-input: + description: + Selects the TGPx pin to be associated with this channel. This setting + only makes sense for toggle or dither enabled channels. If + @adi,toggle-mode is not set and this property is given, the channel is + assumed to be a dither capable channel. Note that multiple channels + can be mapped to the same pin. If this setting is given, the + respective @clock must also be provided. Mappings between this and + input pins + 0 - TGP1 + 1 - TGP2 + 2 - TGP3 + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2] + + dependencies: + adi,toggle-dither-input: [ clocks ] + + required: + - reg + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + spi { + #address-cells = <1>; + #size-cells = <0>; + ltc2688: ltc2688@0 { + compatible = "adi,ltc2688"; + reg = <0>; + + vcc-supply = <&vcc>; + iovcc-supply = <&vcc>; + vref-supply = <&vref>; + + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + adi,toggle-mode; + adi,overrange; + }; + + channel@1 { + reg = <1>; + adi,output-range-microvolt = <0 10000000>; + + clocks = <&clock_tgp3>; + adi,toggle-dither-input = <2>; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index d795cde541d445..0066154ce20d3d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10475,6 +10475,7 @@ L: linux-iio@vger.kernel.org S: Supported W: http://ez.analog.com/community/linux-device-drivers F: Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 +F: Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml F: drivers/iio/dac/ltc2688.c LTC2947 HARDWARE MONITOR DRIVER From 04d2cfe29a1dc394ecc3650b6f0ad9c6e813e63f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Tue, 29 Mar 2022 15:12:50 +0200 Subject: [PATCH 261/407] iio: Kconfig.adi: select LTC2688 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Select the LTC2688 driver. Signed-off-by: Nuno Sá --- drivers/iio/Kconfig.adi | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/Kconfig.adi b/drivers/iio/Kconfig.adi index b95eeef83bcd15..244bba5afbf9e3 100644 --- a/drivers/iio/Kconfig.adi +++ b/drivers/iio/Kconfig.adi @@ -178,3 +178,4 @@ config IIO_ALL_ADI_DRIVERS select IIO_GEN_MUX select AD74413R select ADI_IIO_FAKEDEV + select LTC2688 From f8fe2697b43014922ed6cd52f8e3820eb18a3489 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 25 Mar 2022 10:13:28 +0100 Subject: [PATCH 262/407] iio: adc: ad9081: Fast Frequency Hopping support This path adds FFH support for the RX side. TX side FFH support is revised by supporting individual frequencies for each CDUC. Also GPIO controlled hopping is now supported. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 496 +++++++++++++++++++++++++++------------ 1 file changed, 349 insertions(+), 147 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 5aedefa936a66b..1b706c094eeac4 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -47,6 +47,8 @@ #define MAX_NUM_MAIN_DATAPATHS 4 #define MAX_NUM_CHANNELIZER 8 +#define MAX_NUM_RX_NCO_CHAN_REGS 16 +#define MAX_NUM_TX_NCO_CHAN_REGS 31 #define for_each_cddc(bit, mask) \ for ((bit) = 0; (bit) < MAX_NUM_MAIN_DATAPATHS; (bit)++) \ @@ -72,15 +74,16 @@ enum { CDDC_NCO_FREQ, TRX_CONVERTER_RATE, TRX_ENABLE, CDDC_FFH_HOPF_SET, + ADC_CDDC_FFH_TRIG_HOP_EN, + CDDC_FFH_INDEX_SET, + DAC_FFH_GPIO_MODE_SET, + DAC_FFH_FREQ_SET, }; enum { AD9081_LOOPBACK_MODE, AD9081_ADC_CLK_PWDN, AD9081_MCS, - AD9081_DAC_FFH_FREQ_SET, - AD9081_DAC_FFH_INDEX_SET, - AD9081_DAC_FFH_MODE_SET, AD9081_JESD204_FSM_ERROR, AD9081_JESD204_FSM_PAUSED, AD9081_JESD204_FSM_STATE, @@ -200,9 +203,10 @@ struct ad9081_phy { u8 tx_dac_chan_xbar_1x_non1x[MAX_NUM_MAIN_DATAPATHS]; u8 tx_main_ffh_select[MAX_NUM_MAIN_DATAPATHS]; - u8 ffh_hopf_index; - u8 ffh_hopf_mode; - s64 ffh_hopf_vals[32]; + u8 tx_ffh_hopf_index[MAX_NUM_MAIN_DATAPATHS]; + u8 tx_ffh_hopf_mode[MAX_NUM_MAIN_DATAPATHS]; + s64 tx_ffh_hopf_vals[MAX_NUM_TX_NCO_CHAN_REGS][MAX_NUM_MAIN_DATAPATHS]; + bool tx_ffh_hopf_via_gpio_en; struct dac_settings_cache dac_cache; struct ad9081_jesd_link jrx_link_tx[2]; @@ -212,9 +216,9 @@ struct ad9081_phy { u32 adc_dcm[2]; u64 adc_frequency_hz; s64 rx_fddc_shift[MAX_NUM_CHANNELIZER]; - s64 rx_cddc_shift[MAX_NUM_MAIN_DATAPATHS]; + s64 rx_cddc_shift[MAX_NUM_RX_NCO_CHAN_REGS][MAX_NUM_MAIN_DATAPATHS]; s32 rx_fddc_phase[MAX_NUM_CHANNELIZER]; - s32 rx_cddc_phase[MAX_NUM_MAIN_DATAPATHS]; + s32 rx_cddc_phase[MAX_NUM_RX_NCO_CHAN_REGS][MAX_NUM_MAIN_DATAPATHS]; u32 rx_nyquist_zone[MAX_NUM_MAIN_DATAPATHS]; u8 rx_cddc_c2r[MAX_NUM_MAIN_DATAPATHS]; @@ -226,6 +230,11 @@ struct ad9081_phy { u8 rx_fddc_mxr_if[MAX_NUM_CHANNELIZER]; u8 rx_fddc_select; u8 rx_cddc_select; + u8 rx_main_ffh_select[MAX_NUM_MAIN_DATAPATHS]; + u8 rx_main_ffh_index[MAX_NUM_MAIN_DATAPATHS]; + u8 rx_main_ffh_mode[MAX_NUM_MAIN_DATAPATHS]; + u8 rx_cddc_nco_channel_select_mode[MAX_NUM_MAIN_DATAPATHS]; + bool rx_main_ffh_trig_en[MAX_NUM_MAIN_DATAPATHS]; adi_cms_chip_id_t chip_id; @@ -239,6 +248,7 @@ struct ad9081_phy { struct ad9081_debugfs_entry debugfs_entry[10]; u32 ad9081_debugfs_entry_index; u8 direct_lb_map; + u8 rx_ffh_gpio_mux_sel[6]; }; static int adi_ad9081_adc_nco_sync(adi_ad9081_device_t *device, @@ -968,6 +978,84 @@ static const struct iio_enum ad9081_nyquist_zone_enum = { .get = ad9081_nyquist_zone_read, }; +static int ad9081_main_ffh_mode_read(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev); + struct ad9081_phy *phy = conv->phy; + u8 cddc_num, cddc_mask, fddc_num, fddc_mask; + + ad9081_iiochan_to_fddc_cddc(phy, chan, &fddc_num, + &fddc_mask, &cddc_num, &cddc_mask); + + if (chan->output) + return phy->tx_ffh_hopf_mode[cddc_num]; + + return phy->rx_main_ffh_mode[cddc_num]; +} + +static int ad9081_main_ffh_mode_write(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int item) +{ + struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev); + struct ad9081_phy *phy = conv->phy; + u8 cddc_num, cddc_mask, fddc_num, fddc_mask; + int ret, i; + + ad9081_iiochan_to_fddc_cddc(phy, chan, &fddc_num, + &fddc_mask, &cddc_num, &cddc_mask); + + mutex_lock(&indio_dev->mlock); + if (chan->output) { + ret = adi_ad9081_dac_duc_main_nco_hopf_mode_set(&phy->ad9081, + cddc_mask, item); + if (!ret) + for_each_cddc(i, cddc_mask) + phy->tx_ffh_hopf_mode[i] = item; + + } else { + ret = adi_ad9081_adc_ddc_coarse_nco_channel_update_mode_set(&phy->ad9081, + cddc_mask, item > 0); + + if (item > 0) + ret = adi_ad9081_adc_ddc_coarse_gpio_chip_xfer_mode_set(&phy->ad9081, + cddc_mask, item - 1); + + if (!ret) + phy->rx_main_ffh_mode[cddc_num] = item; + } + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static const char *const ad9081_dac_main_ffh_modes[] = { + "phase_continuous", + "phase_incontinuous", + "phase_coherent", +}; + +static const struct iio_enum ad9081_dac_main_ffh_mode_enum = { + .items = ad9081_dac_main_ffh_modes, + .num_items = ARRAY_SIZE(ad9081_dac_main_ffh_modes), + .set = ad9081_main_ffh_mode_write, + .get = ad9081_main_ffh_mode_read, +}; + +static const char *const ad9081_adc_main_ffh_modes[] = { + "instantaneous_update", + "synchronous_update_by_transfer_bit", + "synchronous_update_by_gpio", +}; + +static const struct iio_enum ad9081_adc_main_ffh_mode_enum = { + .items = ad9081_adc_main_ffh_modes, + .num_items = ARRAY_SIZE(ad9081_adc_main_ffh_modes), + .set = ad9081_main_ffh_mode_write, + .get = ad9081_main_ffh_mode_read, +}; + static ssize_t ad9081_ext_info_read(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, char *buf) @@ -993,7 +1081,7 @@ static ssize_t ad9081_ext_info_read(struct iio_dev *indio_dev, break; } } else { - val = phy->rx_cddc_shift[cddc_num]; + val = phy->rx_cddc_shift[phy->rx_main_ffh_index[cddc_num]][cddc_num]; ret = 0; } break; @@ -1050,7 +1138,7 @@ static ssize_t ad9081_ext_info_read(struct iio_dev *indio_dev, break; } } else { - val = phy->rx_cddc_phase[cddc_num]; + val = phy->rx_cddc_phase[phy->rx_main_ffh_index[cddc_num]][cddc_num]; ret = 0; } break; @@ -1100,14 +1188,64 @@ static ssize_t ad9081_ext_info_read(struct iio_dev *indio_dev, ret = 0; break; case CDDC_FFH_HOPF_SET: + if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { + ret = -EOPNOTSUPP; + break; + } + if (chan->output) { for_each_cddc(i, cddc_mask) { val = phy->tx_main_ffh_select[i]; ret = 0; goto out_unlock; } + } else { + val = phy->rx_main_ffh_select[cddc_num]; + ret = 0; + } + break; + case CDDC_FFH_INDEX_SET: + if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { + ret = -EOPNOTSUPP; + break; + } + + if (chan->output) { + val = phy->tx_ffh_hopf_index[cddc_num]; + ret = 0; + } else { + val = phy->rx_main_ffh_index[cddc_num]; + ret = 0; + } + break; + case ADC_CDDC_FFH_TRIG_HOP_EN: + case DAC_FFH_GPIO_MODE_SET: + if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { + ret = -EOPNOTSUPP; + break; } - /* fall-through */ + + if (chan->output) { + val = phy->tx_ffh_hopf_via_gpio_en; + ret = 0; + } else { + val = phy->rx_main_ffh_trig_en[cddc_num]; + ret = 0; + } + break; + case DAC_FFH_FREQ_SET: + if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { + ret = -EOPNOTSUPP; + break; + } + + if (phy->tx_disable) { + ret = -ENODEV; + break; + } + ret = sysfs_emit(buf, "%lld\n", + phy->tx_ffh_hopf_vals[phy->tx_ffh_hopf_index[cddc_num]][cddc_num]); + break; default: ret = -EINVAL; } @@ -1134,6 +1272,7 @@ static ssize_t ad9081_ext_info_write(struct iio_dev *indio_dev, u8 cddc_num, cddc_mask, fddc_num, fddc_mask; s16 val16; s64 val64; + u64 ftw; mutex_lock(&indio_dev->mlock); @@ -1161,7 +1300,7 @@ static ssize_t ad9081_ext_info_write(struct iio_dev *indio_dev, ret = adi_ad9081_adc_ddc_coarse_nco_set(&phy->ad9081, cddc_mask, readin); if (!ret) - phy->rx_cddc_shift[cddc_num] = readin; + phy->rx_cddc_shift[phy->rx_main_ffh_index[cddc_num]][cddc_num] = readin; else ret = -EFAULT; } @@ -1217,7 +1356,7 @@ static ssize_t ad9081_ext_info_write(struct iio_dev *indio_dev, ret = adi_ad9081_adc_ddc_coarse_nco_phase_offset_set( &phy->ad9081, cddc_mask, val64); if (!ret) - phy->rx_cddc_phase[cddc_num] = readin; + phy->rx_cddc_phase[phy->rx_main_ffh_index[cddc_num]][cddc_num] = readin; else ret = -EFAULT; } @@ -1327,21 +1466,131 @@ static ssize_t ad9081_ext_info_write(struct iio_dev *indio_dev, break; case CDDC_FFH_HOPF_SET: + if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { + ret = -EOPNOTSUPP; + break; + } ret = kstrtoll(buf, 10, &readin); if (ret) goto out; if (chan->output) { + if (readin < 0 || readin >= MAX_NUM_TX_NCO_CHAN_REGS) { + ret = -EINVAL; + goto out; + } /* set main nco */ for_each_cddc(i, cddc_mask) { - ret = adi_ad9081_dac_duc_main_nco_hopf_select_set( - &phy->ad9081, BIT(i), readin); + ret = adi_ad9081_dac_duc_main_nco_hopf_select_set(&phy->ad9081, + BIT(i), readin + 1); if (!ret) phy->tx_main_ffh_select[i] = readin; else ret = -EFAULT; } + } else { + if (readin < 0 || readin >= MAX_NUM_RX_NCO_CHAN_REGS) { + ret = -EINVAL; + goto out; + } + ret = adi_ad9081_adc_ddc_coarse_nco_channel_selection_set(&phy->ad9081, + cddc_mask, readin); + if (!ret) + phy->rx_main_ffh_select[cddc_num] = readin; + else + ret = -EFAULT; + } + break; + case CDDC_FFH_INDEX_SET: + if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { + ret = -EOPNOTSUPP; + break; + } + ret = kstrtoll(buf, 10, &readin); + if (ret) + goto out; + + if (chan->output) { + readin = clamp_t(long long, readin, 0, 30); + if (readin < 0 || readin >= MAX_NUM_TX_NCO_CHAN_REGS) { + ret = -EINVAL; + goto out; + } + for_each_cddc(i, cddc_mask) + phy->tx_ffh_hopf_index[i] = readin; + } else { + if (readin < 0 || readin >= MAX_NUM_RX_NCO_CHAN_REGS) { + ret = -EINVAL; + goto out; + } + ret = adi_ad9081_adc_ddc_coarse_nco_channel_update_index_set(&phy->ad9081, + cddc_mask, readin); + if (!ret) + phy->rx_main_ffh_index[cddc_num] = readin; + else + ret = -EFAULT; + } + break; + case ADC_CDDC_FFH_TRIG_HOP_EN: + case DAC_FFH_GPIO_MODE_SET: + if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { + ret = -EOPNOTSUPP; + break; + } + ret = strtobool(buf, &enable); + if (ret) + goto out; + + if (chan->output) { + ret = adi_ad9081_dac_duc_main_nco_hopf_gpio_as_hop_en_set(&phy->ad9081, + enable); + if (!ret) + phy->tx_ffh_hopf_via_gpio_en = enable; + + adi_ad9081_jesd_rx_syncb_mode_set(&phy->ad9081, 0); + adi_ad9081_jesd_rx_syncb_driver_powerdown_set(&phy->ad9081, + !enable); + } else { + ret = adi_ad9081_adc_ddc_coarse_trig_hop_en_set(&phy->ad9081, + cddc_mask, enable); + if (!ret) + phy->rx_main_ffh_trig_en[cddc_num] = enable; + } + break; + case DAC_FFH_FREQ_SET: + if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { + ret = -EOPNOTSUPP; + break; + } + + if (phy->tx_disable) { + ret = -ENODEV; + break; + } + + ret = kstrtoll(buf, 10, &readin); + if (ret) { + ret = -EINVAL; + break; + } + ret = adi_ad9081_hal_calc_tx_nco_ftw32(&phy->ad9081, + phy->ad9081.dev_info.dac_freq_hz, readin, + &ftw); + if (ret) { + ret = -EINVAL; + break; + } + + ret = adi_ad9081_dac_duc_main_nco_hopf_ftw_set(&phy->ad9081, + cddc_mask, + phy->tx_ffh_hopf_index[cddc_num] + 1, + ftw); + if (ret) { + ret = -EINVAL; + break; } + for_each_cddc(i, cddc_mask) + phy->tx_ffh_hopf_vals[phy->tx_ffh_hopf_index[cddc_num]][i] = readin; break; default: ret = -EINVAL; @@ -1358,6 +1607,8 @@ static struct iio_chan_spec_ext_info rxadc_ext_info[] = { IIO_ENUM_AVAILABLE("test_mode", &ad9081_testmode_enum), IIO_ENUM("nyquist_zone", IIO_SEPARATE, &ad9081_nyquist_zone_enum), IIO_ENUM_AVAILABLE("nyquist_zone", &ad9081_nyquist_zone_enum), + IIO_ENUM("main_ffh_mode", IIO_SEPARATE, &ad9081_adc_main_ffh_mode_enum), + IIO_ENUM_AVAILABLE("main_ffh_mode", &ad9081_adc_main_ffh_mode_enum), { .name = "main_nco_frequency", .read = ad9081_ext_info_read, @@ -1420,10 +1671,33 @@ static struct iio_chan_spec_ext_info rxadc_ext_info[] = { .shared = true, .private = TRX_CONVERTER_RATE, }, + { + .name = "main_nco_ffh_select", + .read = ad9081_ext_info_read, + .write = ad9081_ext_info_write, + .shared = false, + .private = CDDC_FFH_HOPF_SET, + }, + { + .name = "main_nco_ffh_index", + .read = ad9081_ext_info_read, + .write = ad9081_ext_info_write, + .shared = false, + .private = CDDC_FFH_INDEX_SET, + }, + { + .name = "main_ffh_trig_hop_en", + .read = ad9081_ext_info_read, + .write = ad9081_ext_info_write, + .shared = false, + .private = ADC_CDDC_FFH_TRIG_HOP_EN, + }, {}, }; static struct iio_chan_spec_ext_info txdac_ext_info[] = { + IIO_ENUM("main_ffh_mode", IIO_SEPARATE, &ad9081_dac_main_ffh_mode_enum), + IIO_ENUM_AVAILABLE("main_ffh_mode", &ad9081_dac_main_ffh_mode_enum), { .name = "main_nco_frequency", .read = ad9081_ext_info_read, @@ -1514,6 +1788,27 @@ static struct iio_chan_spec_ext_info txdac_ext_info[] = { .shared = false, .private = CDDC_FFH_HOPF_SET, }, + { + .name = "main_nco_ffh_index", + .read = ad9081_ext_info_read, + .write = ad9081_ext_info_write, + .shared = false, + .private = CDDC_FFH_INDEX_SET, + }, + { + .name = "main_ffh_gpio_mode_en", + .read = ad9081_ext_info_read, + .write = ad9081_ext_info_write, + .shared = true, + .private = DAC_FFH_GPIO_MODE_SET, + }, + { + .name = "main_nco_ffh_frequency", + .read = ad9081_ext_info_read, + .write = ad9081_ext_info_write, + .shared = false, + .private = DAC_FFH_FREQ_SET, + }, {}, }; @@ -1814,6 +2109,12 @@ static int ad9081_setup_tx(struct spi_device *spi) } } + if (phy->tx_ffh_hopf_via_gpio_en) { + adi_ad9081_jesd_rx_syncb_mode_set(&phy->ad9081, 0); + adi_ad9081_dac_duc_main_nco_hopf_gpio_as_hop_en_set(&phy->ad9081, 1); + adi_ad9081_jesd_rx_syncb_driver_powerdown_set(&phy->ad9081, 0); + } + return 0; } @@ -1869,7 +2170,7 @@ static int ad9081_setup_rx(struct spi_device *spi) /* start txfe rx */ ret = adi_ad9081_device_startup_rx(&phy->ad9081, phy->rx_cddc_select, phy->rx_fddc_select, - phy->rx_cddc_shift, + phy->rx_cddc_shift[0], phy->rx_fddc_shift, phy->rx_cddc_dcm, phy->rx_fddc_dcm, phy->rx_cddc_c2r, phy->rx_fddc_c2r, jesd_param, @@ -1900,6 +2201,12 @@ static int ad9081_setup_rx(struct spi_device *spi) phy->rx_nyquist_zone[i]); if (ret != 0) return ret; + + ret = adi_ad9081_adc_ddc_coarse_nco_channel_select_via_gpio_set(&phy->ad9081, + BIT(i), phy->rx_cddc_nco_channel_select_mode[i]); + if (ret != 0) + return ret; + } for_each_fddc(i, phy->rx_fddc_select) { @@ -1917,9 +2224,8 @@ static int ad9081_setup_rx(struct spi_device *spi) /* setup txfe jtx converter mapping */ for (i = 0; i < ARRAY_SIZE(phy->jtx_link_rx[0].link_converter_select); i++) { - ret = adi_ad9081_jesd_tx_conv_sel_set( - &phy->ad9081, AD9081_LINK_0, i, - phy->jtx_link_rx[0].link_converter_select[i]); + ret = adi_ad9081_jesd_tx_conv_sel_set(&phy->ad9081, + AD9081_LINK_0, i, phy->jtx_link_rx[0].link_converter_select[i]); if (ret != 0) return ret; } @@ -1962,7 +2268,14 @@ static int ad9081_setup_rx(struct spi_device *spi) &phy->clkscale[RX_SAMPL_CLK_LINK2]); } - return 0; + for (i = 0; i < ARRAY_SIZE(phy->rx_ffh_gpio_mux_sel); i++) + if (phy->rx_ffh_gpio_mux_sel[i] == AD9081_PERI_SEL_SYNCINB1_N || + phy->rx_ffh_gpio_mux_sel[i] == AD9081_PERI_SEL_SYNCINB1_P) + adi_ad9081_hal_bf_set(&phy->ad9081, REG_SYNCB_CTRL_ADDR, + BF_PD_SYNCB_RX_RC_INFO, 0); + + return adi_ad9081_adc_ddc_ffh_sel_to_gpio_mapping_set(&phy->ad9081, + phy->rx_ffh_gpio_mux_sel); } static int ad9081_setup(struct spi_device *spi) @@ -2266,12 +2579,9 @@ static ssize_t ad9081_phy_store(struct device *dev, struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev); struct ad9081_phy *phy = conv->phy; unsigned long res; - long long lval; - uint64_t ftw; bool bres; bool enable; int ret = 0; - u8 val; mutex_lock(&indio_dev->mlock); @@ -2348,87 +2658,7 @@ static ssize_t ad9081_phy_store(struct device *dev, phy->mcs_cached_val = res; break; - case AD9081_DAC_FFH_INDEX_SET: - if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { - ret = -ENOTSUPP; - break; - } - - if (phy->tx_disable) { - ret = -ENODEV; - break; - } - - ret = kstrtoul(buf, 0, &res); - if (ret) { - ret = -EINVAL; - break; - } - phy->ffh_hopf_index = res; - break; - case AD9081_DAC_FFH_FREQ_SET: - if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { - ret = -ENOTSUPP; - break; - } - if (phy->tx_disable) { - ret = -ENODEV; - break; - } - - ret = kstrtoll(buf, 10, &lval); - if (ret) { - ret = -EINVAL; - break; - } - ret = adi_ad9081_hal_calc_tx_nco_ftw32(&phy->ad9081, - phy->ad9081.dev_info.dac_freq_hz, lval, - &ftw); - if (ret) { - ret = -EINVAL; - break; - } - - ret = adi_ad9081_dac_duc_main_nco_hopf_ftw_set(&phy->ad9081, - AD9081_DAC_ALL, - phy->ffh_hopf_index, - ftw); - if (ret) { - ret = -EINVAL; - break; - } - - phy->ffh_hopf_vals[phy->ffh_hopf_index] = lval; - break; - case AD9081_DAC_FFH_MODE_SET: - if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { - ret = -ENOTSUPP; - break; - } - - if (phy->tx_disable) { - ret = -ENODEV; - break; - } - - ret = sysfs_match_string(ffh_modes, buf); - if (ret < 0) { - ret = -EINVAL; - break; - } - - val = ret; - - ret = adi_ad9081_dac_duc_main_nco_hopf_mode_set(&phy->ad9081, - AD9081_DAC_ALL, val); - if (ret) { - ret = -EINVAL; - break; - } - - phy->ffh_hopf_mode = val; - break; case AD9081_JESD204_FSM_RESUME: if (!phy->jdev) { ret = -ENOTSUPP; @@ -2503,27 +2733,6 @@ static ssize_t ad9081_phy_show(struct device *dev, } ret = sprintf(buf, "%u\n", phy->device_cache.adc_clk_pwdn); break; - case AD9081_DAC_FFH_INDEX_SET: - if (phy->tx_disable) { - ret = -ENODEV; - break; - } - ret = sprintf(buf, "%u\n", phy->ffh_hopf_index); - break; - case AD9081_DAC_FFH_FREQ_SET: - if (phy->tx_disable) { - ret = -ENODEV; - break; - } - ret = sprintf(buf, "%lld\n", phy->ffh_hopf_vals[phy->ffh_hopf_index]); - break; - case AD9081_DAC_FFH_MODE_SET: - if (phy->tx_disable) { - ret = -ENODEV; - break; - } - ret = sprintf(buf, "%s\n", ffh_modes[phy->ffh_hopf_mode]); - break; case AD9081_MCS: ret = sprintf(buf, "%u\n", phy->mcs_cached_val); break; @@ -2638,24 +2847,6 @@ static IIO_DEVICE_ATTR(multichip_sync, S_IRUGO | S_IWUSR, ad9081_phy_store, AD9081_MCS); -static IIO_DEVICE_ATTR(out_voltage_main_ffh_frequency, S_IRUGO | S_IWUSR, - ad9081_phy_show, - ad9081_phy_store, - AD9081_DAC_FFH_FREQ_SET); - -static IIO_DEVICE_ATTR(out_voltage_main_ffh_index, S_IRUGO | S_IWUSR, - ad9081_phy_show, - ad9081_phy_store, - AD9081_DAC_FFH_INDEX_SET); - -static IIO_DEVICE_ATTR(out_voltage_main_ffh_mode, S_IRUGO | S_IWUSR, - ad9081_phy_show, - ad9081_phy_store, - AD9081_DAC_FFH_MODE_SET); - -static IIO_CONST_ATTR(out_voltage_main_ffh_mode_available, - "phase_continuous phase_incontinuous phase_coherent"); - static IIO_DEVICE_ATTR(jesd204_fsm_error, 0444, ad9081_phy_show, NULL, @@ -2691,10 +2882,6 @@ static struct attribute *ad9081_phy_attributes[] = { &iio_const_attr_loopback_mode_available.dev_attr.attr, &iio_dev_attr_adc_clk_powerdown.dev_attr.attr, &iio_dev_attr_multichip_sync.dev_attr.attr, - &iio_dev_attr_out_voltage_main_ffh_frequency.dev_attr.attr, - &iio_dev_attr_out_voltage_main_ffh_index.dev_attr.attr, - &iio_dev_attr_out_voltage_main_ffh_mode.dev_attr.attr, - &iio_const_attr_out_voltage_main_ffh_mode_available.dev_attr.attr, &iio_dev_attr_jesd204_fsm_error.dev_attr.attr, &iio_dev_attr_jesd204_fsm_state.dev_attr.attr, &iio_dev_attr_jesd204_fsm_paused.dev_attr.attr, @@ -3709,6 +3896,9 @@ static int ad9081_parse_dt_tx(struct ad9081_phy *phy, struct device_node *np) of_property_read_u64(of_trx_path, "adi,dac-frequency-hz", &phy->dac_frequency_hz); + phy->tx_ffh_hopf_via_gpio_en = + of_property_read_bool(of_trx_path, "adi,ffh-hopf-via-gpio-enable"); + /* The 4 DAC Main Datapaths */ of_channels = of_get_child_by_name(of_trx_path, "adi,main-data-paths"); @@ -3843,6 +4033,11 @@ static int ad9081_parse_dt_rx(struct ad9081_phy *phy, struct device_node *np) of_property_read_u32(of_trx_path, "adi,nyquist-zone", &nz); + of_property_read_variable_u8_array(of_trx_path, + "adi,ffh-gpio-mux-sel", phy->rx_ffh_gpio_mux_sel, + ARRAY_SIZE(phy->rx_ffh_gpio_mux_sel), + ARRAY_SIZE(phy->rx_ffh_gpio_mux_sel)); + /* The 4 DAC Main Datapaths */ of_channels = of_get_child_by_name(of_trx_path, "adi,main-data-paths"); @@ -3856,7 +4051,10 @@ static int ad9081_parse_dt_rx(struct ad9081_phy *phy, struct device_node *np) if (!ret && (reg < ARRAY_SIZE(phy->tx_main_shift))) { of_property_read_u64(of_chan, "adi,nco-frequency-shift-hz", - &phy->rx_cddc_shift[reg]); + &phy->rx_cddc_shift[0][reg]); + of_property_read_u8(of_chan, + "adi,nco-channel-select-mode", + &phy->rx_cddc_nco_channel_select_mode[reg]); of_property_read_u32(of_chan, "adi,decimation", &phy->adc_main_decimation[reg]); phy->rx_cddc_c2r[reg] = of_property_read_bool( @@ -4355,6 +4553,10 @@ static int ad9081_jesd204_link_running(struct jesd204_dev *jdev, phy->is_initialized = true; + /* Need to redo this since GPIOx might have been clobbered by master/slave sync */ + adi_ad9081_dac_duc_main_nco_hopf_gpio_as_hop_en_set(&phy->ad9081, + phy->tx_ffh_hopf_via_gpio_en); + return JESD204_STATE_CHANGE_DONE; } From ec52962d8ef35571d3d159180fe0d58900272344 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 28 Mar 2022 12:06:08 +0200 Subject: [PATCH 263/407] dt-bindings: adi,ad9081.h: Add FFH GPIO defines This adds defines for configuring GPIO controlled fast frequency hopping. Signed-off-by: Michael Hennerich --- include/dt-bindings/iio/adc/adi,ad9081.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/dt-bindings/iio/adc/adi,ad9081.h b/include/dt-bindings/iio/adc/adi,ad9081.h index b5e78fb7c6d828..f54ecd9ed0512e 100644 --- a/include/dt-bindings/iio/adc/adi,ad9081.h +++ b/include/dt-bindings/iio/adc/adi,ad9081.h @@ -30,6 +30,27 @@ #define FDDC_I 0 #define FDDC_Q 1 +/* ffh: 2 - gpio6, 3 - gpio7, 4 - gpio8, 5 - gpio9, 6 - gpio10, 7 - syncinb1_p, 8 - syncinb1_n */ + +#define AD9081_PERI_SEL_GPIO6 2 +#define AD9081_PERI_SEL_GPIO7 3 +#define AD9081_PERI_SEL_GPIO8 4 +#define AD9081_PERI_SEL_GPIO9 5 +#define AD9081_PERI_SEL_GPIO10 6 +#define AD9081_PERI_SEL_SYNCINB1_P 7 +#define AD9081_PERI_SEL_SYNCINB1_N 8 + +#define AD9081_FFH_CHAN_SEL_REG_MODE 0 /* 0: Register Map control (Use ddc_nco_regmap_chan_sel) */ +#define AD9081_FFH_CHAN_SEL_1GPIO_MODE 1 /* 1: profile_pins[0] is used. Pin level control {3'b0, profile_pins[0]} */ +#define AD9081_FFH_CHAN_SEL_2GPIO_MODE 2 /* 2: profile_pins[1 :0] are used. Pin level control {2'b0, profile_pins[1:0]} */ +#define AD9081_FFH_CHAN_SEL_3GPIO_MODE 3 /* 3: profile_pins[2 :0] are used. Pin level control {1'b0, profile_pins[2:0]} */ +#define AD9081_FFH_CHAN_SEL_4GPIO_MODE 4 /* 4: profile_pins[3 :0] are used. Pin level control { profile_pins[3:0]} */ +#define AD9081_FFH_CHAN_SEL_GPIO0_EDGE_MODE 8 /* 8: profile_pins[0] Pin edge control- increment internal counter when rising edge of profile_pins[0] Pin. */ +#define AD9081_FFH_CHAN_SEL_GPIO1_EDGE_MODE 9 /* 9: profile_pins[1] Pin edge control- increment internal counter when rising edge of profile_pins[1] Pin. */ +#define AD9081_FFH_CHAN_SEL_GPIO2_EDGE_MODE 10 /* 10: profile_pins[2] Pin edge control- increment internal counter when rising edge of profile_pins[2] Pin. */ +#define AD9081_FFH_CHAN_SEL_GPIO3_EDGE_MODE 11 /* 11: profile_pins[3] Pin edge control- increment internal counter when rising edge of profile_pins[3] Pin. */ +#define AD9081_FFH_CHAN_SEL_FHT_EXP_MODE 12 /* 12: FHT expire based control - increment internal counter when FHT is expired. */ + /* * JESD204-FSM defines */ From c29263d395e7c6a704b51dde0a7403a851b78d50 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 28 Mar 2022 12:08:17 +0200 Subject: [PATCH 264/407] iio: adc: ad9081: Option to select the GPIO used for MS NCO sync This adds an option to select the GPIO used for master/slave NCO synchronization. Default to GPIO index 0. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 1b706c094eeac4..a856fa36d8cf6a 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -249,6 +249,7 @@ struct ad9081_phy { u32 ad9081_debugfs_entry_index; u8 direct_lb_map; u8 rx_ffh_gpio_mux_sel[6]; + u8 sync_ms_gpio_num; }; static int adi_ad9081_adc_nco_sync(adi_ad9081_device_t *device, @@ -333,7 +334,7 @@ static int ad9081_nco_sync(struct ad9081_phy *phy, bool master) return adi_ad9081_adc_nco_master_slave_sync(&phy->ad9081, master, 1, /* trigger_src */ - 0, /* gpio_index */ + phy->sync_ms_gpio_num, /* gpio_index */ phy->nco_sync_ms_extra_lmfc_num); } @@ -4179,6 +4180,9 @@ static int ad9081_parse_dt(struct ad9081_phy *phy, struct device *dev) of_property_read_u8(np, "adi,direct-loopback-mode-dac-adc-mapping", &phy->direct_lb_map); + of_property_read_u8(np, "adi,master-slave-sync-gpio-num", + &phy->sync_ms_gpio_num); + ret = ad9081_parse_dt_tx(phy, np); if (ret == -ENODEV && phy->dac_frequency_hz) { phy->tx_disable = true; From 328c4c7ae9fc54425ee45a91103e3342cdc4ffff Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 28 Mar 2022 12:11:58 +0200 Subject: [PATCH 265/407] arm64: dt: adi-ad9081-fmc-ebz: Prefer external reference if available This patch changes the default reference priority to accept a 10MHz external reference if available. Signed-off-by: Michael Hennerich --- arch/arm64/boot/dts/xilinx/adi-ad9081-fmc-ebz.dtsi | 2 ++ arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4.dts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/adi-ad9081-fmc-ebz.dtsi b/arch/arm64/boot/dts/xilinx/adi-ad9081-fmc-ebz.dtsi index 5f234fd57e561a..1be8ea3143fab4 100644 --- a/arch/arm64/boot/dts/xilinx/adi-ad9081-fmc-ebz.dtsi +++ b/arch/arm64/boot/dts/xilinx/adi-ad9081-fmc-ebz.dtsi @@ -40,6 +40,8 @@ //adi,vcxo-frequency = <122880000>; adi,pll1-clkin-frequencies = <100000000 10000000 0 0>; + adi,pll1-ref-prio-ctrl = <0xE1>; /* prefer CLKIN1 -> CLKIN0 -> CLKIN2 -> CLKIN3 */ + adi,pll1-ref-autorevert-enable; adi,vcxo-frequency = <100000000>; adi,pll1-loop-bandwidth-hz = <200>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4.dts index 13ec7b80bc9ef4..cb4d360c92126f 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4.dts @@ -45,6 +45,8 @@ //adi,vcxo-frequency = <122880000>; adi,pll1-clkin-frequencies = <100000000 10000000 0 0>; + adi,pll1-ref-prio-ctrl = <0xE1>; /* prefer CLKIN1 -> CLKIN0 -> CLKIN2 -> CLKIN3 */ + adi,pll1-ref-autorevert-enable; adi,vcxo-frequency = <100000000>; adi,pll1-loop-bandwidth-hz = <200>; From e132f4dfb47f7ff3caa92e01383e9b29bfaa2be6 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 28 Mar 2022 12:20:06 +0200 Subject: [PATCH 266/407] arm64: dt: zynqmp-zcu102-rev10-ad9081-m8-l4-ffh: FFH test support This adds devices and properties to test frequency hopping. Signed-off-by: Michael Hennerich --- .../zynqmp-zcu102-rev10-ad9081-m8-l4-ffh.dts | 118 ++++++++++++++++++ .../dts/xilinx/zynqmp-zcu102-rev10-ad9081.dts | 6 +- 2 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-ffh.dts diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-ffh.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-ffh.dts new file mode 100644 index 00000000000000..dd25913a5d5ba0 --- /dev/null +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-ffh.dts @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD9081-FMC-EBZ + * https://wiki.analog.com/resources/eval/user-guides/quadmxfe/quick-start + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2022 Analog Devices Inc. + */ + +#include "zynqmp-zcu102-rev10-ad9081-m8-l4.dts" + +/ { + ad9081_gpio_control@0 { + compatible = "adi,one-bit-adc-dac"; + #address-cells = <1>; + #size-cells = <0>; + + out-gpios = <&gpio 110 0>, <&gpio 111 0>, <&gpio 112 0>, + <&gpio 113 0>, <&gpio 114 0>, <&gpio 115 0>, + <&gpio 116 0>, <&gpio 117 0>, <&gpio 118 0>, + <&gpio 119 0>, <&gpio 120 0>, <&gpio 138 0>, + <&gpio 139 0>, <&gpio 140 0>, <&gpio 141 0>; + + label = "ad9081_gpio"; + + channel@0 { + reg = <0>; + label = "GPIO_0"; + }; + channel@1 { + reg = <1>; + label = "GPIO_1"; + }; + channel@2 { + reg = <2>; + label = "GPIO_2"; + }; + channel@3 { + reg = <3>; + label = "GPIO_3"; + }; + channel@4 { + reg = <4>; + label = "GPIO_4"; + }; + channel@5 { + reg = <5>; + label = "GPIO_5"; + }; + channel@6 { + reg = <6>; + label = "GPIO_6"; + }; + channel@7 { + reg = <7>; + label = "GPIO_7"; + }; + channel@8 { + reg = <8>; + label = "GPIO_8"; + }; + channel@9 { + reg = <9>; + label = "GPIO_9"; + }; + channel@10 { + reg = <10>; + label = "GPIO_10"; + }; + channel@11 { + reg = <11>; + label = "GPIO_SYNCIN1P"; + }; + channel@12 { + reg = <12>; + label = "GPIO_SYNCIN1N"; + }; + channel@13 { + reg = <13>; + label = "GPIO_SYNCOUT1P"; + }; + channel@14 { + reg = <14>; + label = "GPIO_SYNCOUT1N"; + }; + }; +}; + +&trx0_ad9081 { + adi,rx-adcs { + adi,ffh-gpio-mux-sel = /bits/ 8 < + AD9081_PERI_SEL_SYNCINB1_N + AD9081_PERI_SEL_SYNCINB1_P + AD9081_PERI_SEL_GPIO6 + AD9081_PERI_SEL_GPIO7 + AD9081_PERI_SEL_GPIO8 + AD9081_PERI_SEL_GPIO9>; + }; +}; + +&ad9081_adc0 { + adi,nco-channel-select-mode = /bits/ 8 ; +}; + +&ad9081_adc1 { + adi,nco-channel-select-mode = /bits/ 8 ; +}; + +&ad9081_adc2 { + adi,nco-channel-select-mode = /bits/ 8 ; +}; + +&ad9081_adc3 { + adi,nco-channel-select-mode = /bits/ 8 ; +}; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081.dts index f984e4cb773619..ab5f031ebc30e4 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081.dts @@ -212,7 +212,7 @@ // assign rxen[1] = gpio_o[57]; 135 // assign txen[0] = gpio_o[58]; 136 // assign txen[1] = gpio_o[59]; 137 -// assign dac_fifo_bypass = gpio_o[60]; + &trx0_ad9081 { reset-gpios = <&gpio 133 0>; @@ -222,7 +222,3 @@ tx2-enable-gpios = <&gpio 137 0>; tx1-enable-gpios = <&gpio 136 0>; }; - -&axi_ad9081_core_tx { - plddrbypass-gpios = <&gpio 138 0>; -}; From 70894fd1b0e07b4f419656bc0483d0b4a89d260d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 29 Mar 2022 13:01:26 +0200 Subject: [PATCH 267/407] iio: adc: ad9081: Support for AD9177, AD9207 & AD9209 chip variants This adds support for AD9177, AD9207 & AD9209 DAC/ADC only chip variants. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index a856fa36d8cf6a..5e4525f4df5329 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -41,6 +41,9 @@ #define CHIPID_AD9082 0x9082 #define CHIPID_AD9988 0x9988 #define CHIPID_AD9986 0x9986 +#define CHIPID_AD9177 0x9177 +#define CHIPID_AD9207 0x9207 +#define CHIPID_AD9209 0x9209 #define CHIPID_MASK 0xFFFF #define ID_DUAL BIT(31) @@ -4944,6 +4947,9 @@ static int ad9081_probe(struct spi_device *spi) case CHIPID_AD9082: case CHIPID_AD9988: case CHIPID_AD9986: + case CHIPID_AD9177: + case CHIPID_AD9207: + case CHIPID_AD9209: spi_id = spi_get_device_id(spi)->driver_data & CHIPID_MASK; if (conv->id != spi_id) @@ -5060,6 +5066,9 @@ static const struct spi_device_id ad9081_id[] = { { "ad9082", CHIPID_AD9082 }, { "ad9988", CHIPID_AD9988 }, { "ad9986", CHIPID_AD9986 }, + { "ad9177", CHIPID_AD9177 }, + { "ad9207", CHIPID_AD9207 }, + { "ad9209", CHIPID_AD9209 }, {} }; MODULE_DEVICE_TABLE(spi, ad9081_id); @@ -5069,6 +5078,9 @@ static const struct of_device_id ad9081_of_match[] = { { .compatible = "adi,ad9082" }, { .compatible = "adi,ad9988" }, { .compatible = "adi,ad9986" }, + { .compatible = "adi,ad9177" }, + { .compatible = "adi,ad9207" }, + { .compatible = "adi,ad9209" }, {}, }; MODULE_DEVICE_TABLE(of, ad9081_of_match); From ac068fc416516ae74699c11b9442cdcd2521e6d6 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 30 Mar 2022 08:45:42 +0200 Subject: [PATCH 268/407] configs: zynq_xcomm_adv7511_defconfig: Enable NFS support This harmonizes NFS support between zynq and zynqmp targets. Signed-off-by: Michael Hennerich --- arch/arm/configs/zynq_xcomm_adv7511_defconfig | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/zynq_xcomm_adv7511_defconfig b/arch/arm/configs/zynq_xcomm_adv7511_defconfig index b7b6657bdd5007..cb3be54f507d4c 100644 --- a/arch/arm/configs/zynq_xcomm_adv7511_defconfig +++ b/arch/arm/configs/zynq_xcomm_adv7511_defconfig @@ -238,7 +238,12 @@ CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y -# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y From cd6a84aca79e48b4767cb0216178f9d8b0abb2b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 28 Mar 2022 10:57:43 +0200 Subject: [PATCH 269/407] clk: clk-ad9545: make sure to remove the clk provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to make sure to remove ourselfes as clk providers on the unbind path. Fixes: e649163a47ae ("clk: ad9545: Add support") Signed-off-by: Nuno Sá --- drivers/clk/adi/clk-ad9545.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index 707aec057aaa03..057e86705d175e 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -2973,6 +2973,11 @@ static struct clk *ad9545_clk_src_twocell_get(struct of_phandle_args *clkspec, v return clks[clk_type][clk_address]; } +static void ad9545_clk_del_provider(void *of_node) +{ + of_clk_del_provider(of_node); +} + static int ad9545_setup(struct ad9545_state *st) { int ret; @@ -3028,6 +3033,11 @@ static int ad9545_setup(struct ad9545_state *st) if (ret < 0) return ret; + ret = devm_add_action_or_reset(st->dev, ad9545_clk_del_provider, + st->dev->of_node); + if (ret) + return ret; + ret = ad9545_calib_aplls(st); if (ret < 0) return ret; From e9b73e64813160639d662f3214481d398973742b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 28 Mar 2022 11:59:53 +0200 Subject: [PATCH 270/407] clk: clk-ad9545: fix 'adi,fast-acq-trigger-mode' reading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The profile node is only validated (reg property is present and valid for example) in the 'fwnode_for_each_available_child_node()' loop. Hence, we should only read 'adi,fast-acq-trigger-mode' inside the loop. Fixes: 93ef95d1b73b ("clk: ad9545: Add fast acq trigger mode to dt") Signed-off-by: Nuno Sá --- drivers/clk/adi/clk-ad9545.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index 057e86705d175e..bf44d15b010dc5 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -737,10 +737,6 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) st->pll_clks[addr].pll_used = true; st->pll_clks[addr].address = addr; - ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-trigger-mode", &val); - if (!ret) - st->pll_clks[addr].fast_acq_trigger_mode = val; - ret = fwnode_property_read_u32(child, "adi,pll-slew-rate-limit-ps", &val); if (!ret) st->pll_clks[addr].slew_rate_limit_ps = val; @@ -791,6 +787,11 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) st->pll_clks[addr].profiles[profile_addr].loop_bw_uhz = val; + ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-trigger-mode", + &val); + if (!ret) + st->pll_clks[addr].fast_acq_trigger_mode = val; + ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-excess-bw", &val); if (!ret) From 37efc90b50955dade7a557357c435e8cddbb55ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 28 Mar 2022 12:04:44 +0200 Subject: [PATCH 271/407] clk: clk-ad9545: don't use child node's to identify the 'pll-clk' node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The profile node is not documented as a mandatory property, which means that we could just completely ignore pll-clk. Note that this was actually fine before the commit 64af96d2ea6f ("clk: ad9545: add zero delay support"). After it, we can be wrongly ignoring zero delays properties just because a profile node is not present. This changes fixes this. Fixes: 64af96d2ea6f ("clk: ad9545: add zero delay support") Signed-off-by: Nuno Sá --- drivers/clk/adi/clk-ad9545.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index bf44d15b010dc5..9fa5ebc2240d78 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -723,8 +724,7 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) prop_found = false; fwnode_for_each_available_child_node(fwnode, child) { - profile_node = fwnode_get_next_available_child_node(child, NULL); - if (!profile_node) + if (strncmp(fwnode_get_name(child), "pll-clk", strlen("pll-clk"))) continue; ret = fwnode_property_read_u32(child, "reg", &addr); From 9ba46c7f02e90bc26263cd850e4172699e4675bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 28 Mar 2022 13:00:11 +0200 Subject: [PATCH 272/407] clk: clk-ad9545: properly release fwnode handles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to call 'fwnode_handle_put()' after we are done with the fwnode handle or on error paths of 'fwnode_for_each_available_child_node()' loops. Fixes: e649163a47ae ("clk: ad9545: Add support") Signed-off-by: Nuno Sá --- drivers/clk/adi/clk-ad9545.c | 145 ++++++++++++++++++++++------------- 1 file changed, 91 insertions(+), 54 deletions(-) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index 9fa5ebc2240d78..7037fd537f1fa4 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -583,7 +583,7 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) bool prop_found; int ref_ind; u32 val; - int ret; + int ret = 0; int i; fwnode = dev_fwnode(st->dev); @@ -596,11 +596,13 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "reg", &ref_ind); if (ret < 0) { dev_err(st->dev, "reg not specified in ref node."); - return ret; + goto out_fail; } - if (ref_ind > 3) - return -EINVAL; + if (ref_ind > 3) { + ret = -EINVAL; + goto out_fail; + } st->ref_in_clks[ref_ind].ref_used = true; st->ref_in_clks[ref_ind].address = ref_ind; @@ -611,14 +613,14 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) st->ref_in_clks[ref_ind].mode = AD9545_SINGLE_ENDED; ret = fwnode_property_read_u32(child, "adi,single-ended-mode", &val); if (ret < 0) - return ret; + goto out_fail; st->ref_in_clks[ref_ind].s_conf = val; } else { st->ref_in_clks[ref_ind].mode = AD9545_DIFFERENTIAL; ret = fwnode_property_read_u32(child, "adi,differential-mode", &val); if (ret < 0) - return ret; + goto out_fail; st->ref_in_clks[ref_ind].d_conf = val; } @@ -626,7 +628,7 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "adi,r-divider-ratio", &val); if (ret < 0) { dev_err(st->dev, "No r-divider-ratio specified for ref: %d", ref_ind); - return ret; + goto out_fail; } st->ref_in_clks[ref_ind].r_div_ratio = val; @@ -634,7 +636,7 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "adi,ref-dtol-pbb", &val); if (ret < 0) { dev_err(st->dev, "No ref-dtol-pbb specified for ref: %d", ref_ind); - return ret; + goto out_fail; } st->ref_in_clks[ref_ind].d_tol_ppb = val; @@ -643,7 +645,7 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) if (ret < 0) { dev_err(st->dev, "No ref-monitor-hysteresis-pbb specified for ref: %d", ref_ind); - return ret; + goto out_fail; } for (i = 0; i < ARRAY_SIZE(ad9545_hyst_scales_bp); i++) { @@ -653,14 +655,16 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) } } - if (i == ARRAY_SIZE(ad9545_hyst_scales_bp)) - return -EINVAL; + if (i == ARRAY_SIZE(ad9545_hyst_scales_bp)) { + ret = -EINVAL; + goto out_fail; + } ret = fwnode_property_read_u32(child, "adi,ref-validation-timer-ms", &val); if (ret < 0) { dev_err(st->dev, "No ref-validation-timer-ms specified for ref: %d", ref_ind); - return ret; + goto out_fail; } st->ref_in_clks[ref_ind].valid_t_ms = val; @@ -669,7 +673,7 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) if (ret < 0) { dev_err(st->dev, "No freq-lock-threshold-ps specified for ref: %d", ref_ind); - return ret; + goto out_fail; } st->ref_in_clks[ref_ind].freq_thresh_ps = val; @@ -678,7 +682,7 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) if (ret < 0) { dev_err(st->dev, "No phase-lock-threshold-ps specified for ref: %d", ref_ind); - return ret; + goto out_fail; } st->ref_in_clks[ref_ind].phase_thresh_ps = val; @@ -700,13 +704,18 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) st->ref_in_clks[ref_ind].freq_lock_drain_rate = val; clk = devm_clk_get(st->dev, ad9545_ref_clk_names[ref_ind]); - if (IS_ERR(clk)) - return PTR_ERR(clk); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto out_fail; + } st->ref_in_clks[ref_ind].parent_clk = clk; + ret = 0; } - return 0; +out_fail: + fwnode_handle_put(child); + return ret; } static int ad9545_parse_dt_plls(struct ad9545_state *st) @@ -718,7 +727,7 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) bool prop_found; u32 val; u32 addr; - int ret; + int ret = 0; fwnode = dev_fwnode(st->dev); @@ -729,10 +738,12 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "reg", &addr); if (ret < 0) - return ret; + goto out_fail_child; - if (addr > 1) - return -EINVAL; + if (addr > 1) { + ret = -EINVAL; + goto out_fail_child; + } st->pll_clks[addr].pll_used = true; st->pll_clks[addr].address = addr; @@ -748,7 +759,8 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) if (prop_found && !ret) { if (val >= ARRAY_SIZE(ad9545_out_clk_names)) { dev_err(st->dev, "Invalid zero-delay fb path: %u.", val); - return -EINVAL; + ret = -EINVAL; + goto out_fail_child; } st->pll_clks[addr].internal_zero_delay_source = val; @@ -758,7 +770,8 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) if (prop_found && !ret) { if (val >= AD9545_MAX_ZERO_DELAY_RATE) { dev_err(st->dev, "Invalid zero-delay output rate: %u.", val); - return -EINVAL; + ret = -EINVAL; + goto out_fail_child; } st->pll_clks[addr].internal_zero_delay_source_rate_hz = val; @@ -769,11 +782,13 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) ret = fwnode_property_read_u32(profile_node, "reg", &profile_addr); if (ret < 0) { dev_err(st->dev, "Could not read Profile reg property."); - return ret; + goto out_fail_profile; } - if (profile_addr >= AD9545_MAX_DPLL_PROFILES) - return -EINVAL; + if (profile_addr >= AD9545_MAX_DPLL_PROFILES) { + ret = -EINVAL; + goto out_fail_profile; + } st->pll_clks[addr].profiles[profile_addr].en = true; st->pll_clks[addr].profiles[profile_addr].address = profile_addr; @@ -782,7 +797,7 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) if (ret < 0) { dev_err(st->dev, "Could not read Profile %d, pll-loop-bandwidth.", profile_addr); - return ret; + goto out_fail_profile; } st->pll_clks[addr].profiles[profile_addr].loop_bw_uhz = val; @@ -815,18 +830,24 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) if (ret < 0) { dev_err(st->dev, "Could not read Profile %d, pll-loop-bandwidth.", profile_addr); - return ret; + goto out_fail_profile; } - if (val > 5) - return -EINVAL; + if (val > 5) { + ret = -EINVAL; + goto out_fail_profile; + } st->pll_clks[addr].profiles[profile_addr].tdc_source = val; } } - return 0; +out_fail_profile: + fwnode_handle_put(profile_node); +out_fail_child: + fwnode_handle_put(child); + return ret; } static int ad9545_parse_dt_outputs(struct ad9545_state *st) @@ -836,7 +857,7 @@ static int ad9545_parse_dt_outputs(struct ad9545_state *st) bool prop_found; int out_ind; u32 val; - int ret; + int ret = 0; fwnode = dev_fwnode(st->dev); @@ -848,11 +869,13 @@ static int ad9545_parse_dt_outputs(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "reg", &out_ind); if (ret < 0) { dev_err(st->dev, "No reg specified for output."); - return ret; + goto out_fail; } - if (out_ind > 9) - return -EINVAL; + if (out_ind > 9) { + ret = -EINVAL; + goto out_fail; + } st->out_clks[out_ind].output_used = true; st->out_clks[out_ind].address = out_ind; @@ -864,7 +887,7 @@ static int ad9545_parse_dt_outputs(struct ad9545_state *st) if (ret < 0) { dev_err(st->dev, "No current-source-microamp specified for output: %d", out_ind); - return ret; + goto out_fail; } st->out_clks[out_ind].source_ua = val; @@ -872,13 +895,15 @@ static int ad9545_parse_dt_outputs(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "adi,output-mode", &val); if (ret < 0) { dev_err(st->dev, "No output-mode specified for output: %d", out_ind); - return ret; + goto out_fail; } st->out_clks[out_ind].output_mode = val; } - return 0; +out_fail: + fwnode_handle_put(child); + return ret; } static int ad9545_parse_dt_ncos(struct ad9545_state *st) @@ -888,7 +913,7 @@ static int ad9545_parse_dt_ncos(struct ad9545_state *st) bool prop_found; u32 val; u32 addr; - int ret; + int ret = 0; fwnode = dev_fwnode(st->dev); @@ -901,11 +926,13 @@ static int ad9545_parse_dt_ncos(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "reg", &addr); if (ret < 0) { dev_err(st->dev, "No reg specified for aux. NCO."); - return ret; + goto out_fail; } - if (addr > 1) - return -EINVAL; + if (addr > 1) { + ret = -EINVAL; + goto out_fail; + } st->aux_nco_clks[addr].nco_used = true; st->aux_nco_clks[addr].address = addr; @@ -915,7 +942,7 @@ static int ad9545_parse_dt_ncos(struct ad9545_state *st) if (ret < 0) { dev_err(st->dev, "No freq-lock-threshold-ps specified for aux. NCO: %d", addr); - return ret; + goto out_fail; } st->aux_nco_clks[addr].freq_thresh_ps = val; @@ -924,13 +951,15 @@ static int ad9545_parse_dt_ncos(struct ad9545_state *st) if (ret < 0) { dev_err(st->dev, "No phase-lock-threshold-ps specified for aux. NCO: %d", addr); - return ret; + goto out_fail; } st->aux_nco_clks[addr].phase_thresh_ps = val; } - return 0; +out_fail: + fwnode_handle_put(child); + return ret; } static int ad9545_parse_dt_tdcs(struct ad9545_state *st) @@ -939,7 +968,7 @@ static int ad9545_parse_dt_tdcs(struct ad9545_state *st) struct fwnode_handle *child; u32 val; u32 addr; - int ret; + int ret = 0; fwnode = dev_fwnode(st->dev); fwnode_for_each_available_child_node(fwnode, child) { @@ -949,12 +978,13 @@ static int ad9545_parse_dt_tdcs(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "reg", &addr); if (ret < 0) { dev_err(st->dev, "No reg specified for aux. TDC."); - return ret; + goto out_fail; } if (addr > 1) { dev_err(st->dev, "Invalid address: %u for aux. TDC.", addr); - return -EINVAL; + ret = -EINVAL; + goto out_fail; } st->aux_tdc_clks[addr].tdc_used = true; @@ -964,18 +994,21 @@ static int ad9545_parse_dt_tdcs(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "adi,pin-nr", &val); if (ret < 0) { dev_err(st->dev, "No source pin specified for aux. TDC: %d", addr); - return ret; + goto out_fail; } if (val >= ARRAY_SIZE(ad9545_ref_m_clk_names)) { dev_err(st->dev, "Invalid Mx pin-nr: %d", val); - return -EINVAL; + ret = -EINVAL; + goto out_fail; } st->aux_tdc_clks[addr].pin_nr = val; } - return 0; +out_fail: + fwnode_handle_put(child); + return ret; } static int ad9545_parse_dt_aux_dpll(struct ad9545_state *st) @@ -996,7 +1029,7 @@ static int ad9545_parse_dt_aux_dpll(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "adi,compensation-source", &val); if (ret < 0) { dev_err(st->dev, "No TDC source specified for aux. DPLL."); - return ret; + goto out_fail; } st->aux_dpll_clk.source = val; @@ -1004,7 +1037,7 @@ static int ad9545_parse_dt_aux_dpll(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "adi,aux-dpll-bw-mhz", &val); if (ret < 0) { dev_err(st->dev, "No loop bw specified for aux. DPLL."); - return ret; + goto out_fail; } st->aux_dpll_clk.loop_bw_mhz = val; @@ -1012,8 +1045,12 @@ static int ad9545_parse_dt_aux_dpll(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "adi,rate-change-limit", &val); if (!ret) st->aux_dpll_clk.rate_change_limit = val; + else + ret = 0; - return 0; +out_fail: + fwnode_handle_put(child); + return ret; } static int ad9545_parse_dt(struct ad9545_state *st) From 69eb47a26e7f728a5c052687380993cd9a0dd643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 28 Mar 2022 13:29:19 +0200 Subject: [PATCH 273/407] clk: clk-conf: properly release of nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to call 'of_node_put()' when we are done with the node or on error paths. Otherwise this can leak memory in DYNAMIC_OF setups. Fixes: 86be408bfbd8 ("clk: Support for clock parents and rates assigned from device tree") Signed-off-by: Nuno Sá --- drivers/clk/clk-conf.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c index a44ef7cfb13ef8..af151ce38772d3 100644 --- a/drivers/clk/clk-conf.c +++ b/drivers/clk/clk-conf.c @@ -33,9 +33,12 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) else return rc; } - if (clkspec.np == node && !clk_supplier) + if (clkspec.np == node && !clk_supplier) { + of_node_put(clkspec.np); return 0; + } pclk = of_clk_get_from_provider(&clkspec); + of_node_put(clkspec.np); if (IS_ERR(pclk)) { if (PTR_ERR(pclk) != -EPROBE_DEFER) pr_warn("clk: couldn't get parent clock %d for %pOF\n", @@ -49,7 +52,7 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) goto err; if (clkspec.np == node && !clk_supplier) { rc = 0; - goto err; + goto err_of_put; } clk = of_clk_get_from_provider(&clkspec); if (IS_ERR(clk)) { @@ -57,7 +60,7 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) pr_warn("clk: couldn't get assigned clock %d for %pOF\n", index, node); rc = PTR_ERR(clk); - goto err; + goto err_of_put; } rc = clk_set_parent(clk, pclk); @@ -66,8 +69,11 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) __clk_get_name(clk), __clk_get_name(pclk), rc); clk_put(clk); clk_put(pclk); + of_node_put(clkspec.np); } return 0; +err_of_put: + of_node_put(clkspec.np); err: clk_put(pclk); return rc; @@ -93,14 +99,17 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) else return rc; } - if (clkspec.np == node && !clk_supplier) + if (clkspec.np == node && !clk_supplier) { + of_node_put(clkspec.np); return 0; + } clk = of_clk_get_from_provider(&clkspec); if (IS_ERR(clk)) { if (PTR_ERR(clk) != -EPROBE_DEFER) pr_warn("clk: couldn't get clock %d for %pOF\n", index, node); + of_node_put(clkspec.np); return PTR_ERR(clk); } @@ -110,6 +119,7 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) __clk_get_name(clk), rate, rc, clk_get_rate(clk)); clk_put(clk); + of_node_put(clkspec.np); } index++; } From e6f48d8b6f535a591acb0b724a3a38a7d9ec5345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 28 Mar 2022 13:37:23 +0200 Subject: [PATCH 274/407] jesd204: core: fix dts overlay handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When handling the notifications sent by dts overlays, the code was calling 'of_find_node_with_property()' to look for jesd204 devices. The typical way to call this is: ``` for (dn = of_find_node_with_property(NULL, prop_name); dn; \ dn = of_find_node_with_property(dn, prop_name)) ``` So when we are done with the loop, all nodes are properly handled (i.e: of_node_put() was called). The problem here is that we first call 'of_find_node_with_property()' with a non NULL 'from' and so 'of_node_put()' will be wrongly called on it (since that node is not something we really hold a reference for) leading to the following dump when releasing a dt overlay: [ 8590.192388] OF: ERROR: Bad of_node_put() on /fragment@0/__overlay__ [ 8590.192410] CPU: 0 PID: 1352 Comm: dtoverlay Tainted: G WC 5.10.63-v7l+ #3 [ 8590.192420] Hardware name: BCM2711 [ 8590.192429] Backtrace: [ 8590.192468] [] (dump_backtrace) from [] (show_stack+0x20/0x24) [ 8590.192483] r7:ffffffff r6:00000000 r5:60000013 r4:c1ee76fc [ 8590.192501] [] (show_stack) from [] (dump_stack+0xc4/0xf0) [ 8590.192519] [] (dump_stack) from [] (of_node_release+0x120/0x124) [ 8590.192533] r9:c49b1100 r8:c4fe3020 r7:c5fb0190 r6:c5fb01bc r5:00000000 r4:c5fb01bc [ 8590.192553] [] (of_node_release) from [] (kobject_put+0xb8/0xf8) [ 8590.192565] r7:00000000 r6:c1f30748 r5:00000000 r4:c5fb01bc [ 8590.192580] [] (kobject_put) from [] (of_node_put+0x24/0x28) [ 8590.192592] r7:c1f3097c r6:c4fe3000 r5:c4fe3000 r4:00000001 [ 8590.192609] [] (of_node_put) from [] (free_overlay_changeset+0x68/0xa8) [ 8590.192626] [] (free_overlay_changeset) from [] (of_overlay_remove+0x1b8/0x2b8) ... This change fixes it by refactoring the way we detect jesd204 devices. Note that with this, the following dts overlay example won't work: ``` __overlay__ { node1 { node2 { jesd204_device; }; }; }; ``` For now this should not be a problem as we don't really have jesd devices defined in child nodes of a device. Fixes: b61aebb5a54a ("jesd204: jesd204-core: Support for dynamic dt changes") Signed-off-by: Nuno Sá --- drivers/jesd204/jesd204-core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/jesd204/jesd204-core.c b/drivers/jesd204/jesd204-core.c index 306c66f3b750f6..4eca440d885b17 100644 --- a/drivers/jesd204/jesd204-core.c +++ b/drivers/jesd204/jesd204-core.c @@ -1082,9 +1082,10 @@ static int jesd204_overlay_has_device(struct device_node *node) struct device_node *dn; int i = 0; - for (dn = of_find_node_with_property(node, "jesd204-device"); dn; - dn = of_find_node_with_property(dn, "jesd204-device")) - i++; + for_each_available_child_of_node(node, dn) { + if (of_property_read_bool(dn, "jesd204-device")) + i++; + } return i; } From de88d0ebdb51954a6f9ca105a0da8c2cf36d9a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 28 Mar 2022 10:51:06 +0200 Subject: [PATCH 275/407] iio: hmc7044: add error checking for 'devm_add_action_or_reset()' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure that 'devm_add_action_or_reset()' actually succeeds. Signed-off-by: Nuno Sá --- drivers/iio/frequency/hmc7044.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/frequency/hmc7044.c b/drivers/iio/frequency/hmc7044.c index 88a458d24dc487..fb1c9e5ecaf6f3 100644 --- a/drivers/iio/frequency/hmc7044.c +++ b/drivers/iio/frequency/hmc7044.c @@ -1774,8 +1774,9 @@ static int hmc7044_get_clks(struct device *dev, hmc->clkin_freq_ccf[i] = clk_get_rate(clk); - devm_add_action_or_reset(dev, - hmc7044_clk_disable_unprepare, clk); + ret = devm_add_action_or_reset(dev, hmc7044_clk_disable_unprepare, clk); + if (ret) + return ret; hmc->clk_input[i] = clk; } From 17d69f6045fd74bddc173c886779157e055edd26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 28 Mar 2022 14:17:01 +0200 Subject: [PATCH 276/407] clk: clk-ad9545: handle first optional dt properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no functional changes with this. The only advantage in first handling optional properties is that we do not need to reset 'ret = 0' to not carry the error code of a non found optional property. Note that this rearrangement was only done in the APIs doing the extra 'ret' reset. Signed-off-by: Nuno Sá --- drivers/clk/adi/clk-ad9545.c | 43 +++++++++++++++++------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index 7037fd537f1fa4..c4773f6e616149 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -608,6 +608,22 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) st->ref_in_clks[ref_ind].address = ref_ind; st->ref_in_clks[ref_ind].st = st; + ret = fwnode_property_read_u32(child, "adi,phase-lock-fill-rate", &val); + if (!ret) + st->ref_in_clks[ref_ind].phase_lock_fill_rate = val; + + ret = fwnode_property_read_u32(child, "adi,phase-lock-drain-rate", &val); + if (!ret) + st->ref_in_clks[ref_ind].phase_lock_drain_rate = val; + + ret = fwnode_property_read_u32(child, "adi,freq-lock-fill-rate", &val); + if (!ret) + st->ref_in_clks[ref_ind].freq_lock_fill_rate = val; + + ret = fwnode_property_read_u32(child, "adi,freq-lock-drain-rate", &val); + if (!ret) + st->ref_in_clks[ref_ind].freq_lock_drain_rate = val; + prop_found = fwnode_property_present(child, "adi,single-ended-mode"); if (prop_found) { st->ref_in_clks[ref_ind].mode = AD9545_SINGLE_ENDED; @@ -687,22 +703,6 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) st->ref_in_clks[ref_ind].phase_thresh_ps = val; - ret = fwnode_property_read_u32(child, "adi,phase-lock-fill-rate", &val); - if (!ret) - st->ref_in_clks[ref_ind].phase_lock_fill_rate = val; - - ret = fwnode_property_read_u32(child, "adi,phase-lock-drain-rate", &val); - if (!ret) - st->ref_in_clks[ref_ind].phase_lock_drain_rate = val; - - ret = fwnode_property_read_u32(child, "adi,freq-lock-fill-rate", &val); - if (!ret) - st->ref_in_clks[ref_ind].freq_lock_fill_rate = val; - - ret = fwnode_property_read_u32(child, "adi,freq-lock-drain-rate", &val); - if (!ret) - st->ref_in_clks[ref_ind].freq_lock_drain_rate = val; - clk = devm_clk_get(st->dev, ad9545_ref_clk_names[ref_ind]); if (IS_ERR(clk)) { ret = PTR_ERR(clk); @@ -710,7 +710,6 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) } st->ref_in_clks[ref_ind].parent_clk = clk; - ret = 0; } out_fail: @@ -1026,6 +1025,10 @@ static int ad9545_parse_dt_aux_dpll(struct ad9545_state *st) st->aux_dpll_clk.dpll_used = true; st->aux_dpll_clk.st = st; + ret = fwnode_property_read_u32(child, "adi,rate-change-limit", &val); + if (!ret) + st->aux_dpll_clk.rate_change_limit = val; + ret = fwnode_property_read_u32(child, "adi,compensation-source", &val); if (ret < 0) { dev_err(st->dev, "No TDC source specified for aux. DPLL."); @@ -1042,12 +1045,6 @@ static int ad9545_parse_dt_aux_dpll(struct ad9545_state *st) st->aux_dpll_clk.loop_bw_mhz = val; - ret = fwnode_property_read_u32(child, "adi,rate-change-limit", &val); - if (!ret) - st->aux_dpll_clk.rate_change_limit = val; - else - ret = 0; - out_fail: fwnode_handle_put(child); return ret; From 15e01ce03ba6ad0d4665f30c96507969b38d3ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 28 Mar 2022 14:31:51 +0200 Subject: [PATCH 277/407] clk: clk-ad9545: get dpll profile properties in separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As 'ad9545_parse_dt_pll_profiles()' was already fairly big, spitting it seems like a good idea. Moreover, this will make the error path cleaner and easier to understand (and get right). No functional changes... Signed-off-by: Nuno Sá --- drivers/clk/adi/clk-ad9545.c | 156 +++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 73 deletions(-) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index c4773f6e616149..7467347edf0667 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -717,12 +717,85 @@ static int ad9545_parse_dt_inputs(struct ad9545_state *st) return ret; } -static int ad9545_parse_dt_plls(struct ad9545_state *st) +static int ad9545_parse_dt_pll_profiles(struct ad9545_state *st, const struct fwnode_handle *child, + u32 addr) { struct fwnode_handle *profile_node; + int ret = 0; + + /* parse DPLL profiles */ + fwnode_for_each_available_child_node(child, profile_node) { + u32 profile_addr; + u32 val; + + ret = fwnode_property_read_u32(profile_node, "reg", &profile_addr); + if (ret < 0) { + dev_err(st->dev, "Could not read Profile reg property."); + goto out_fail; + } + + if (profile_addr >= AD9545_MAX_DPLL_PROFILES) { + ret = -EINVAL; + goto out_fail; + } + + st->pll_clks[addr].profiles[profile_addr].en = true; + st->pll_clks[addr].profiles[profile_addr].address = profile_addr; + + ret = fwnode_property_read_u32(profile_node, "adi,pll-loop-bandwidth-uhz", &val); + if (ret < 0) { + dev_err(st->dev, "Could not read Profile %d, pll-loop-bandwidth.", + profile_addr); + goto out_fail; + } + + st->pll_clks[addr].profiles[profile_addr].loop_bw_uhz = val; + + ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-trigger-mode", &val); + if (!ret) + st->pll_clks[addr].fast_acq_trigger_mode = val; + + ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-excess-bw", &val); + if (!ret) + st->pll_clks[addr].profiles[profile_addr].fast_acq_excess_bw = val; + + ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-timeout-ms", &val); + if (!ret) + st->pll_clks[addr].profiles[profile_addr].fast_acq_timeout_ms = val; + + ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-lock-settle-ms", + &val); + if (!ret) + st->pll_clks[addr].profiles[profile_addr].fast_acq_settle_ms = val; + + ret = fwnode_property_read_u32(profile_node, "adi,profile-priority", &val); + if (!ret) + st->pll_clks[addr].profiles[profile_addr].priority = val; + + ret = fwnode_property_read_u32(profile_node, "adi,pll-source", &val); + if (ret < 0) { + dev_err(st->dev, "Could not read Profile %d, pll-loop-bandwidth.", + profile_addr); + goto out_fail; + } + + if (val > 5) { + ret = -EINVAL; + goto out_fail; + } + + st->pll_clks[addr].profiles[profile_addr].tdc_source = val; + } + +out_fail: + fwnode_handle_put(profile_node); + return ret; +} + +static int ad9545_parse_dt_plls(struct ad9545_state *st) +{ struct fwnode_handle *fwnode; struct fwnode_handle *child; - u32 profile_addr; bool prop_found; u32 val; u32 addr; @@ -737,11 +810,11 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) ret = fwnode_property_read_u32(child, "reg", &addr); if (ret < 0) - goto out_fail_child; + goto out_fail; if (addr > 1) { ret = -EINVAL; - goto out_fail_child; + goto out_fail; } st->pll_clks[addr].pll_used = true; @@ -759,7 +832,7 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) if (val >= ARRAY_SIZE(ad9545_out_clk_names)) { dev_err(st->dev, "Invalid zero-delay fb path: %u.", val); ret = -EINVAL; - goto out_fail_child; + goto out_fail; } st->pll_clks[addr].internal_zero_delay_source = val; @@ -770,81 +843,18 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) if (val >= AD9545_MAX_ZERO_DELAY_RATE) { dev_err(st->dev, "Invalid zero-delay output rate: %u.", val); ret = -EINVAL; - goto out_fail_child; + goto out_fail; } st->pll_clks[addr].internal_zero_delay_source_rate_hz = val; } - /* parse DPLL profiles */ - fwnode_for_each_available_child_node(child, profile_node) { - ret = fwnode_property_read_u32(profile_node, "reg", &profile_addr); - if (ret < 0) { - dev_err(st->dev, "Could not read Profile reg property."); - goto out_fail_profile; - } - - if (profile_addr >= AD9545_MAX_DPLL_PROFILES) { - ret = -EINVAL; - goto out_fail_profile; - } - - st->pll_clks[addr].profiles[profile_addr].en = true; - st->pll_clks[addr].profiles[profile_addr].address = profile_addr; - - ret = fwnode_property_read_u32(profile_node, "adi,pll-loop-bandwidth-uhz", &val); - if (ret < 0) { - dev_err(st->dev, "Could not read Profile %d, pll-loop-bandwidth.", - profile_addr); - goto out_fail_profile; - } - - st->pll_clks[addr].profiles[profile_addr].loop_bw_uhz = val; - - ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-trigger-mode", - &val); - if (!ret) - st->pll_clks[addr].fast_acq_trigger_mode = val; - - ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-excess-bw", - &val); - if (!ret) - st->pll_clks[addr].profiles[profile_addr].fast_acq_excess_bw = val; - - ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-timeout-ms", - &val); - if (!ret) - st->pll_clks[addr].profiles[profile_addr].fast_acq_timeout_ms = val; - - ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-lock-settle-ms", - &val); - if (!ret) - st->pll_clks[addr].profiles[profile_addr].fast_acq_settle_ms = val; - - ret = fwnode_property_read_u32(profile_node, "adi,profile-priority", &val); - if (!ret) - st->pll_clks[addr].profiles[profile_addr].priority = val; - - ret = fwnode_property_read_u32(profile_node, "adi,pll-source", &val); - if (ret < 0) { - dev_err(st->dev, "Could not read Profile %d, pll-loop-bandwidth.", - profile_addr); - goto out_fail_profile; - } - - if (val > 5) { - ret = -EINVAL; - goto out_fail_profile; - } - - st->pll_clks[addr].profiles[profile_addr].tdc_source = val; - } - + ret = ad9545_parse_dt_pll_profiles(st, child, addr); + if (ret) + goto out_fail; } -out_fail_profile: - fwnode_handle_put(profile_node); -out_fail_child: +out_fail: fwnode_handle_put(child); return ret; } From 479d8ff19c7658c8437807792a585e67d6794e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 31 Mar 2022 13:49:59 +0200 Subject: [PATCH 278/407] clk: clk-ad9545: move to 'devm_of_clk_add_hw_provider()' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clk providers should not have to know or use clk consumers 'struct clk'. This change moves 'of_clk_add_provider()' to the clk_hw equivalent. Signed-off-by: Nuno Sá --- drivers/clk/adi/clk-ad9545.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index 7467347edf0667..1e8b0631fe63de 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -565,7 +565,7 @@ struct ad9545_state { struct ad9545_out_clk out_clks[ARRAY_SIZE(ad9545_out_clk_names)]; struct ad9545_aux_nco_clk aux_nco_clks[ARRAY_SIZE(ad9545_aux_nco_clk_names)]; struct ad9545_aux_tdc_clk aux_tdc_clks[ARRAY_SIZE(ad9545_aux_tdc_clk_names)]; - struct clk **clks[4]; + struct clk_hw **clks[4]; }; #define to_ref_in_clk(_hw) container_of(_hw, struct ad9545_ref_in_clk, hw) @@ -1702,7 +1702,7 @@ static int ad9545_outputs_setup(struct ad9545_state *st) if (ret < 0) return ret; - st->clks[AD9545_CLK_OUT][i] = st->out_clks[i].hw.clk; + st->clks[AD9545_CLK_OUT][i] = &st->out_clks[i].hw; } for (i = 0; i < ARRAY_SIZE(st->pll_clks); i++) { @@ -2596,7 +2596,7 @@ static int ad9545_plls_setup(struct ad9545_state *st) if (ret < 0) return ret; - st->clks[AD9545_CLK_PLL][i] = pll->hw.clk; + st->clks[AD9545_CLK_PLL][i] = &pll->hw; } return 0; @@ -2698,7 +2698,7 @@ static int ad9545_aux_ncos_setup(struct ad9545_state *st) if (ret < 0) return ret; - st->clks[AD9545_CLK_NCO][i] = nco->hw.clk; + st->clks[AD9545_CLK_NCO][i] = &nco->hw; } return 0; @@ -2810,7 +2810,7 @@ static int ad9545_aux_tdcs_setup(struct ad9545_state *st) if (ret < 0) return ret; - st->clks[AD9545_CLK_AUX_TDC][i] = tdc->hw.clk; + st->clks[AD9545_CLK_AUX_TDC][i] = &tdc->hw; } return 0; @@ -2997,11 +2997,11 @@ static int ad9545_calib_aplls(struct ad9545_state *st) return 0; } -static struct clk *ad9545_clk_src_twocell_get(struct of_phandle_args *clkspec, void *data) +static struct clk_hw *ad9545_clk_hw_twocell_get(struct of_phandle_args *clkspec, void *data) { unsigned int clk_address = clkspec->args[1]; unsigned int clk_type = clkspec->args[0]; - struct clk ***clks = data; + struct clk_hw ***clks = data; if (clk_type > AD9545_CLK_AUX_TDC) { pr_err("%s: invalid clock type %u\n", __func__, clk_type); @@ -3018,11 +3018,6 @@ static struct clk *ad9545_clk_src_twocell_get(struct of_phandle_args *clkspec, v return clks[clk_type][clk_address]; } -static void ad9545_clk_del_provider(void *of_node) -{ - of_clk_del_provider(of_node); -} - static int ad9545_setup(struct ad9545_state *st) { int ret; @@ -3073,16 +3068,11 @@ static int ad9545_setup(struct ad9545_state *st) if (ret < 0) return ret; - ret = of_clk_add_provider(st->dev->of_node, ad9545_clk_src_twocell_get, - &st->clks[AD9545_CLK_OUT]); + ret = devm_of_clk_add_hw_provider(st->dev, ad9545_clk_hw_twocell_get, + &st->clks[AD9545_CLK_OUT]); if (ret < 0) return ret; - ret = devm_add_action_or_reset(st->dev, ad9545_clk_del_provider, - st->dev->of_node); - if (ret) - return ret; - ret = ad9545_calib_aplls(st); if (ret < 0) return ret; From db2008b21c6baecdc23b8f52f0fcee088754260c Mon Sep 17 00:00:00 2001 From: Michael Bradley Date: Wed, 30 Mar 2022 11:31:46 -0700 Subject: [PATCH 279/407] arch: arm: dts: Add zedboard with otg enabled Creating a zedboard dt file with USB OtG enabled by default. This is for product evaluation use cases. Signed-off-by: Michael Bradley --- arch/arm/boot/dts/zynq-zed-otg.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 arch/arm/boot/dts/zynq-zed-otg.dts diff --git a/arch/arm/boot/dts/zynq-zed-otg.dts b/arch/arm/boot/dts/zynq-zed-otg.dts new file mode 100644 index 00000000000000..edc6cf7f67939b --- /dev/null +++ b/arch/arm/boot/dts/zynq-zed-otg.dts @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices ADV7511 + * https://www.analog.com/en/products/adv7511.html + * https://wiki.analog.com/resources/tools-software/linux-drivers/platforms/zynq + * https://wiki.analog.com/resources/fpga/xilinx/kc705/adv7511 + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2012-2019 Analog Devices Inc. + */ +/dts-v1/; + +#include "zynq-zed.dtsi" + +&usb0 { + dr_mode = "otg"; +}; From 9e81976def6c6a5a746e3cb925baf1fa7fbb0b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 14 Jan 2022 14:26:08 +0100 Subject: [PATCH 280/407] iio:imu:adis16480: fix buffering for devices with no burst mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The trigger handler defined in the driver assumes that burst mode is being used. Hence, for devices that do not support it, we have to use the adis library default trigger implementation. Tested-by: Julia Pineda Fixes: 941f130881fa9 ("iio: adis16480: support burst read function") Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20220114132608.241-1-nuno.sa@analog.com Cc: Signed-off-by: Jonathan Cameron (cherry picked from commit b0e85f95e30d4d2dc22ea123a30dba36406879a1) --- drivers/iio/imu/adis16480.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index b1a15e95586a25..50ce99b6fc4d7b 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -1470,6 +1470,7 @@ static int adis16480_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); const struct adis_data *adis16480_data; + irq_handler_t trigger_handler = NULL; struct iio_dev *indio_dev; struct adis16480 *st; int ret; @@ -1543,8 +1544,12 @@ static int adis16480_probe(struct spi_device *spi) st->clk_freq = st->chip_info->int_clk; } + /* Only use our trigger handler if burst mode is supported */ + if (adis16480_data->burst_len) + trigger_handler = adis16480_trigger_handler; + ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev, - adis16480_trigger_handler); + trigger_handler); if (ret) return ret; From a9f2b2b28d1454fd4983e4a6b144b3c200277adf Mon Sep 17 00:00:00 2001 From: Bjoern Kerler Date: Sun, 3 Apr 2022 12:02:23 +0200 Subject: [PATCH 281/407] Add antsdr patches --- arch/arm/boot/dts/zynq-ant-sdr-revb.dts | 50 +++ arch/arm/boot/dts/zynq-ant-sdr-revc.dts | 88 +++++ arch/arm/boot/dts/zynq-ant-sdr.dts | 53 +++ arch/arm/boot/dts/zynq-ant-sdr.dtsi | 448 ++++++++++++++++++++++++ arch/arm/boot/dts/zynq.dtsi | 2 + arch/arm/configs/zynq_ant_defconfig | 285 +++++++++++++++ drivers/iio/adc/ad9361.c | 102 +++++- drivers/iio/adc/ad9361_private.h | 8 + 8 files changed, 1019 insertions(+), 17 deletions(-) create mode 100644 arch/arm/boot/dts/zynq-ant-sdr-revb.dts create mode 100644 arch/arm/boot/dts/zynq-ant-sdr-revc.dts create mode 100644 arch/arm/boot/dts/zynq-ant-sdr.dts create mode 100644 arch/arm/boot/dts/zynq-ant-sdr.dtsi create mode 100644 arch/arm/configs/zynq_ant_defconfig diff --git a/arch/arm/boot/dts/zynq-ant-sdr-revb.dts b/arch/arm/boot/dts/zynq-ant-sdr-revb.dts new file mode 100644 index 00000000000000..8672218eccb648 --- /dev/null +++ b/arch/arm/boot/dts/zynq-ant-sdr-revb.dts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + + * hdl_project: + * board_revision: + * + * Copyright (C) 2016-2021 MicroPhase Inc. + */ +/dts-v1/; +#include "zynq-ant-sdr.dtsi" +#include +#include +#include + +// &axi_i2c0 { +// current_limiter@5a { +// compatible = "adi,adm1177"; +// reg = <0x5a>; +// adi,r-sense-mohm = <50>; /* 50 mOhm */ +// adi,shutdown-threshold-ma = <1059>; /* 1.059 A */ +// adi,vrange-high-enable; +// }; +// }; + +/ { + model = "Analog Devices PlutoSDR Rev.B (Z7010/AD9363)"; + + leds { + compatible = "gpio-leds"; + led0 { + label = "led0:green"; + gpios = <&gpio0 15 0>; + linux,default-trigger = "heartbeat"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button { + interrupt-parent = <&gpio0>; + interrupts = <14 IRQ_TYPE_EDGE_FALLING>; + label = "Button"; + linux,code = ; + }; + + }; +}; diff --git a/arch/arm/boot/dts/zynq-ant-sdr-revc.dts b/arch/arm/boot/dts/zynq-ant-sdr-revc.dts new file mode 100644 index 00000000000000..663eb03665521f --- /dev/null +++ b/arch/arm/boot/dts/zynq-ant-sdr-revc.dts @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * hdl_project: + * board_revision: + * + * Copyright (C) 2016-2019 MicroPhase Inc. + */ +/dts-v1/; +#include "zynq-ant-sdr.dtsi" +#include +#include +#include + +/* These GPIO hogs are configured by u-boot environment */ +&gpio0 { + clock_extern_en { + gpio-hog; + gpios = <48 0>; + output-high; + }; + + clock_internal_en { + gpio-hog; + gpios = <48 0>; + output-low; + }; +}; + +&amba { + axi_spi: axi_quad_spi@7C430000 { + #address-cells = <1>; + #size-cells = <0>; + bits-per-word = <8>; + compatible = "xlnx,xps-spi-2.00.a"; + fifo-size = <16>; + interrupt-parent = <&intc>; + interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>; + cs-gpios = <&gpio0 49 0>; + num-cs = <0x1>; + reg = <0x7C430000 0x10000>; + xlnx,num-ss-bits = <0x1>; + xlnx,spi-mode = <0>; + + spidev0: spidev@0 { + compatible = "adi,swspi"; + reg = <0>; /* CE0 */ + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <125000000>; + }; + }; +}; + +&adc0_ad9364 { + /* This property is controlled by u-boot environment. */ + adi,2rx-2tx-mode-enable; +}; + +&cf_ad9364_dac_core_0 { + /* This property is controlled by u-boot environment. */ + compatible = "adi,axi-ad9361-dds-6.00.a"; +}; + +/ { + model = "Analog Devices PlutoSDR Rev.C (Z7010/AD9363)"; + + leds { + compatible = "gpio-leds"; + led0 { + label = "led0:green"; + gpios = <&gpio0 15 0>; + linux,default-trigger = "heartbeat"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button { + interrupt-parent = <&gpio0>; + interrupts = <14 IRQ_TYPE_EDGE_FALLING>; + label = "Button"; + linux,code = ; + }; + }; +}; diff --git a/arch/arm/boot/dts/zynq-ant-sdr.dts b/arch/arm/boot/dts/zynq-ant-sdr.dts new file mode 100644 index 00000000000000..e4a140524acb2f --- /dev/null +++ b/arch/arm/boot/dts/zynq-ant-sdr.dts @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * + * hdl_project: + * board_revision: + * + * Copyright (C) 2016-2019 MicroPhase Inc. + */ +/dts-v1/; +#include "zynq-ant-sdr.dtsi" + + +// &axi_i2c0 { +// current_limiter@5a { +// compatible = "adi,adm1177"; +// reg = <0x5a>; +// adi,r-sense-mohm = <50>; /* 50 mOhm */ +// adi,shutdown-threshold-ma = <1059>; /* 1.059 A */ +// adi,vrange-high-enable; +// }; +// }; + + +&adc0_ad9364 { + /* This property is controlled by u-boot environment. */ + adi,2rx-2tx-mode-enable; +}; + +&cf_ad9364_dac_core_0 { + /* This property is controlled by u-boot environment. */ + compatible = "adi,axi-ad9361-dds-6.00.a"; +}; + + +/ { + model = "Analog Devices PlutoSDR Rev.C (Z7010/AD9363)"; + + leds { + compatible = "gpio-leds"; + led0 { + label = "led0:green"; + gpios = <&gpio0 15 0>; + linux,default-trigger = "heartbeat"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + autorepeat; + }; +}; diff --git a/arch/arm/boot/dts/zynq-ant-sdr.dtsi b/arch/arm/boot/dts/zynq-ant-sdr.dtsi new file mode 100644 index 00000000000000..4e2e6bca85b890 --- /dev/null +++ b/arch/arm/boot/dts/zynq-ant-sdr.dtsi @@ -0,0 +1,448 @@ +/* + * ZYNQ Pluto SDR (Z7020/AD936x) + * + * Copyright (C) 2021 MicroPhase Inc. + * + * Licensed under the GPL-2. + */ +#include "zynq.dtsi" + +#include + +/ { + model = "Analog Devices PlutoSDR Rev.A (Z7010/AD9363)"; + memory { + device_type = "memory"; + reg = <0x00000000 0x40000000>; + }; + + chosen { + stdout-path = "/amba@0/uart@E0001000"; + }; + + + clocks { + ad9364_clkin: clock@0 { + #clock-cells = <0>; + compatible = "adjustable-clock"; + clock-frequency = <40000000>; + clock-accuracy = <200000>; /* 200 ppm (ppb) */ + clock-output-names = "ad9364_ext_refclk"; + }; + }; + + usb_phy0: phy0 { + compatible = "ulpi-phy"; + #phy-cells = <0>; + reg = <0xe0002000 0x1000>; + view-port = <0x0170>; + drv-vbus; + }; + +}; + + +&sdhci0 { + status = "okay"; + xlnx,has-cd = <0x0>; + xlnx,has-power = <0x0>; + xlnx,has-wp = <0x0>; +}; + +&watchdog0 { + status = "okay"; + reset-on-timeout; +}; + +&gem0 { + status = "okay"; + phy-mode = "rgmii-id"; + phy-handle = <&phy0>; + + phy0: phy@0 { /* Marvell 88e1512 */ + reg = <0>; + compatible = "ethernet-phy-ieee802.3-c22"; + reset-gpios = <&gpio0 46 1>; + }; +}; + +&usb0 { + xlnx,phy-reset-gpio = <&gpio0 47 0>; + dr_mode = "otg"; + status = "okay"; + usb-phy = <&usb_phy0>; +}; + +&qspi { + status = "okay"; + is-dual = <0>; + num-cs = <1>; + primary_flash: ps7-qspi@0 { + #address-cells = <1>; + #size-cells = <1>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + compatible = "n25q256a", "n25q512a", "jedec,spi-nor"; /* same as S25FL256 */ + reg = <0x0>; + spi-max-frequency = <50000000>; + partition@qspi-fsbl-uboot { + label = "qspi-fsbl-uboot"; + reg = <0x0 0x100000>; /* 1M */ + }; + partition@qspi-uboot-env { + label = "qspi-uboot-env"; + reg = <0x100000 0x20000>; /* 128k */ + }; + partition@qspi-nvmfs { + label = "qspi-nvmfs"; + reg = <0x120000 0xE0000>; /* 1M */ + }; + partition@qspi-linux { + label = "qspi-linux"; + reg = <0x200000 0x1E00000>; /* 30M */ + }; + }; +}; + +&adc { + xlnx,channels { + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + }; + }; +}; + +/ { + fpga_axi: fpga-axi@0 { + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + + axi_i2c0: i2c@41600000 { + compatible = "xlnx,axi-iic-1.02.a", "xlnx,xps-iic-2.00.a"; + reg = <0x41600000 0x10000>; + interrupt-parent = <&intc>; + interrupts = <0 59 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 15>; + clock-names = "pclk"; + + #address-cells = <1>; + #size-cells = <0>; + + }; + + rx_dma: dma@7c400000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x7c400000 0x10000>; + #dma-cells = <1>; + interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 16>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <32>; + adi,source-bus-type = <2>; + adi,destination-bus-width = <64>; + adi,destination-bus-type = <0>; + }; + }; + }; + + tx_dma: dma@7c420000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x7c420000 0x10000>; + #dma-cells = <1>; + interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 16>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <64>; + adi,source-bus-type = <0>; + adi,destination-bus-width = <32>; + adi,destination-bus-type = <2>; + }; + }; + }; + + cf_ad9364_adc_core_0: cf-ad9361-lpc@79020000 { + compatible = "adi,axi-ad9361-6.00.a"; + reg = <0x79020000 0x6000>; + dmas = <&rx_dma 0>; + dma-names = "rx"; + spibus-connected = <&adc0_ad9364>; + adi,axi-decimation-core-available; + }; + + cf_ad9364_dac_core_0: cf-ad9361-dds-core-lpc@79024000 { + compatible = "adi,axi-ad9364-dds-6.00.a"; + reg = <0x79024000 0x1000>; + clocks = <&adc0_ad9364 13>; + clock-names = "sampl_clk"; + dmas = <&tx_dma 0>; + dma-names = "tx"; + adi,axi-interpolation-core-available; + adi,axi-dds-default-scale = <0>; + }; + + mwipcore@43c00000 { + compatible = "mathworks,mwipcore-axi4lite-v1.00"; + reg = <0x43c00000 0xffff>; + }; + }; +}; + +&spi0 { + status = "okay"; + + adc0_ad9364: ad9361-phy@0 { + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + compatible = "adi,ad9364"; + + /* SPI Setup */ + reg = <0>; + spi-cpha; + spi-max-frequency = <10000000>; + + /* Clocks */ + clocks = <&ad9364_clkin 0>; + clock-names = "ad9364_ext_refclk"; + clock-output-names = "rx_sampl_clk", "tx_sampl_clk"; + + /* Digital Interface Control */ + + /* adi,digital-interface-tune-skip-mode: + * 0 = TUNE RX&TX + * 1 = SKIP TX + * 2 = SKIP ALL + */ + //adi,digital-interface-tune-skip-mode = <0>; + + adi,pp-tx-swap-enable; + adi,pp-rx-swap-enable; + adi,rx-frame-pulse-mode-enable; + + adi,xo-disable-use-ext-refclk-enable; + + /* Enable CMOS Mode */ + adi,full-port-enable; + adi,digital-interface-tune-fir-disable; + + adi,digital-interface-tune-skip-mode = <0>; /* TUNE RX & TX */ + adi,tx-fb-clock-delay = <0>; + adi,tx-data-delay = <9>; + adi,swap-ports-enable; + + /* Mode Setup */ + + //adi,split-gain-table-mode-enable; + + /* ENSM Mode */ + adi,frequency-division-duplex-mode-enable; + //adi,ensm-enable-pin-pulse-mode-enable; + //adi,ensm-enable-txnrx-control-enable; + + + /* adi,rx-rf-port-input-select: + * 0 = (RX1A_N & RX1A_P) and (RX2A_N & RX2A_P) enabled; balanced + * 1 = (RX1B_N & RX1B_P) and (RX2B_N & RX2B_P) enabled; balanced + * 2 = (RX1C_N & RX1C_P) and (RX2C_N & RX2C_P) enabled; balanced + * + * 3 = RX1A_N and RX2A_N enabled; unbalanced + * 4 = RX1A_P and RX2A_P enabled; unbalanced + * 5 = RX1B_N and RX2B_N enabled; unbalanced + * 6 = RX1B_P and RX2B_P enabled; unbalanced + * 7 = RX1C_N and RX2C_N enabled; unbalanced + * 8 = RX1C_P and RX2C_P enabled; unbalanced + */ + + adi,rx-rf-port-input-select = <1>; /* (RX1A_N & RX1A_P) and (RX2A_N & RX2A_P) enabled; balanced */ + adi,rx-rf-port-input-select-lock-enable; + + /* adi,tx-rf-port-input-select: + * 0 TX1A, TX2A + * 1 TX1B, TX2B + */ + + adi,tx-rf-port-input-select = <0>; /* TX1A, TX2A */ + adi,tx-rf-port-input-select-lock-enable; + + //adi,update-tx-gain-in-alert-enable; + adi,tx-attenuation-mdB = <10000>; + adi,tx-lo-powerdown-managed-enable; + + adi,rf-rx-bandwidth-hz = <18000000>; + adi,rf-tx-bandwidth-hz = <18000000>; + adi,rx-synthesizer-frequency-hz = /bits/ 64 <2400000000>; + adi,tx-synthesizer-frequency-hz = /bits/ 64 <2450000000>; + + /* BBPLL ADC R2CLK R1CLK CLKRF RSAMPL */ + adi,rx-path-clock-frequencies = <983040000 245760000 122880000 61440000 30720000 30720000>; + /* BBPLL DAC T2CLK T1CLK CLKTF TSAMPL */ + adi,tx-path-clock-frequencies = <983040000 122880000 122880000 61440000 30720000 30720000>; + + /* Gain Control */ + + /* adi,gc-rx[1|2]-mode: + * 0 = RF_GAIN_MGC + * 1 = RF_GAIN_FASTATTACK_AGC + * 2 = RF_GAIN_SLOWATTACK_AGC + * 3 = RF_GAIN_HYBRID_AGC + */ + + adi,gc-rx1-mode = <2>; + adi,gc-rx2-mode = <2>; + adi,gc-adc-ovr-sample-size = <4>; /* sum 4 samples */ + adi,gc-adc-small-overload-thresh = <47>; /* sum of squares */ + adi,gc-adc-large-overload-thresh = <58>; /* sum of squares */ + adi,gc-lmt-overload-high-thresh = <800>; /* mV */ + adi,gc-lmt-overload-low-thresh = <704>; /* mV */ + adi,gc-dec-pow-measurement-duration = <8192>; /* 0..524288 Samples */ + adi,gc-low-power-thresh = <24>; /* 0..-64 dBFS vals are set pos */ + //adi,gc-dig-gain-enable; + //adi,gc-max-dig-gain = <15>; + + /* Manual Gain Control Setup */ + + //adi,mgc-rx1-ctrl-inp-enable; /* uncomment to use ctrl inputs */ + //adi,mgc-rx2-ctrl-inp-enable; /* uncomment to use ctrl inputs */ + adi,mgc-inc-gain-step = <2>; + adi,mgc-dec-gain-step = <2>; + + /* adi,mgc-split-table-ctrl-inp-gain-mode: + * (relevant if adi,split-gain-table-mode-enable is set) + * 0 = AGC determine this + * 1 = only in LPF + * 2 = only in LMT + */ + + adi,mgc-split-table-ctrl-inp-gain-mode = <0>; + + /* Automatic Gain Control Setup */ + + adi,agc-attack-delay-extra-margin-us= <1>; /* us */ + adi,agc-outer-thresh-high = <5>; /* -dBFS */ + adi,agc-outer-thresh-high-dec-steps = <2>; /* 0..15 */ + adi,agc-inner-thresh-high = <10>; /* -dBFS */ + adi,agc-inner-thresh-high-dec-steps = <1>; /* 0..7 */ + adi,agc-inner-thresh-low = <12>; /* -dBFS */ + adi,agc-inner-thresh-low-inc-steps = <1>; /* 0..7 */ + adi,agc-outer-thresh-low = <18>; /* -dBFS */ + adi,agc-outer-thresh-low-inc-steps = <2>; /* 0..15 */ + + adi,agc-adc-small-overload-exceed-counter = <10>; /* 0..15 */ + adi,agc-adc-large-overload-exceed-counter = <10>; /* 0..15 */ + adi,agc-adc-large-overload-inc-steps = <2>; /* 0..15 */ + //adi,agc-adc-lmt-small-overload-prevent-gain-inc-enable; + adi,agc-lmt-overload-large-exceed-counter = <10>; /* 0..15 */ + adi,agc-lmt-overload-small-exceed-counter = <10>; /* 0..15 */ + adi,agc-lmt-overload-large-inc-steps = <2>; /* 0..7 */ + //adi,agc-dig-saturation-exceed-counter = <3>; /* 0..15 */ + //adi,agc-dig-gain-step-size = <4>; /* 1..8 */ + + //adi,agc-sync-for-gain-counter-enable; + adi,agc-gain-update-interval-us = <1000>; /* 1ms */ + //adi,agc-immed-gain-change-if-large-adc-overload-enable; + //adi,agc-immed-gain-change-if-large-lmt-overload-enable; + + /* Fast AGC */ + + adi,fagc-dec-pow-measurement-duration = <64>; /* 64 Samples */ + //adi,fagc-allow-agc-gain-increase-enable; + adi,fagc-lp-thresh-increment-steps = <1>; + adi,fagc-lp-thresh-increment-time = <5>; + + adi,fagc-energy-lost-stronger-sig-gain-lock-exit-cnt = <8>; + adi,fagc-final-overrange-count = <3>; + //adi,fagc-gain-increase-after-gain-lock-enable; + adi,fagc-gain-index-type-after-exit-rx-mode = <0>; + adi,fagc-lmt-final-settling-steps = <1>; + adi,fagc-lock-level = <10>; + adi,fagc-lock-level-gain-increase-upper-limit = <5>; + adi,fagc-lock-level-lmt-gain-increase-enable; + + adi,fagc-lpf-final-settling-steps = <1>; + adi,fagc-optimized-gain-offset = <5>; + adi,fagc-power-measurement-duration-in-state5 = <64>; + adi,fagc-rst-gla-engergy-lost-goto-optim-gain-enable; + adi,fagc-rst-gla-engergy-lost-sig-thresh-below-ll = <10>; + adi,fagc-rst-gla-engergy-lost-sig-thresh-exceeded-enable; + adi,fagc-rst-gla-if-en-agc-pulled-high-mode = <0>; + adi,fagc-rst-gla-large-adc-overload-enable; + adi,fagc-rst-gla-large-lmt-overload-enable; + adi,fagc-rst-gla-stronger-sig-thresh-above-ll = <10>; + adi,fagc-rst-gla-stronger-sig-thresh-exceeded-enable; + adi,fagc-state-wait-time-ns = <260>; + adi,fagc-use-last-lock-level-for-set-gain-enable; + + /* RSSI */ + + /* adi,rssi-restart-mode: + * 0 = AGC_IN_FAST_ATTACK_MODE_LOCKS_THE_GAIN, + * 1 = EN_AGC_PIN_IS_PULLED_HIGH, + * 2 = ENTERS_RX_MODE, + * 3 = GAIN_CHANGE_OCCURS, + * 4 = SPI_WRITE_TO_REGISTER, + * 5 = GAIN_CHANGE_OCCURS_OR_EN_AGC_PIN_PULLED_HIGH, + */ + adi,rssi-restart-mode = <3>; + //adi,rssi-unit-is-rx-samples-enable; + adi,rssi-delay = <1>; /* 1us */ + adi,rssi-wait = <1>; /* 1us */ + adi,rssi-duration = <1000>; /* 1ms */ + + /* Control Outputs */ + adi,ctrl-outs-index = <0>; + adi,ctrl-outs-enable-mask = <0xFF>; + + /* AuxADC Temp Sense Control */ + + adi,temp-sense-measurement-interval-ms = <1000>; + adi,temp-sense-offset-signed = <0xCE>; + adi,temp-sense-periodic-measurement-enable; + + /* AuxDAC Control */ + + adi,aux-dac-manual-mode-enable; + + adi,aux-dac1-default-value-mV = <0>; + //adi,aux-dac1-active-in-rx-enable; + //adi,aux-dac1-active-in-tx-enable; + //adi,aux-dac1-active-in-alert-enable; + adi,aux-dac1-rx-delay-us = <0>; + adi,aux-dac1-tx-delay-us = <0>; + + adi,aux-dac2-default-value-mV = <0>; + //adi,aux-dac2-active-in-rx-enable; + //adi,aux-dac2-active-in-tx-enable; + //adi,aux-dac2-active-in-alert-enable; + adi,aux-dac2-rx-delay-us = <0>; + adi,aux-dac2-tx-delay-us = <0>; + + /* Control GPIOs */ + + en_agc-gpios = <&gpio0 66 0>; + reset-gpios = <&gpio0 67 0>; + VCRX1_1-gpios = <&gpio0 71 0>;/* RX1 3~6G */ + VCRX1_2-gpios = <&gpio0 72 0>;/* RX1 4.5M~3G */ + VCTX1_2-gpios = <&gpio0 73 0>;/* TX1 3~6G */ + VCTX1_1-gpios = <&gpio0 74 0>;/* TX1 4.5M~3G */ + VCRX2_1-gpios = <&gpio0 75 0>;/* RX2 4.5M~3G */ + VCRX2_2-gpios = <&gpio0 76 0>;/* RX2 3~6G */ + VCTX2_1-gpios = <&gpio0 77 0>;/* TX2 3~6G */ + VCTX2_2-gpios = <&gpio0 78 0>;/* TX2 4.5M~3G */ + }; +}; diff --git a/arch/arm/boot/dts/zynq.dtsi b/arch/arm/boot/dts/zynq.dtsi index 465f00e21eddb8..c296cf63751016 100644 --- a/arch/arm/boot/dts/zynq.dtsi +++ b/arch/arm/boot/dts/zynq.dtsi @@ -7,6 +7,8 @@ aliases: aliases { ethernet0 = &gem0; serial0 = &uart1; + mmc0 = &sdhci0; + usb0 = &usb0; }; }; diff --git a/arch/arm/configs/zynq_ant_defconfig b/arch/arm/configs/zynq_ant_defconfig new file mode 100644 index 00000000000000..ec4dc278c3c8cf --- /dev/null +++ b/arch/arm/configs/zynq_ant_defconfig @@ -0,0 +1,285 @@ +CONFIG_SYSVIPC=y +CONFIG_USELIB=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=15 +CONFIG_CGROUPS=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_EMBEDDED=y +CONFIG_PERF_EVENTS=y +CONFIG_SLAB=y +CONFIG_ARCH_ZYNQ=y + +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y + +CONFIG_UEVENT_HELPER=y +CONFIG_MACB=y +CONFIG_MDIO_BITBANG=y +CONFIG_MARVELL_PHY=y +CONFIG_XILINX_GMII2RGMII=y +CONFIG_USB_NET_DM9601=y + +CONFIG_XILINX_RESET_CODE=y +CONFIG_PL310_ERRATA_588369=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_PL310_ERRATA_769419=y +# CONFIG_ARM_ERRATA_643719 is not set +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_754327=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_ARM_ERRATA_775420=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw earlyprintk" +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_ARM_ZYNQ_CPUIDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_COMPACTION is not set +CONFIG_CMA=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +# CONFIG_IPV6 is not set +CONFIG_VLAN_8021Q=m +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_MAC80211_LEDS=y +CONFIG_RFKILL=y +CONFIG_RFKILL_INPUT=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=256 +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_SPI_NOR=y +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_SRAM=y +# CONFIG_MATHWORKS_IP_CORE is not set +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +CONFIG_USB_RTL8152=y +CONFIG_USB_LAN78XX=y +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_CDC_NCM is not set +CONFIG_USB_NET_SMSC75XX=y +CONFIG_USB_NET_SMSC95XX=y +# CONFIG_USB_NET_NET1080 is not set +CONFIG_USB_NET_RNDIS_HOST=y +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +CONFIG_RT2X00=y +CONFIG_RT2500USB=y +CONFIG_RT73USB=y +CONFIG_RT2800USB=y +CONFIG_RT2800USB_RT3573=y +CONFIG_RT2800USB_RT53XX=y +CONFIG_RT2800USB_RT55XX=y +CONFIG_RT2800USB_UNKNOWN=y +CONFIG_RTL8187=y +CONFIG_RTL8192CU=y +# CONFIG_RTLWIFI_DEBUG is not set +CONFIG_RTL8XXXU=y +CONFIG_RTL8XXXU_UNTESTED=y +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +CONFIG_INPUT_FF_MEMLESS=y +CONFIG_INPUT_SPARSEKMAP=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_CADENCE=y +CONFIG_I2C_GPIO=y +CONFIG_I2C_XILINX=y +CONFIG_SPI=y +CONFIG_SPI_AXI_SPI_ENGINE=y +CONFIG_SPI_CADENCE=y +CONFIG_SPI_XILINX=y +CONFIG_SPI_ZYNQ_QSPI=y +CONFIG_SPI_SPIDEV=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_ZYNQ=y +CONFIG_POWER_SUPPLY=y +CONFIG_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_XILINX_WATCHDOG=y +CONFIG_CADENCE_WATCHDOG=y +CONFIG_SSB=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_HIDRAW=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_OTG=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_STORAGE=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_FTDI_SIO=y +CONFIG_USB_ULPI=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_XILINX=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_ACM=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_ECM=y +CONFIG_USB_CONFIGFS_ECM_SUBSET=y +CONFIG_USB_CONFIGFS_RNDIS=y +CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_DMADEVICES=y +CONFIG_AXI_DMAC=y +CONFIG_UIO=y +CONFIG_UIO_PDRV_GENIRQ=y +CONFIG_UIO_DMEM_GENIRQ=y +CONFIG_UIO_XILINX_APM=y +CONFIG_STAGING=y +CONFIG_R8712U=y +CONFIG_R8188EU=y +CONFIG_COMMON_CLK_AXI_CLKGEN=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_MEMORY=y +CONFIG_IIO=y +CONFIG_ADM1177=y +CONFIG_AD9361=y +CONFIG_ADMC=y +CONFIG_XILINX_XADC=y +CONFIG_CF_AXI_DDS=y +CONFIG_FPGA=y +CONFIG_FPGA_MGR_ZYNQ_FPGA=y +CONFIG_EXT4_FS=y +# CONFIG_DNOTIFY is not set +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_MICHAEL_MIC=y +CONFIG_DEBUG_INFO=y +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_DEBUG_FS=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=20 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_FTRACE is not set +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_ZYNQ_UART1=y +CONFIG_EARLY_PRINTK=y \ No newline at end of file diff --git a/drivers/iio/adc/ad9361.c b/drivers/iio/adc/ad9361.c index ae85e1a42f319c..f9c9408e3dd3da 100644 --- a/drivers/iio/adc/ad9361.c +++ b/drivers/iio/adc/ad9361.c @@ -38,6 +38,7 @@ #include "ad9361.h" #include "ad9361_private.h" + static const struct SynthLUT SynthLUT_FDD[LUT_FTDD_ENT][SYNTH_LUT_SIZE] = { { {12605, 13, 1, 4, 2, 15, 12, 7, 14, 6, 14, 5, 15}, /* 40 MHz */ @@ -1031,7 +1032,7 @@ int ad9361_bist_loopback(struct ad9361_rf_phy *phy, unsigned mode) } EXPORT_SYMBOL(ad9361_bist_loopback); -int ad9361_write_bist_reg(struct ad9361_rf_phy *phy, u32 val) +int ad9361_write_bist_reg(struct ad9361_rf_phy *phy, u32 val) { if (!phy || !phy->state) return -EINVAL; @@ -1531,9 +1532,9 @@ static int ad9361_get_split_table_gain(struct ad9361_rf_phy *phy, u32 idx_reg, rx_gain->tia_index = ad9361_spi_readf(spi, REG_GAIN_TABLE_READ_DATA2, TIA_GAIN); - rx_gain->lmt_gain = lna_table[ad9361_gt(phy) - RXGAIN_TBLS_END][rx_gain->lna_index] + - mixer_table[ad9361_gt(phy) - RXGAIN_TBLS_END][rx_gain->mixer_index] + - tia_table[rx_gain->tia_index]; + rx_gain->lmt_gain = lna_table[ad9361_gt(phy)][rx_gain->lna_index] + + mixer_table[ad9361_gt(phy)][rx_gain->mixer_index] + + tia_table[rx_gain->tia_index]; ad9361_spi_write(spi, REG_GAIN_TABLE_ADDRESS, tbl_addr); @@ -2731,15 +2732,11 @@ static int __ad9361_tx_quad_calib(struct ad9361_rf_phy *phy, u32 phase, if (ret < 0) return ret; - if (res) { + if (res) *res = ad9361_spi_read(phy->spi, (phy->pdata->rx1tx1_mode_use_tx_num == 2) ? REG_QUAD_CAL_STATUS_TX2 : REG_QUAD_CAL_STATUS_TX1) & (TX1_LO_CONV | TX1_SSB_CONV); - if (phy->pdata->rx2tx2) - *res &= ad9361_spi_read(phy->spi, REG_QUAD_CAL_STATUS_TX2) & - (TX2_LO_CONV | TX2_SSB_CONV); - } return 0; } @@ -2919,8 +2916,8 @@ static int ad9361_tx_quad_calib(struct ad9361_rf_phy *phy, ad9361_spi_write(spi, REG_QUAD_CAL_COUNT, 0xFF); ad9361_spi_write(spi, REG_KEXP_1, KEXP_TX(1) | KEXP_TX_COMP(3) | KEXP_DC_I(3) | KEXP_DC_Q(3)); - ad9361_spi_write(spi, REG_MAG_FTEST_THRESH, 0x03); - ad9361_spi_write(spi, REG_MAG_FTEST_THRESH_2, 0x03); + ad9361_spi_write(spi, REG_MAG_FTEST_THRESH, 0x01); + ad9361_spi_write(spi, REG_MAG_FTEST_THRESH_2, 0x01); if (st->tx_quad_lpf_tia_match < 0) /* set in ad9361_load_gt() */ dev_err(dev, "failed to find suitable LPF TIA value in gain table\n"); @@ -4838,7 +4835,7 @@ static int ad9361_rssi_gain_step_calib(struct ad9361_rf_phy *phy) u8 lo_index; u8 i; int ret; - + lo_freq_hz = ad9361_from_clk(clk_get_rate(phy->clks[RX_RFPLL])); if (lo_freq_hz < 1300000000ULL) lo_index = 0; @@ -5072,7 +5069,7 @@ static int ad9361_setup(struct ad9361_rf_phy *phy) clk_set_parent(phy->clks[TX_RFPLL], phy->clks[TX_RFPLL_INT]); clk_set_parent(phy->clks[RX_RFPLL], phy->clks[RX_RFPLL_INT]); - + ret = clk_set_rate(phy->clks[RX_REFCLK], ref_freq); if (ret < 0) { dev_err(dev, "Failed to set RX Synth ref clock rate (%d)\n", ret); @@ -5092,7 +5089,6 @@ static int ad9361_setup(struct ad9361_rf_phy *phy) ret = ad9361_txrx_synth_cp_calib(phy, ref_freq, true); /* TXCP */ if (ret < 0) return ret; - ret = clk_set_rate(phy->clks[RX_RFPLL], ad9361_to_clk(pd->rx_synth_freq)); if (ret < 0) { dev_err(dev, "Failed to set RX Synth rate (%d)\n", @@ -5116,7 +5112,6 @@ static int ad9361_setup(struct ad9361_rf_phy *phy) ret = clk_prepare_enable(phy->clks[TX_RFPLL]); if (ret < 0) return ret; - clk_set_parent(phy->clks[RX_RFPLL], pd->use_ext_rx_lo ? phy->clk_ext_lo_rx : phy->clks[RX_RFPLL_INT]); @@ -7005,6 +7000,7 @@ static ssize_t ad9361_phy_store(struct device *dev, ad9361_set_trx_clock_chain(phy, st->current_rx_path_clks, st->current_tx_path_clks); clk_set_rate(phy->clks[RX_RFPLL], rx); + clk_set_rate(phy->clks[TX_RFPLL], tx); break; } @@ -7192,7 +7188,7 @@ static IIO_DEVICE_ATTR(calib_mode_available, S_IRUGO, NULL, AD9361_CALIB_MODE_AVAIL); -static IIO_DEVICE_ATTR(rssi_gain_step_error, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(rssi_gain_step_error, S_IRUGO, ad9361_phy_show, ad9361_phy_store, AD9361_RSSI_GAIN_STEP_ERROR); @@ -7391,10 +7387,40 @@ static ssize_t ad9361_phy_lo_write(struct iio_dev *indio_dev, case 0: ret = clk_set_rate(phy->clks[RX_RFPLL], ad9361_to_clk(readin)); + if(ad9361_to_clk(readin)>1500000000) + { + gpiod_set_value_cansleep(phy->pdata->VCRX1_1_gpio, 1); + gpiod_set_value_cansleep(phy->pdata->VCRX2_2_gpio, 1); + gpiod_set_value_cansleep(phy->pdata->VCRX1_2_gpio, 0); + gpiod_set_value_cansleep(phy->pdata->VCRX2_1_gpio, 0); + } + else + { + gpiod_set_value_cansleep(phy->pdata->VCRX1_1_gpio, 0); + gpiod_set_value_cansleep(phy->pdata->VCRX2_2_gpio, 0); + gpiod_set_value_cansleep(phy->pdata->VCRX1_2_gpio, 1); + gpiod_set_value_cansleep(phy->pdata->VCRX2_1_gpio, 1); + } + +/******************************切换滤波器频段**********************************/ break; case 1: ret = clk_set_rate(phy->clks[TX_RFPLL], ad9361_to_clk(readin)); + if(ad9361_to_clk(readin)>1500000000) + { + gpiod_set_value_cansleep(phy->pdata->VCTX1_2_gpio, 1); + gpiod_set_value_cansleep(phy->pdata->VCTX2_1_gpio, 1); + gpiod_set_value_cansleep(phy->pdata->VCTX1_1_gpio, 0); + gpiod_set_value_cansleep(phy->pdata->VCTX2_2_gpio, 0); + } + else + { + gpiod_set_value_cansleep(phy->pdata->VCTX1_2_gpio, 0); + gpiod_set_value_cansleep(phy->pdata->VCTX2_1_gpio, 0); + gpiod_set_value_cansleep(phy->pdata->VCTX1_1_gpio, 1); + gpiod_set_value_cansleep(phy->pdata->VCTX2_2_gpio, 1); + } if (test_bit(0, &st->flags)) wait_for_completion(&phy->complete); @@ -7446,10 +7472,11 @@ static ssize_t ad9361_phy_lo_write(struct iio_dev *indio_dev, default: switch (chan->channel) { case 0: - if (phy->clk_ext_lo_rx) + if (phy->clk_ext_lo_rx){ ret = clk_set_parent(phy->clks[RX_RFPLL], res ? phy->clk_ext_lo_rx : phy->clks[RX_RFPLL_INT]); + } else ret = -ENODEV; break; @@ -9470,7 +9497,48 @@ static int ad9361_probe(struct spi_device *spi) GPIOD_OUT_HIGH); if (IS_ERR(phy->pdata->reset_gpio)) return PTR_ERR(phy->pdata->reset_gpio); +/********************************************************************************/ + phy->pdata->VCRX1_1_gpio = devm_gpiod_get_optional(&spi->dev, "VCRX1_1", + GPIOD_OUT_HIGH); + if (IS_ERR(phy->pdata->VCRX1_1_gpio)) + return PTR_ERR(phy->pdata->VCRX1_1_gpio); + + phy->pdata->VCRX1_2_gpio = devm_gpiod_get_optional(&spi->dev, "VCRX1_2", + GPIOD_OUT_HIGH); + if (IS_ERR(phy->pdata->VCRX1_2_gpio)) + return PTR_ERR(phy->pdata->VCRX1_2_gpio); + + phy->pdata->VCTX1_2_gpio = devm_gpiod_get_optional(&spi->dev, "VCTX1_2", + GPIOD_OUT_HIGH); + if (IS_ERR(phy->pdata->VCTX1_2_gpio)) + return PTR_ERR(phy->pdata->VCTX1_2_gpio); + + phy->pdata->VCTX1_1_gpio = devm_gpiod_get_optional(&spi->dev, "VCTX1_1", + GPIOD_OUT_HIGH); + if (IS_ERR(phy->pdata->VCTX1_1_gpio)) + return PTR_ERR(phy->pdata->VCTX1_1_gpio); + + phy->pdata->VCRX2_1_gpio = devm_gpiod_get_optional(&spi->dev, "VCRX2_1", + GPIOD_OUT_HIGH); + if (IS_ERR(phy->pdata->VCRX2_1_gpio)) + return PTR_ERR(phy->pdata->VCRX2_1_gpio); + + phy->pdata->VCRX2_2_gpio = devm_gpiod_get_optional(&spi->dev, "VCRX2_2", + GPIOD_OUT_HIGH); + if (IS_ERR(phy->pdata->VCRX2_2_gpio)) + return PTR_ERR(phy->pdata->VCRX2_2_gpio); + + phy->pdata->VCTX2_1_gpio = devm_gpiod_get_optional(&spi->dev, "VCTX2_1", + GPIOD_OUT_HIGH); + if (IS_ERR(phy->pdata->VCTX2_1_gpio)) + return PTR_ERR(phy->pdata->VCTX2_1_gpio); + + phy->pdata->VCTX2_2_gpio = devm_gpiod_get_optional(&spi->dev, "VCTX2_2", + GPIOD_OUT_HIGH); + if (IS_ERR(phy->pdata->VCTX2_2_gpio)) + return PTR_ERR(phy->pdata->VCTX2_2_gpio); +/********************************************************************************/ /* Optional: next three used for MCS synchronization */ phy->pdata->sync_gpio = devm_gpiod_get_optional(&spi->dev, "sync", GPIOD_OUT_LOW); diff --git a/drivers/iio/adc/ad9361_private.h b/drivers/iio/adc/ad9361_private.h index dfffc4fa88a9a7..390ea7b755920d 100644 --- a/drivers/iio/adc/ad9361_private.h +++ b/drivers/iio/adc/ad9361_private.h @@ -371,6 +371,14 @@ struct ad9361_phy_platform_data { struct tx_monitor_control txmon_ctrl; struct gpio_desc *reset_gpio; + struct gpio_desc *VCRX1_1_gpio; + struct gpio_desc *VCRX1_2_gpio; + struct gpio_desc *VCTX1_2_gpio; + struct gpio_desc *VCTX1_1_gpio; + struct gpio_desc *VCRX2_1_gpio; + struct gpio_desc *VCRX2_2_gpio; + struct gpio_desc *VCTX2_1_gpio; + struct gpio_desc *VCTX2_2_gpio; /* MCS SYNC */ struct gpio_desc *sync_gpio; struct gpio_desc *cal_sw1_gpio; From 72390de6f2edda72a3a45b3fb7504e81b8df16b4 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Tue, 5 Apr 2022 16:50:25 +0300 Subject: [PATCH 282/407] arch: arm: socfpga_adi_defconfig: Extend Kuiper support Scopy and Chromium are two applications that require these options. Signed-off-by: Dragos Bogdan --- arch/arm/configs/socfpga_adi_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/socfpga_adi_defconfig b/arch/arm/configs/socfpga_adi_defconfig index 71cc26db69ac6b..eba673a99966e0 100644 --- a/arch/arm/configs/socfpga_adi_defconfig +++ b/arch/arm/configs/socfpga_adi_defconfig @@ -7,6 +7,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_CGROUPS=y CONFIG_CPUSETS=y CONFIG_NAMESPACES=y +CONFIG_USER_NS=y CONFIG_BLK_DEV_INITRD=y CONFIG_EMBEDDED=y CONFIG_PROFILING=y @@ -128,6 +129,7 @@ CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y CONFIG_EXT3_FS=y CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y CONFIG_VFAT_FS=y CONFIG_NTFS_FS=y CONFIG_NTFS_RW=y From c606fc09ccb1da9dfd356d643ef5ffeb099200bb Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Tue, 5 Apr 2022 16:58:38 +0300 Subject: [PATCH 283/407] arch: arm: zynq_xcomm_adv7511_defconfig: Extend Kuiper support Scopy and Chromium are two applications that require these options. Signed-off-by: Dragos Bogdan --- arch/arm/configs/zynq_xcomm_adv7511_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/configs/zynq_xcomm_adv7511_defconfig b/arch/arm/configs/zynq_xcomm_adv7511_defconfig index cb3be54f507d4c..0e4180e7802f87 100644 --- a/arch/arm/configs/zynq_xcomm_adv7511_defconfig +++ b/arch/arm/configs/zynq_xcomm_adv7511_defconfig @@ -7,6 +7,8 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=15 CONFIG_CGROUPS=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_BZIP2 is not set # CONFIG_RD_LZMA is not set @@ -234,6 +236,7 @@ CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y # CONFIG_DNOTIFY is not set CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y From 492b6c743be99545710623940efdca16b621adcf Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Tue, 5 Apr 2022 16:59:36 +0300 Subject: [PATCH 284/407] arch: arm64: adi_zynqmp_defconfig: Extend Kuiper support Scopy and Chromium are two applications that require these options. Signed-off-by: Dragos Bogdan --- arch/arm64/configs/adi_zynqmp_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/configs/adi_zynqmp_defconfig b/arch/arm64/configs/adi_zynqmp_defconfig index da1862103f9bc4..21beb6a281c660 100644 --- a/arch/arm64/configs/adi_zynqmp_defconfig +++ b/arch/arm64/configs/adi_zynqmp_defconfig @@ -13,6 +13,8 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_CGROUPS=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y CONFIG_BLK_DEV_INITRD=y CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set @@ -331,6 +333,7 @@ CONFIG_BTRFS_FS=y CONFIG_QUOTA=y CONFIG_QFMT_V2=y CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y From a9d7a8970c3244c1a0b7da3c33faff2157cfa86f Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Tue, 5 Apr 2022 17:00:38 +0300 Subject: [PATCH 285/407] arch: arm64: adi_versal_defconfig: Extend Kuiper support Scopy and Chromium are two applications that require these options. The .defconfig file was generated using "make savedefconfig". Signed-off-by: Dragos Bogdan --- arch/arm64/configs/adi_versal_defconfig | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/arch/arm64/configs/adi_versal_defconfig b/arch/arm64/configs/adi_versal_defconfig index 23a28d36c669ee..30d2ea1e2754b8 100644 --- a/arch/arm64/configs/adi_versal_defconfig +++ b/arch/arm64/configs/adi_versal_defconfig @@ -13,6 +13,8 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_CGROUPS=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y CONFIG_BLK_DEV_INITRD=y CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set @@ -125,7 +127,6 @@ CONFIG_BT_HCIVHCI=y CONFIG_BT_MRVL=y CONFIG_BT_MRVL_SDIO=y CONFIG_BT_ATH3K=y -CONFIG_BT_WILINK=y CONFIG_CFG80211=y CONFIG_NL80211_TESTMODE=y CONFIG_CFG80211_CERTIFICATION_ONUS=y @@ -159,7 +160,6 @@ CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_ARASAN=y CONFIG_MTD_SPI_NOR=y # CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set -CONFIG_SPI_CADENCE_QUADSPI=y CONFIG_MTD_UBI=y CONFIG_OF_OVERLAY=y CONFIG_OF_CONFIGFS=y @@ -187,25 +187,25 @@ CONFIG_MACB=y CONFIG_XILINX_EMACLITE=y CONFIG_XILINX_AXI_EMAC=y CONFIG_AMD_PHY=y -CONFIG_AT803X_PHY=y +CONFIG_BROADCOM_PHY=y CONFIG_BCM7XXX_PHY=y CONFIG_BCM87XX_PHY=y -CONFIG_BROADCOM_PHY=y CONFIG_CICADA_PHY=y CONFIG_DAVICOM_PHY=y -CONFIG_DP83848_PHY=y -CONFIG_DP83867_PHY=y CONFIG_ICPLUS_PHY=y -CONFIG_LSI_ET1011C_PHY=y CONFIG_LXT_PHY=y +CONFIG_LSI_ET1011C_PHY=y CONFIG_MARVELL_PHY=y CONFIG_MICREL_PHY=y CONFIG_MICROSEMI_PHY=y CONFIG_NATIONAL_PHY=y +CONFIG_AT803X_PHY=y CONFIG_QSEMI_PHY=y CONFIG_REALTEK_PHY=y CONFIG_SMSC_PHY=y CONFIG_STE10XP=y +CONFIG_DP83848_PHY=y +CONFIG_DP83867_PHY=y CONFIG_VITESSE_PHY=y CONFIG_XILINX_PHY=y CONFIG_XILINX_GMII2RGMII=y @@ -234,6 +234,7 @@ CONFIG_I2C_MUX_PCA954x=y CONFIG_I2C_CADENCE=y CONFIG_I2C_XILINX=y CONFIG_SPI_CADENCE=y +CONFIG_SPI_CADENCE_QUADSPI=y CONFIG_SPI_XILINX=y CONFIG_SPI_ZYNQMP_GQSPI=y CONFIG_GPIO_SYSFS=y @@ -251,6 +252,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_GPIO=y CONFIG_REGULATOR_TPS65086=y CONFIG_VIDEO_XILINX=y +CONFIG_VIDEO_XILINX_CSI2RXSS=y CONFIG_VIDEO_XILINX_AXI4S_SWITCH=y CONFIG_VIDEO_XILINX_CFA=y CONFIG_VIDEO_XILINX_CRESAMPLE=y @@ -266,16 +268,15 @@ CONFIG_VIDEO_XILINX_SWITCH=y CONFIG_VIDEO_XILINX_TPG=y CONFIG_VIDEO_XILINX_VPSS_CSC=y CONFIG_VIDEO_XILINX_VPSS_SCALER=y -CONFIG_VIDEO_XILINX_CSI2RXSS=y CONFIG_VIDEO_XILINX_DPRXSS=y CONFIG_VIDEO_XILINX_SCD=y CONFIG_VIDEO_XILINX_M2M=y # CONFIG_VGA_ARB is not set CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM=y +CONFIG_DRM_ZYNQMP_DPSUB=y CONFIG_DRM_XLNX=y CONFIG_DRM_XLNX_BRIDGE=y CONFIG_DRM_XLNX_BRIDGE_DEBUG_FS=y -CONFIG_DRM_ZYNQMP_DPSUB=y CONFIG_DRM_XLNX_DPTX=y CONFIG_DRM_XLNX_DSI=y CONFIG_DRM_XLNX_MIXER=y @@ -363,6 +364,7 @@ CONFIG_EXPORTFS_BLOCK_OPS=y CONFIG_QUOTA=y CONFIG_QFMT_V2=y CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -405,9 +407,9 @@ CONFIG_CMA_SIZE_MBYTES=256 CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y # CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_DEBUG_FS=y # CONFIG_SECTION_MISMATCH_WARN_ONLY is not set CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y # CONFIG_SCHED_DEBUG is not set # CONFIG_FTRACE is not set # CONFIG_STRICT_DEVMEM is not set From f899bbde4ef96c0a55c05fdf225d666cd60a2e42 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Fri, 11 Feb 2022 12:02:14 +0200 Subject: [PATCH 286/407] Documentation: bindings: Add docs for AD978X Add documentation for the AD9780/AD9781/AD9783 device driver. Signed-off-by: Sergiu Cuciurean --- .../bindings/iio/frequency/adi,ad9783.yaml | 62 +++++++++++++++++++ MAINTAINERS | 7 +++ 2 files changed, 69 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/frequency/adi,ad9783.yaml diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,ad9783.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,ad9783.yaml new file mode 100644 index 00000000000000..5cdcb03c6be890 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/frequency/adi,ad9783.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2022 Analog Devices Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bindings/iio/adc/adi,ad9783.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD9783 DAC family device driver + +maintainers: + - Sergiu Cuciurean + +description: | + The AD9780/AD9781/AD9783 include pin-compatible, high + dynamic range, dual digital-to-analog converters (DACs) with + 12-/14-/16-bit resolutions, and sample rates of up to 500 MSPS. + +properties: + compatible: + enum: + - adi,ad9780 + - adi,ad9781 + - adi,ad9783 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 10000000 + + clocks: + description: + DAC sampling clock input + + clocks-names: + const: dac_clk + + reset-gpios: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + ad9783_spi: adc@0 { + compatible = "adi,ad9783"; + reg = <0>; + spi-max-freequency = <10000000>; + clocks = <&ad9783_clk>; + clock-names = "dac_clk"; + reset-gpios = <&gpio 0 GPIO_ACTIVE_LOW>; + }; + }; + diff --git a/MAINTAINERS b/MAINTAINERS index 0066154ce20d3d..69641cadbfb0b6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1089,6 +1089,13 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/media/i2c/ad9389b* +ANALOG DEVICES INC AD9783 DRIVER +M: Sergiu Cuciurean +L: linux-iio@vger.kernel.org +S: Supported +W: http://ez.analog.com/community/linux-device-drivers +F: Documentation/devicetree/bindings/iio/frequency/adi,ad9783.yaml + ANALOG DEVICES INC ADAR100 DRIVER M: Mircea Caprioru L: linux-iio@vger.kernel.org From abdceca3a01972448a9d3173f0504bb3b63332ee Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Fri, 11 Feb 2022 12:03:57 +0200 Subject: [PATCH 287/407] drivers: iio: adc: Add support for AD9783 The AD9780/AD9781/AD9783 include pin-compatible, high dynamic range, dual digital-to-analog converters (DACs) with 12-/14-/16-bit resolutions, and sample rates of up to 500 MSPS. Full programmability is provided through a serial peripheral interface (SPI) port. Some pin-programmable features are also offered for those applications without a controller. The application domains for this device are Wireless infrastructure, W-CDMA, CDMA2000, TD-SCDMA, WiMAX, Wideband communications LMDS/MMDS, point-to-pointRF signal generators and arbitrary waveform generators. The device offers two main (OUT) DAC channels and two additional (AUX) DAC channels. The main channels offer adjustable gain from 8.66 mA up to 31.66 mA and three operating modes: normal mode, mix mode, RZ mode. The secondary (AUX) channels can be used as independent channels, or if paired with the main ones, they can be ussed as a source or sink for external offset nulling. Signed-off-by: Sergiu Cuciurean --- MAINTAINERS | 1 + drivers/iio/Kconfig.adi | 1 + drivers/iio/frequency/Kconfig | 11 + drivers/iio/frequency/Makefile | 1 + drivers/iio/frequency/ad9783.c | 838 +++++++++++++++++++++++++++++ drivers/iio/frequency/cf_axi_dds.c | 20 + drivers/iio/frequency/cf_axi_dds.h | 1 + 7 files changed, 873 insertions(+) create mode 100644 drivers/iio/frequency/ad9783.c diff --git a/MAINTAINERS b/MAINTAINERS index 69641cadbfb0b6..11ffd1804eb443 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1095,6 +1095,7 @@ L: linux-iio@vger.kernel.org S: Supported W: http://ez.analog.com/community/linux-device-drivers F: Documentation/devicetree/bindings/iio/frequency/adi,ad9783.yaml +F: drivers/iio/frequency/ad9783.c ANALOG DEVICES INC ADAR100 DRIVER M: Mircea Caprioru diff --git a/drivers/iio/Kconfig.adi b/drivers/iio/Kconfig.adi index 244bba5afbf9e3..74652d77191850 100644 --- a/drivers/iio/Kconfig.adi +++ b/drivers/iio/Kconfig.adi @@ -122,6 +122,7 @@ config IIO_ALL_ADI_DRIVERS select CF_AXI_DDS_AD9122 select CF_AXI_DDS_AD9144 select CF_AXI_DDS_AD9739A + select CF_AXI_DDS_AD9783 select HMC7044 select CF_AXI_DDS_AD9162 select CF_AXI_DDS_AD9172 diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig index f1424021282797..0465a3a120c34d 100644 --- a/drivers/iio/frequency/Kconfig +++ b/drivers/iio/frequency/Kconfig @@ -185,6 +185,17 @@ config CF_AXI_DDS_AD9739A Say yes here to build support for Analog Devices AD9739A DAC chip ad9739a, provides direct access via sysfs. +config CF_AXI_DDS_AD9783 + tristate "Analog Devices AD9783 DAC" + depends on CF_AXI_DDS + help + Say yes here to build support for Analog Devices AD9783 DAC family, + provides direct access via sysfs. + + The AD9780/AD9781/AD9783 include pin-compatible, high + dynamic range, dual digital-to-analog converters (DACs) with + 12-/14-/16-bit resolutions, and sample rates of up to 500 MSPS. + config M2K_DAC tristate "Analog Devices M2K DAC" depends on CF_AXI_DDS diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile index fe9ec3a22395c3..f673f2781b85d4 100644 --- a/drivers/iio/frequency/Makefile +++ b/drivers/iio/frequency/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_CF_AXI_DDS) += cf_axi_dds_drv.o obj-$(CONFIG_CF_AXI_DDS_AD9122) += ad9122.o obj-$(CONFIG_CF_AXI_DDS_AD9144) += ad9144.o obj-$(CONFIG_CF_AXI_DDS_AD9739A) += ad9739a.o +obj-$(CONFIG_CF_AXI_DDS_AD9783) += ad9783.o obj-$(CONFIG_HMC7044) += hmc7044.o obj-$(CONFIG_LTC6952) += ltc6952.o diff --git a/drivers/iio/frequency/ad9783.c b/drivers/iio/frequency/ad9783.c new file mode 100644 index 00000000000000..1e790ab391fa16 --- /dev/null +++ b/drivers/iio/frequency/ad9783.c @@ -0,0 +1,838 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * + * AD9783 family device driver + * + * Copyright (c) 2022 Analog Devices Inc. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cf_axi_dds.h" + +/* AD9783 Registers */ +#define AD9783_REG_SPI_CONTROL 0x00 +#define AD9783_REG_DATA_CONTROL 0x02 +#define AD9783_REG_POWER_DOWN 0x03 +#define AD9783_REG_SETUP_AND_HOLD 0x04 +#define AD9783_REG_TIMING_ADJUST 0x05 +#define AD9783_REG_SEEK 0x06 +#define AD9783_REG_MIX_MODE 0x0A +#define AD9783_REG_DAC1_FSC 0x0B +#define AD9783_REG_DAC1_FSC_MSBS 0x0C +#define AD9783_REG_AUXDAC1 0x0D +#define AD9783_REG_AUXDAC1_MSB 0x0E +#define AD9783_REG_DAC2_FSC 0x0F +#define AD9783_REG_DAC2_FSC_MSBS 0x10 +#define AD9783_REG_AUXDAC2 0x11 +#define AD9783_REG_AUXDAC2_MSB 0x12 +#define AD9783_REG_BIST_CONTROL 0x1A +#define AD9783_REG_BIST_RESULT_1_LOW 0x1B +#define AD9783_REG_BIST_RESULT_1_HIGH 0x1C +#define AD9783_REG_BIST_RESULT_2_LOW 0x1D +#define AD9783_REG_BIST_RESULT_2_HIGH 0x1E +#define AD9783_REG_HARDWARE_REVISION 0x1F + +/* AD9783_REG_SPI_CONTROL */ +#define AD9783_SDIO_DIR BIT(7) +#define AD9783_LSBFIRST BIT(6) +#define AD9783_RESET BIT(5) +/* AD9783_REG_DATA_CONTROL */ +#define AD9783_DATA BIT(7) +#define AD9783_DATA_UNSIGNED BIT(7) +#define AD9783_DATA_TWOS_COMPLEMENT 0x00 +#define AD9783_INVDCO BIT(4) +/* AD9783_REG_POWER_DOWN */ +#define AD9783_PD_DCO BIT(7) +#define AD9783_PD_INPT BIT(6) +#define AD9783_PD_AUX2 BIT(5) +#define AD9783_PD_AUX1 BIT(4) +#define AD9783_PD_BIAS BIT(3) +#define AD9783_PD_CLK BIT(2) +#define AD9783_PD_DAC2 BIT(1) +#define AD9783_PD_DAC1 BIT(0) +/* AD9783_REG_SETUP_AND_HOLD */ +#define AD9783_SET GENMASK(7, 4) +#define AD9783_HLD GENMASK(3, 0) +#define AD9783_SH_RESET 0x00 +#define AD9783_SH_SET(x) FIELD_PREP(AD9783_SET, x) +#define AD9783_MAX_SET BIT(4) +#define AD9783_MAX_HLD BIT(4) +/* AD9783_REG_TIMING_ADJUST */ +#define AD9783_SAMP_DLY GENMASK(4, 0) +#define AD9783_MAX_SAMPL_DLY BIT(5) +/* AD9783_REG_SEEK */ +#define AD9783_LVDS_LOW BIT(2) +#define AD9783_LVDS_HIGH BIT(1) +#define AD9783_SEEK BIT(0) +/* AD9783_REG_MIX_MODE */ +#define AD9783_DAC1_MIX GENMASK(3, 2) +#define AD9783_DAC2_MIX GENMASK(1, 0) +#define AD9783_DAC_MIX_MODE_MSK(dac) GENMASK(1 + (2 * (dac)), (2 * (dac))) +#define AD9783_DAC_MIX_MODE(dac, mode) ((mode) << (2 * (dac))) +#define AD9783_GET_MIX_MODE(dac, reg) (((reg) >> (2 * (dac))) & GENMASK(1, 0)) +/* AD9783_REG_DAC1_FSC_MSBS */ +#define AD9783_DAC1FSC_MSB GENMASK(1, 0) +/* AD9783_REG_DAC2_FSC_MSBS */ +#define AD9783_DAC2FSC_MSB GENMASK(1, 0) +/* AD9783_REG_BIST_CONTROL */ +#define AD9783_BISTEN BIT(7) +#define AD9783_BISTRD BIT(6) +#define AD9783_BISTCLR BIT(5) +#define AD9783_BIST_INIT 0x00 +/* AD9783_REG_HARDWARE_REVISION */ +#define AD9783_VERSION GENMASK(7, 4) +#define AD9783_DEVICE GENMASK(3, 0) +#define AD9783_HARDWARE_VERSION 0x1F +/* AD9783_AUX_DAC */ +#define AD9783_REG_AUXDAC_MSB(dac) (AD9783_REG_AUXDAC1_MSB + (4 * (dac))) +#define AD9783_REG_AUXDAC(dac) (AD9783_REG_AUXDAC1 + (4 * (dac))) +#define AD9783_AUXSGN_MSK BIT(7) +#define AD9783_AUXDIR_MSK BIT(6) +#define AD9783_AUXDAC_MSB_MSK GENMASK(1, 0) +#define AD9783_AUXDAC_AUX_P 0 +#define AD9783_AUXDAC_AUX_N BIT(7) +#define AD9783_AUXDAC_OFFSET_I_LSB_NA 1955 +#define AD9783_GET_ACTIVE_OUTPUT(reg) ((reg) & AD9783_AUXSGN_MSK) +#define AD9783_GET_OUTPUT_TYPE(reg) ((reg) & AD9783_AUXDIR_MSK) +/* AD9783_DAC */ +#define AD9783_REG_DAC_MSB(dac) (AD9783_REG_DAC1_FSC_MSBS + (4 * (dac))) +#define AD9783_REG_DACB(dac) (AD9783_REG_DAC1_FSC + (4 * (dac))) +#define AD9783_DAC_MSB_MSK GENMASK(1, 0) +/* AD9783_BIST */ +#define AD9783_REG_BIST_RESULT AD9783_REG_BIST_RESULT_1_LOW +/* AD9783 SPI ops */ +#define AD9783_SPI_WRITE 0 +#define AD9783_SPI_READ BIT(7) +#define AD9783_SPI_TRANSFER_NBYTES(x) FIELD_PREP(GENMASK(6, 5), ((x) - 1)) +#define AD9783_SPI_TRANSFER_ONE_BYTE 0 +#define AD9783_SPI_RESET 0 + +/* AD9783 timing defs */ +#define SEEK 0 +#define SET 1 +#define HLD 2 + +enum ad9783_mix_mode { + NORMAL_MODE, + MIX_MODE, + RZ_MODE +}; + +enum ad9783_output { + AUXP = 0, + AUXN = BIT(7) +}; + +enum ad9783_output_type { + SOURCE = 0, + SINK = BIT(6) +}; + +struct ad9783_phy { + int device_id; + /* Lock for write operations */ + struct mutex lock; + struct clk *sampl_clk; + struct regmap *regmap; + struct spi_device *spi; + struct regulator *ref_io; + struct iio_dev *indio_dev; + struct gpio_desc *reset_gpio; + struct cf_axi_dds_state *dds; +}; + +enum ad9783_device_ids { + ID_DEV_AD9780, + ID_DEV_AD9781, + ID_DEV_AD9783, +}; + +static const char * const ad9783_id_table[] = { + [ID_DEV_AD9780] = "ad9780", + [ID_DEV_AD9781] = "ad9781", + [ID_DEV_AD9783] = "ad9783", +}; + +static const struct regmap_config ad9783_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .write_flag_mask = (AD9783_SPI_WRITE | AD9783_SPI_TRANSFER_ONE_BYTE), + .read_flag_mask = (AD9783_SPI_READ | AD9783_SPI_TRANSFER_ONE_BYTE), + .max_register = 0x1F +}; + +static int ad9783_seek(struct ad9783_phy *phy) +{ + unsigned int val; + int ret; + + ret = regmap_read(phy->regmap, AD9783_REG_SEEK, &val); + if (ret < 0) + return ret; + + return val & AD9783_SEEK; +} + +static int ad9783_timing_adjust(struct ad9783_phy *phy) +{ + int ret, i, smp, set, hld, min = AD9783_MAX_SET; + unsigned char table[AD9783_MAX_SAMPL_DLY][3]; + + for (smp = 0; smp < AD9783_MAX_SAMPL_DLY; smp++) { + ret = regmap_write(phy->regmap, AD9783_REG_SETUP_AND_HOLD, + AD9783_SH_RESET); + if (ret < 0) + return ret; + + ret = regmap_write(phy->regmap, AD9783_REG_TIMING_ADJUST, smp); + if (ret < 0) + return ret; + + ret = ad9783_seek(phy); + if (ret < 0) + return ret; + + table[smp][SEEK] = ret; + set = 0; + hld = 0; + do { + hld++; + ret = regmap_update_bits(phy->regmap, + AD9783_REG_SETUP_AND_HOLD, + AD9783_HLD, hld); + if (ret < 0) + return ret; + + ret = ad9783_seek(phy); + if (ret < 0) + return ret; + + } while (ret > 0 && hld < AD9783_MAX_HLD); + + table[smp][HLD] = hld; + hld = 0; + ret = regmap_write(phy->regmap, AD9783_REG_SETUP_AND_HOLD, + AD9783_SH_RESET); + if (ret < 0) + return ret; + + do { + set++; + ret = regmap_update_bits(phy->regmap, + AD9783_REG_SETUP_AND_HOLD, + AD9783_SET, + AD9783_SH_SET(set)); + if (ret < 0) + return ret; + + ret = ad9783_seek(phy); + if (ret < 0) + return ret; + + } while (ret > 0 && set < AD9783_MAX_SET); + + table[smp][SET] = set; + } + + for (smp = -1, i = 0; i < AD9783_MAX_SAMPL_DLY; i++) { + if (table[i][SEEK] == 1 && table[i][SET] < table[i][HLD]) { + ret = table[i][HLD] - table[i][SET]; + if (ret <= min) { + min = ret; + set = table[i][SET]; + hld = table[i][HLD]; + smp = i; + } + } + } + if (smp < 0) { + dev_err(&phy->spi->dev, + "Could not find and optimal value for the port timing"); + return -EINVAL; + } + + ret = 0; + if (!((table[smp][HLD] + table[smp][SET]) > 8)) + ret = 1; + if (smp == 0) { + if (table[smp + 1][SEEK] == 0) + ret = 1; + } else if (smp == AD9783_MAX_SAMPL_DLY - 1) { + if (table[smp - 1][SEEK] == 0) + ret = 1; + } else { + if (!(table[smp - 1][SEEK] == table[smp + 1][SEEK] && + table[smp - 1][SEEK] == 1)) + ret = 1; + } + if (ret) + dev_warn(&phy->spi->dev, + "Please check for excessive on the input clock line."); + + ret = regmap_write(phy->regmap, AD9783_REG_TIMING_ADJUST, smp); + if (ret < 0) + return ret; + + ret = regmap_update_bits(phy->regmap, AD9783_REG_SETUP_AND_HOLD, + AD9783_SET, AD9783_SH_SET(set)); + if (ret < 0) + return ret; + + return regmap_update_bits(phy->regmap, AD9783_REG_SETUP_AND_HOLD, + AD9783_HLD, hld); +} + +static int ad9783_selftest(struct ad9783_phy *phy, struct cf_axi_dds_state *dds) +{ + int ret; + + ret = regmap_update_bits(phy->regmap, AD9783_REG_DATA_CONTROL, + AD9783_DATA, AD9783_DATA_UNSIGNED); + if (ret < 0) + return ret; + + ret = regmap_write(phy->regmap, AD9783_REG_BIST_CONTROL, + AD9783_BIST_INIT); + if (ret < 0) + return ret; + + usleep_range(5000, 6500); + cf_axi_dds_datasel(dds, 0, DATA_SEL_ZERO); + cf_axi_dds_datasel(dds, 1, DATA_SEL_ZERO); + usleep_range(5000, 6500); + + ret = regmap_write(phy->regmap, AD9783_REG_BIST_CONTROL, + AD9783_BISTCLR); + if (ret < 0) + return ret; + + ret = regmap_write(phy->regmap, AD9783_REG_BIST_CONTROL, + AD9783_BIST_INIT); + if (ret < 0) + return ret; + + ret = regmap_write(phy->regmap, AD9783_REG_BIST_CONTROL, + AD9783_BISTEN); + if (ret < 0) + return ret; + + usleep_range(5000, 6500); + cf_axi_dds_datasel(dds, 0, DATA_SEL_PNXX); + cf_axi_dds_datasel(dds, 1, DATA_SEL_PNXX); + usleep_range(5000, 6500); + + return 0; +} + +static int ad9783_selftest_check(struct ad9783_phy *phy, + struct cf_axi_dds_state *dds) +{ + unsigned int bist_result[4]; + int ret, i; + + ret = regmap_write(phy->regmap, AD9783_REG_BIST_CONTROL, + AD9783_BISTRD); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(bist_result); i++) { + ret = regmap_read(phy->regmap, AD9783_REG_BIST_RESULT + i, + &bist_result[i]); + if (ret < 0) + return ret; + } + + usleep_range(5000, 6500); + cf_axi_dds_datasel(dds, 0, DATA_SEL_DDS); + cf_axi_dds_datasel(dds, 1, DATA_SEL_DDS); + usleep_range(5000, 6500); + + if (bist_result[0] == bist_result[2] && + bist_result[1] == bist_result[3]) + return 0; + + return -EINVAL; +} + +static int ad9783_interface_tune(struct ad9783_phy *phy) +{ + struct cf_axi_converter *conv = spi_get_drvdata(phy->spi); + struct cf_axi_dds_state *dds = iio_priv(conv->indio_dev); + int ret; + + ret = ad9783_timing_adjust(phy); + if (ret < 0) + return ret; + + ret = ad9783_selftest(phy, dds); + if (ret < 0) + return ret; + + if (ad9783_selftest_check(phy, dds) < 0) + return -EINVAL; + + return regmap_update_bits(phy->regmap, AD9783_REG_DATA_CONTROL, + AD9783_DATA, AD9783_DATA_TWOS_COMPLEMENT); +} + +static int ad9783_set_chan_gain(struct ad9783_phy *phy, int ch, + int val_int, int val_frac) +{ + unsigned int val; + int ret; + + val = val_int * 1000 * 1000 + val_frac; + val = clamp(val, 8660000U, 31660000U); + val = (val * 10) - 86600000; + val = DIV_ROUND_CLOSEST(val, 220000); + + mutex_lock(&phy->lock); + ret = regmap_update_bits(phy->regmap, AD9783_REG_DAC_MSB(ch), + AD9783_DAC_MSB_MSK, (val >> 8) & 0x03); + if (ret < 0) + goto err_set_chan_gain; + ret = regmap_write(phy->regmap, AD9783_REG_DACB(ch), val); +err_set_chan_gain: + mutex_unlock(&phy->lock); + + return ret; +} + +static int ad9783_get_chan_gain(struct ad9783_phy *phy, int ch, + int *val, int *val2) +{ + unsigned int data, reg; + int ret; + + mutex_lock(&phy->lock); + ret = regmap_read(phy->regmap, AD9783_REG_DACB(ch), &data); + if (ret < 0) + goto err_get_chan_gain; + ret = regmap_read(phy->regmap, AD9783_REG_DAC_MSB(ch), ®); + if (ret < 0) + goto err_get_chan_gain; + data |= (reg & 0x03) << 8; + *val = DIV_ROUND_CLOSEST((data * 10 - 86600000), 220000); + *val2 = 1000000; +err_get_chan_gain: + mutex_unlock(&phy->lock); + + return ret; +} + +static int ad9783_set_auxdac(struct ad9783_phy *phy, int ch, + int val_int, int val_frac) +{ + unsigned int val; + int ret; + + val = val_int * 1000 * 1000 + val_frac; + val = clamp(val, 0U, 2000000U); + val = DIV_ROUND_CLOSEST(val, AD9783_AUXDAC_OFFSET_I_LSB_NA); + mutex_lock(&phy->lock); + ret = regmap_update_bits(phy->regmap, AD9783_REG_AUXDAC_MSB(ch), + AD9783_AUXDAC_MSB_MSK, (val >> 8) & 0x03); + if (ret < 0) + goto err_set_auxdac; + ret = regmap_write(phy->regmap, AD9783_REG_AUXDAC(ch), val); +err_set_auxdac: + mutex_unlock(&phy->lock); + + return ret; +} + +static int ad9783_get_auxdac(struct ad9783_phy *phy, int ch, + int *val, int *val2) +{ + unsigned int data, reg; + int ret; + + mutex_lock(&phy->lock); + ret = regmap_read(phy->regmap, AD9783_REG_AUXDAC(ch), &data); + if (ret < 0) + goto err_get_auxdac; + ret = regmap_read(phy->regmap, AD9783_REG_AUXDAC_MSB(ch), ®); + if (ret < 0) + goto err_get_auxdac; + data |= (reg & 0x03) << 8; + *val = data * AD9783_AUXDAC_OFFSET_I_LSB_NA; + *val2 = 1000000; +err_get_auxdac: + mutex_unlock(&phy->lock); + + return ret; +} + +static int ad9783_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct ad9783_phy *phy = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + return ad9783_set_auxdac(phy, chan->address % 2, val, val2); + + case IIO_CHAN_INFO_HARDWAREGAIN: + return ad9783_set_chan_gain(phy, chan->channel, val, val2); + } + + return -EINVAL; +} + +static int ad9783_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct ad9783_phy *phy = iio_priv(indio_dev); + int ret; + + switch (info) { + case IIO_CHAN_INFO_RAW: + ret = ad9783_get_auxdac(phy, chan->address % 2, val, val2); + if (ret < 0) + return ret; + + return IIO_VAL_FRACTIONAL; + + case IIO_CHAN_INFO_HARDWAREGAIN: + ret = ad9783_get_chan_gain(phy, chan->address, val, val2); + if (ret < 0) + return ret; + + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; +} + +static int ad9783_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct ad9783_phy *phy = iio_priv(indio_dev); + + if (readval) + return regmap_read(phy->regmap, reg, readval); + + return regmap_write(phy->regmap, reg, writeval); +} + +static int ad9783_set_mix_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct ad9783_phy *phy = iio_priv(indio_dev); + + return regmap_update_bits(phy->regmap, AD9783_REG_MIX_MODE, + AD9783_DAC_MIX_MODE_MSK(chan->channel), + AD9783_DAC_MIX_MODE(chan->channel, mode)); +} + +static int ad9783_get_mix_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad9783_phy *phy = iio_priv(indio_dev); + unsigned int reg; + int ret; + + ret = regmap_read(phy->regmap, AD9783_REG_MIX_MODE, ®); + if (ret < 0) + return ret; + + return AD9783_GET_MIX_MODE(chan->channel, reg); +} + +static int ad9783_set_active_output(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int index) +{ + struct ad9783_phy *phy = iio_priv(indio_dev); + + return regmap_update_bits(phy->regmap, + AD9783_REG_AUXDAC_MSB(chan->address % 2), + AD9783_AUXSGN_MSK, index); +} + +static int ad9783_get_active_output(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad9783_phy *phy = iio_priv(indio_dev); + unsigned int reg; + int ret; + + ret = regmap_read(phy->regmap, + AD9783_REG_AUXDAC_MSB(chan->address % 2), + ®); + if (ret < 0) + return ret; + + return AD9783_GET_ACTIVE_OUTPUT(reg); +} + +static int ad9783_set_output_type(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int type) +{ + struct ad9783_phy *phy = iio_priv(indio_dev); + + return regmap_update_bits(phy->regmap, + AD9783_REG_AUXDAC_MSB(chan->channel), + AD9783_AUXDIR_MSK, type); +} + +static int ad9783_get_output_type(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad9783_phy *phy = iio_priv(indio_dev); + unsigned int reg; + int ret; + + ret = regmap_read(phy->regmap, + AD9783_REG_AUXDAC_MSB(chan->address % 2), + ®); + if (ret < 0) + return ret; + + return AD9783_GET_OUTPUT_TYPE(reg); +} + +static void ad987x_clk_disable(void *data) +{ + struct clk *clk = data; + + clk_disable_unprepare(clk); +} + +unsigned long long ad9783_get_data_clk(struct cf_axi_converter *conv) +{ + return clk_get_rate(conv->clk[CLK_DAC]); +} + +static const char *const ad9783_mix_mode_iio_enum[] = { + [NORMAL_MODE] = "NORMAL_MODE", + [MIX_MODE] = "MIX_MODE", + [RZ_MODE] = "RZ_MODE", +}; + +static const char *const ad9783_output_type_iio_enum[] = { + [SOURCE] = "SOURCE", + [SINK] = "SINK", +}; + +static const char *const ad9783_active_output_iio_enum[] = { + [AUXP] = "AUXP", + [AUXN] = "AUXN", +}; + +static const struct iio_enum ad9783_iio_enums[] = { + { + .items = ad9783_mix_mode_iio_enum, + .num_items = ARRAY_SIZE(ad9783_mix_mode_iio_enum), + .set = ad9783_set_mix_mode, + .get = ad9783_get_mix_mode, + }, + { + .items = ad9783_output_type_iio_enum, + .num_items = ARRAY_SIZE(ad9783_output_type_iio_enum), + .set = ad9783_set_output_type, + .get = ad9783_get_output_type, + }, + { + .items = ad9783_active_output_iio_enum, + .num_items = ARRAY_SIZE(ad9783_active_output_iio_enum), + .set = ad9783_set_active_output, + .get = ad9783_get_active_output, + }, +}; + +static struct iio_chan_spec_ext_info ad9783_dac_ext_info[] = { + IIO_ENUM("mix_mode", IIO_SEPARATE, &ad9783_iio_enums[0]), + IIO_ENUM_AVAILABLE("mix_mode", &ad9783_iio_enums[0]), + { }, +}; + +static struct iio_chan_spec_ext_info ad9783_auxdac_ext_info[] = { + IIO_ENUM("output_type", IIO_SEPARATE, &ad9783_iio_enums[1]), + IIO_ENUM_AVAILABLE("output_type", &ad9783_iio_enums[1]), + IIO_ENUM("active_output", IIO_SEPARATE, &ad9783_iio_enums[2]), + IIO_ENUM_AVAILABLE("active_output", &ad9783_iio_enums[2]), + { }, +}; + +static const struct iio_info ad9783_info = { + .write_raw = &ad9783_write_raw, + .read_raw = &ad9783_read_raw, + .debugfs_reg_access = &ad9783_reg_access, +}; + +#define AD9783_CHANNEL_DAC(_name, _index) \ + { \ + .type = IIO_VOLTAGE, \ + .extend_name = _name, \ + .output = 1, \ + .indexed = 1, \ + .channel = _index, \ + .address = _index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ + .scan_index = _index, \ + .ext_info = ad9783_dac_ext_info, \ + } + +#define AD9783_CHANNEL_AUXDAC(_name, _index) \ + { \ + .type = IIO_VOLTAGE, \ + .extend_name = _name, \ + .output = 1, \ + .indexed = 1, \ + .channel = _index, \ + .address = _index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .ext_info = ad9783_auxdac_ext_info, \ + } + +static const struct iio_chan_spec ad9783_channels[][4] = { + [ID_DEV_AD9783] = { + AD9783_CHANNEL_DAC("TX_I", 0), + AD9783_CHANNEL_DAC("TX_Q", 1), + AD9783_CHANNEL_AUXDAC("AUX1", 2), + AD9783_CHANNEL_AUXDAC("AUX2", 3), + } +}; + +static int ad9783_setup(struct cf_axi_converter *conv) +{ + struct ad9783_phy *phy = conv->phy; + struct spi_device *spi = phy->spi; + struct iio_dev *indio_dev; + int ret; + + indio_dev = phy->indio_dev; + indio_dev->name = ad9783_id_table[phy->device_id]; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &ad9783_info; + indio_dev->channels = ad9783_channels[phy->device_id]; + indio_dev->num_channels = ARRAY_SIZE(ad9783_channels[phy->device_id]); + if (phy->reset_gpio) { + gpiod_set_value_cansleep(phy->reset_gpio, 0); + usleep_range(10, 15); + } else { + ret = regmap_write(phy->regmap, AD9783_REG_SPI_CONTROL, + AD9783_SPI_RESET); + if (ret < 0) + return -ENXIO; + + usleep_range(10, 15); + } + + if (ad9783_interface_tune(phy) < 0) + dev_warn(&phy->spi->dev, "Selftest failed."); + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static int ad9783_register_converter(struct ad9783_phy *phy) +{ + struct spi_device *spi = phy->spi; + struct cf_axi_converter *conv; + + conv = devm_kzalloc(&spi->dev, sizeof(*conv), GFP_KERNEL); + if (!conv) + return -ENOMEM; + + conv->clk[CLK_DAC] = phy->sampl_clk; + conv->id = ID_DEV_AD9783; + conv->phy = phy; + conv->spi = phy->spi; + conv->setup = ad9783_setup; + conv->get_data_clk = ad9783_get_data_clk; + spi_set_drvdata(phy->spi, conv); + + return 0; +} + +static int ad9783_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct ad9783_phy *phy; + const int *id; + int ret; + + id = device_get_match_data(&spi->dev); + if (!id) + return -EINVAL; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*phy)); + if (!indio_dev) + return -ENOMEM; + + phy = iio_priv(indio_dev); + phy->indio_dev = indio_dev; + phy->spi = spi; + phy->device_id = *id; + + mutex_init(&phy->lock); + + phy->sampl_clk = devm_clk_get(&spi->dev, "dac_clk"); + if (IS_ERR(phy->sampl_clk)) + return PTR_ERR(phy->sampl_clk); + + ret = clk_prepare_enable(phy->sampl_clk); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(&spi->dev, ad987x_clk_disable, + phy->sampl_clk); + if (ret) + return ret; + + phy->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(phy->reset_gpio)) + return PTR_ERR(phy->reset_gpio); + + phy->regmap = devm_regmap_init_spi(spi, &ad9783_regmap_config); + if (IS_ERR(phy->regmap)) + return PTR_ERR(phy->regmap); + + return ad9783_register_converter(phy); +} + +static const int ad9780_id = ID_DEV_AD9780; +static const int ad9781_id = ID_DEV_AD9781; +static const int ad9783_id = ID_DEV_AD9783; + +static const struct of_device_id ad9783_of_match[] = { + { .compatible = "adi,ad9780", .data = &ad9780_id}, + { .compatible = "adi,ad9781", .data = &ad9781_id}, + { .compatible = "adi,ad9783", .data = &ad9783_id}, + {} +}; + +static struct spi_driver ad9783_driver = { + .driver = { + .name = "ad9783", + .of_match_table = ad9783_of_match, + }, + .probe = ad9783_probe, +}; +module_spi_driver(ad9783_driver); + +MODULE_AUTHOR("Sergiu Cuciurean "); +MODULE_DESCRIPTION("Analog Devices AD9783 family device driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/frequency/cf_axi_dds.c b/drivers/iio/frequency/cf_axi_dds.c index 0cde78a8369095..d396e4b59128b1 100644 --- a/drivers/iio/frequency/cf_axi_dds.c +++ b/drivers/iio/frequency/cf_axi_dds.c @@ -1191,6 +1191,18 @@ static struct cf_axi_dds_chip_info cf_axi_dds_chip_info_tbl[] = { .num_dds_channels = 2, .num_buf_channels = 1, + }, + [ID_AD9783] = { + .name = "AD9783", + .channel = { + CF_AXI_DDS_CHAN_BUF(0), + CF_AXI_DDS_CHAN(0, 0, "1A"), + CF_AXI_DDS_CHAN(1, 0, "1B"), + }, + .num_channels = 3, + .num_dds_channels = 2, + .num_buf_channels = 1, + }, [ID_AD9136] = { .name = "AD9136", @@ -1983,6 +1995,11 @@ static const struct axidds_core_info ad9739a_8_00_b_info = { .issue_sync_en = 1, }; +static const struct axidds_core_info ad9783_1_0_info = { + .version = ADI_AXI_PCORE_VER(9, 0, 'b'), + .rate = 1, +}; + static const struct axidds_core_info ad9371_6_00_a_info = { .version = ADI_AXI_PCORE_VER(9, 0, 'a'), .standalone = true, @@ -2082,6 +2099,9 @@ static const struct of_device_id cf_axi_dds_of_match[] = { }, { .compatible = "adi,axi-ad9162-1.0", .data = &ad9162_1_00_a_info, + }, { + .compatible = "adi,axi-ad9783-1.0", + .data = &ad9783_1_0_info, }, { .compatible = "adi,axi-ad9963-dds-1.00.a", .data = &ad9963_1_00_a_info, diff --git a/drivers/iio/frequency/cf_axi_dds.h b/drivers/iio/frequency/cf_axi_dds.h index fbabbc22dd687c..c55b814fbaa325 100644 --- a/drivers/iio/frequency/cf_axi_dds.h +++ b/drivers/iio/frequency/cf_axi_dds.h @@ -198,6 +198,7 @@ enum dds_data_select { enum { ID_AD9122, ID_AD9739A, + ID_AD9783, ID_AD9135, ID_AD9136, ID_AD9144, From 45c83c4bf574cb792b6ab77f97a52d3ed61f8c9b Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Fri, 11 Feb 2022 14:50:39 +0200 Subject: [PATCH 288/407] arch: arm: dts: Add devicetree for EVAL-AD9783 Add devicetree for EVAL-AD9783. Signed-off-by: Sergiu Cuciurean --- .../dts/xilinx/zynqmp-zcu102-rev10-ad9783.dts | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9783.dts diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9783.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9783.dts new file mode 100644 index 00000000000000..fa7914d545f6b1 --- /dev/null +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9783.dts @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2022 Analog Devices Inc. + */ +/dts-v1/; + +#include "zynqmp-zcu102-rev1.0.dts" +#include + +/ { + clocks { + ad9783_clk: clock@0 { + compatible = "fixed-clock"; + #clock-cells =<0>; + clock-frequency = <500000000>; + }; + }; +}; + +&i2c1 { + i2c-mux@75 { + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + eeprom@50 { + compatible = "at24,24c02"; + reg = <0x50>; + }; + + }; + }; +}; + +/ { + fpga_axi: fpga-axi@0 { + interrupt-parent = <&gic>; + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges = <0 0 0 0xffffffff>; + + tx_dma: tx-dmac@9c420000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x9c420000 0x10000>; + #dma-cells = <1>; + interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zynqmp_clk 71>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <128>; + adi,source-bus-type = <0>; + adi,destination-bus-width = <128>; + adi,destination-bus-type = <1>; + }; + }; + }; + + axi_sysid_0: axi-sysid-0@85000000 { + compatible = "adi,axi-sysid-1.00.a"; + reg = <0x85000000 0x10000>; + }; + + axi_ad9783_core: ad9783_core_dds@94204000 { + compatible = "adi,axi-ad9783-1.0"; + reg = <0x94204000 0x4000>; + dmas = <&tx_dma 0>; + dma-names = "tx"; + spibus-connected = <&ad9783_spi>; + }; + }; +}; + +&spi0 { + status = "okay"; + + ad9783_spi: ad9783@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,ad9783"; + reg = <0>; + spi-max-freequency = <10000000>; + clocks = <&ad9783_clk>; + clock-names = "dac_clk"; + }; +}; + +&dwc3_0 { + status = "okay"; + dr_mode = "otg"; +}; From 111d05f22cdbb7f23a3ce66ff738daa90f6c59b6 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 7 Mar 2022 10:07:13 +0200 Subject: [PATCH 289/407] dt-bindings: iio: frequency: add ADF4377 doc Add device tree bindings for the ADF4377 Microwave Wideband Synthesizer with Integrated VCO. Signed-off-by: Antoniu Miclaus --- .../bindings/iio/frequency/adi,adf4377.yaml | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/frequency/adi,adf4377.yaml diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,adf4377.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,adf4377.yaml new file mode 100644 index 00000000000000..3f5c83e03bb92f --- /dev/null +++ b/Documentation/devicetree/bindings/iio/frequency/adi,adf4377.yaml @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/frequency/adi,adf4377.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADF4377 Microwave Wideband Synthesizer with Integrated VCO + +maintainers: + - Antoniu Miclaus + - Dragos Bogdan + +description: | + The ADF4377 is a high performance, ultralow jitter, dual output integer-N + phased locked loop (PLL) with integrated voltage controlled oscillator (VCO) + ideally suited for data converter and mixed signal front end (MxFE) clock + applications. + + https://www.analog.com/en/products/adf4377.html + +properties: + compatible: + enum: + - adi,adf4377 + - adi,adf4378 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 10000000 + + clocks: + maxItems: 1 + + clock-names: + description: + External clock that provides reference input frequency. + items: + - const: ref_in + + ce-en-gpios: + description: + Gpio that controls the Chip Enable Pin. + maxItems: 1 + + enclk1-gpios: + description: + Gpio that controls the Enable Clock 1 Output Buffer Pin. + maxItems: 1 + + enclk2-gpios: + description: + Gpio that controls the Enable Clock 2 Output Buffer Pin. + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + frequency@0 { + compatible = "adi,adf4377"; + reg = <0>; + spi-max-frequency = <10000000>; + clocks = <&adf4377_ref_in>; + clock-names = "ref_in"; + }; + }; +... From 0e25d1ade4cf1a06b0c5478275ee743a91dd9943 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 2 Mar 2022 15:50:25 +0200 Subject: [PATCH 290/407] iio: frequency: add support for adf4377 Add support for Analog Devices ADF4377 Microwave Wideband Synthesizer. Signed-off-by: Dragos Bogdan Signed-off-by: Antoniu Miclaus --- drivers/iio/frequency/Kconfig | 10 + drivers/iio/frequency/Makefile | 1 + drivers/iio/frequency/adf4377.c | 1173 +++++++++++++++++++++++++++++++ 3 files changed, 1184 insertions(+) create mode 100644 drivers/iio/frequency/adf4377.c diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig index 0465a3a120c34d..c593eacf8a94fd 100644 --- a/drivers/iio/frequency/Kconfig +++ b/drivers/iio/frequency/Kconfig @@ -256,6 +256,16 @@ config ADF4371 To compile this driver as a module, choose M here: the module will be called adf4371. +config ADF4377 + tristate "Analog Devices ADF4377 Microwave Wideband Synthesizer" + depends on SPI && COMMON_CLK + help + Say yes here to build support for Analog Devices ADF4377 Microwave + Wideband Synthesizer. + + To compile this driver as a module, choose M here: the + module will be called adf4377. + config ADF5355 tristate "Analog Devices ADF5355/ADF4355 Wideband Synthesizers" depends on SPI diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile index f673f2781b85d4..e3989897d47992 100644 --- a/drivers/iio/frequency/Makefile +++ b/drivers/iio/frequency/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_ADF4159) += adf4159.o obj-$(CONFIG_ADF4350) += adf4350.o obj-$(CONFIG_ADF4360) += adf4360.o obj-$(CONFIG_ADF4371) += adf4371.o +obj-$(CONFIG_ADF4377) += adf4377.o obj-$(CONFIG_ADF5355) += adf5355.o obj-$(CONFIG_ADL5960) += adl5960.o obj-$(CONFIG_ADMV1013) += admv1013.o diff --git a/drivers/iio/frequency/adf4377.c b/drivers/iio/frequency/adf4377.c new file mode 100644 index 00000000000000..989a1c643029d2 --- /dev/null +++ b/drivers/iio/frequency/adf4377.c @@ -0,0 +1,1173 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADF4377 driver + * + * Copyright 2022 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* ADF4377 REG0000 Map */ +#define ADF4377_SOFT_RESET_R_MSK BIT(7) +#define ADF4377_LSB_FIRST_R_MSK BIT(6) +#define ADF4377_ADDRESS_ASC_R_MSK BIT(5) +#define ADF4377_SDO_ACTIVE_R_MSK BIT(4) +#define ADF4377_SDO_ACTIVE_MSK BIT(3) +#define ADF4377_ADDRESS_ASC_MSK BIT(2) +#define ADF4377_LSB_FIRST_MSK BIT(1) +#define ADF4377_SOFT_RESET_MSK BIT(0) + +/* ADF4377 REG0000 Bit Definition */ +#define ADF4377_SDO_ACTIVE_SPI_3W 0x0 +#define ADF4377_SDO_ACTIVE_SPI_4W 0x1 + +#define ADF4377_ADDR_ASC_AUTO_DECR 0x0 +#define ADF4377_ADDR_ASC_AUTO_INCR 0x1 + +#define ADF4377_LSB_FIRST_MSB 0x0 +#define ADF4377_LSB_FIRST_LSB 0x1 + +#define ADF4377_SOFT_RESET_N_OP 0x0 +#define ADF4377_SOFT_RESET_EN 0x1 + +/* ADF4377 REG0001 Map */ +#define ADF4377_SINGLE_INSTR_MSK BIT(7) +#define ADF4377_MASTER_RB_CTRL_MSK BIT(5) + +/* ADF4377 REG0001 Bit Definition */ +#define ADF4377_SPI_STREAM_EN 0x0 +#define ADF4377_SPI_STREAM_DIS 0x1 + +#define ADF4377_RB_SLAVE_REG 0x0 +#define ADF4377_RB_MASTER_REG 0x1 + +/* ADF4377 REG0003 Bit Definition */ +#define ADF4377_CHIP_TYPE 0x06 + +/* ADF4377 REG0004 Bit Definition */ +#define ADF4377_PRODUCT_ID_LSB 0x0005 + +/* ADF4377 REG0005 Bit Definition */ +#define ADF4377_PRODUCT_ID_MSB 0x0005 + +/* ADF4377 REG000A Map */ +#define ADF4377_SCRATCHPAD_MSK GENMASK(7, 0) + +/* ADF4377 REG000C Bit Definition */ +#define ADF4377_VENDOR_ID_LSB 0x56 + +/* ADF4377 REG000D Bit Definition */ +#define ADF4377_VENDOR_ID_MSB 0x04 + +/* ADF4377 REG000F Bit Definition */ +#define ADF4377_R00F_RSV1_MSK GENMASK(7, 0) + +/* ADF4377 REG0010 Map*/ +#define ADF4377_N_INT_LSB_MSK GENMASK(7, 0) + +/* ADF4377 REG0011 Map*/ +#define ADF4377_EN_AUTOCAL_MSK BIT(7) +#define ADF4377_EN_RDBLR_MSK BIT(6) +#define ADF4377_DCLK_DIV2_MSK GENMASK(5, 4) +#define ADF4377_N_INT_MSB_MSK GENMASK(3, 0) + +/* ADF4377 REG0011 Bit Definition */ +#define ADF4377_VCO_CALIB_DIS 0x0 +#define ADF4377_VCO_CALIB_EN 0x1 + +#define ADF4377_REF_DBLR_DIS 0x0 +#define ADF4377_REF_DBLR_EN 0x1 + +#define ADF4377_DCLK_DIV2_1 0x0 +#define ADF4377_DCLK_DIV2_2 0x1 +#define ADF4377_DCLK_DIV2_4 0x2 +#define ADF4377_DCLK_DIV2_8 0x3 + +/* ADF4377 REG0012 Map*/ +#define ADF4377_CLKOUT_DIV_MSK GENMASK(7, 6) +#define ADF4377_R_DIV_MSK GENMASK(5, 0) + +/* ADF4377 REG0012 Bit Definition */ +#define ADF4377_CLKOUT_DIV_1 0x0 +#define ADF4377_CLKOUT_DIV_2 0x1 +#define ADF4377_CLKOUT_DIV_4 0x2 +#define ADF4377_CLKOUT_DIV_8 0x3 + +/* ADF4377 REG0013 Map */ +#define ADF4377_M_VCO_CORE_MSK GENMASK(5, 4) +#define ADF4377_M_VCO_BIAS_MSK GENMASK(3, 0) + +/* ADF4377 REG0013 Bit Definition */ +#define ADF4377_M_VCO_0 0x0 +#define ADF4377_M_VCO_1 0x1 +#define ADF4377_M_VCO_2 0x2 +#define ADF4377_M_VCO_3 0x3 + +/* ADF4377 REG0014 Map */ +#define ADF4377_M_VCO_BAND_MSK GENMASK(7, 0) + +/* ADF4377 REG0015 Map */ +#define ADF4377_BLEED_I_LSB_MSK GENMASK(7, 6) +#define ADF4377_BLEED_POL_MSK BIT(5) +#define ADF4377_EN_BLEED_MSK BIT(4) +#define ADF4377_CP_I_MSK GENMASK(3, 0) + +/* ADF4377 REG0015 Bit Definition */ +#define ADF4377_CURRENT_SINK 0x0 +#define ADF4377_CURRENT_SOURCE 0x1 + +#define ADF4377_BLEED_CURR_DIS 0x0 +#define ADF4377_BLEED_CURR_EN 0x1 + +#define ADF4377_CP_0MA7 0x0 +#define ADF4377_CP_0MA9 0x1 +#define ADF4377_CP_1MA1 0x2 +#define ADF4377_CP_1MA3 0x3 +#define ADF4377_CP_1MA4 0x4 +#define ADF4377_CP_1MA8 0x5 +#define ADF4377_CP_2MA2 0x6 +#define ADF4377_CP_2MA5 0x7 +#define ADF4377_CP_2MA9 0x8 +#define ADF4377_CP_3MA6 0x9 +#define ADF4377_CP_4MA3 0xA +#define ADF4377_CP_5MA0 0xB +#define ADF4377_CP_5MA7 0xC +#define ADF4377_CP_7MA2 0xD +#define ADF4377_CP_8MA6 0xE +#define ADF4377_CP_10MA1 0xF + +/* ADF4377 REG0016 Map */ +#define ADF4377_BLEED_I_MSB_MSK GENMASK(7, 0) + +/* ADF4377 REG0017 Map */ +#define ADF4377_INV_CLKOUT_MSK BIT(7) +#define ADF4377_N_DEL_MSK GENMASK(6, 0) + +/* ADF4377 REG0017 Bit Definition */ +#define ADF4377_CLKOUT_INV_DIS 0x0 +#define ADF4377_CLKOUT_INV_EN 0x1 + +/* ADF4377 REG0018 Map */ +#define ADF4377_CMOS_OV_MSK BIT(7) +#define ADF4377_R_DEL_MSK GENMASK(6, 0) + +/* ADF4377 REG0018 Bit Definition */ +#define ADF4377_1V8_LOGIC 0x0 +#define ADF4377_3V3_LOGIC 0x1 + +/* ADF4377 REG0019 Map */ +#define ADF4377_CLKOUT2_OP_MSK GENMASK(7, 6) +#define ADF4377_CLKOUT1_OP_MSK GENMASK(5, 4) +#define ADF4377_PD_CLK_MSK BIT(3) +#define ADF4377_PD_RDET_MSK BIT(2) +#define ADF4377_PD_ADC_MSK BIT(1) +#define ADF4377_PD_CALADC_MSK BIT(0) + +/* ADF4377 REG0019 Bit Definition */ +#define ADF4377_CLKOUT_320MV 0x0 +#define ADF4377_CLKOUT_420MV 0x1 +#define ADF4377_CLKOUT_530MV 0x2 +#define ADF4377_CLKOUT_640MV 0x3 + +#define ADF4377_PD_CLK_N_OP 0x0 +#define ADF4377_PD_CLK_PD 0x1 + +#define ADF4377_PD_RDET_N_OP 0x0 +#define ADF4377_PD_RDET_PD 0x1 + +#define ADF4377_PD_ADC_N_OP 0x0 +#define ADF4377_PD_ADC_PD 0x1 + +#define ADF4377_PD_CALADC_N_OP 0x0 +#define ADF4377_PD_CALADC_PD 0x1 + +/* ADF4377 REG001A Map */ +#define ADF4377_PD_ALL_MSK BIT(7) +#define ADF4377_PD_RDIV_MSK BIT(6) +#define ADF4377_PD_NDIV_MSK BIT(5) +#define ADF4377_PD_VCO_MSK BIT(4) +#define ADF4377_PD_LD_MSK BIT(3) +#define ADF4377_PD_PFDCP_MSK BIT(2) +#define ADF4377_PD_CLKOUT1_MSK BIT(1) +#define ADF4377_PD_CLKOUT2_MSK BIT(0) + +/* ADF4377 REG001A Bit Definition */ +#define ADF4377_PD_ALL_N_OP 0x0 +#define ADF4377_PD_ALL_PD 0x1 + +#define ADF4377_PD_RDIV_N_OP 0x0 +#define ADF4377_PD_RDIV_PD 0x1 + +#define ADF4377_PD_NDIV_N_OP 0x0 +#define ADF4377_PD_NDIV_PD 0x1 + +#define ADF4377_PD_VCO_N_OP 0x0 +#define ADF4377_PD_VCO_PD 0x1 + +#define ADF4377_PD_LD_N_OP 0x0 +#define ADF4377_PD_LD_PD 0x1 + +#define ADF4377_PD_PFDCP_N_OP 0x0 +#define ADF4377_PD_PFDCP_PD 0x1 + +#define ADF4377_PD_CLKOUT1_N_OP 0x0 +#define ADF4377_PD_CLKOUT1_PD 0x1 + +#define ADF4377_PD_CLKOUT2_N_OP 0x0 +#define ADF4377_PD_CLKOUT2_PD 0x1 + +/* ADF4377 REG001B Map */ +#define ADF4377_EN_LOL_MSK BIT(7) +#define ADF4377_LDWIN_PW_MSK BIT(6) +#define ADF4377_EN_LDWIN_MSK BIT(5) +#define ADF4377_LD_COUNT_MSK GENMASK(4, 0) + +/* ADF4377 REG001B Bit Definition */ +#define ADF4377_EN_LOL_DIS 0x0 +#define ADF4377_EN_LOL_EN 0x1 + +#define ADF4377_LDWIN_PW_NARROW 0x0 +#define ADF4377_LDWIN_PW_WIDE 0x1 + +#define ADF4377_EN_LDWIN_DIS 0x0 +#define ADF4377_EN_LDWIN_EN 0x1 + +/* ADF4377 REG001C Map */ +#define ADF4377_EN_DNCLK_MSK BIT(7) +#define ADF4377_EN_DRCLK_MSK BIT(6) +#define ADF4377_RST_LD_MSK BIT(2) +#define ADF4377_R01C_RSV1_MSK BIT(0) + +/* ADF4377 REG001C Bit Definition */ +#define ADF4377_EN_DNCLK_OFF 0x0 +#define ADF4377_EN_DNCLK_ON 0x1 + +#define ADF4377_EN_DRCLK_OFF 0x0 +#define ADF4377_EN_DRCLK_ON 0x1 + +#define ADF4377_RST_LD_INACTIVE 0x0 +#define ADF4377_RST_LD_ACTIVE 0x1 + +/* ADF4377 REG001D Map */ +#define ADF4377_MUXOUT_MSK GENMASK(7, 4) +#define ADF4377_EN_CPTEST_MSK BIT(2) +#define ADF4377_CP_DOWN_MSK BIT(1) +#define ADF4377_CP_UP_MSK BIT(0) + +#define ADF4377_EN_CPTEST_OFF 0x0 +#define ADF4377_EN_CPTEST_ON 0x1 + +#define ADF4377_CP_DOWN_OFF 0x0 +#define ADF4377_CP_DOWN_ON 0x1 + +#define ADF4377_CP_UP_OFF 0x0 +#define ADF4377_CP_UP_ON 0x1 + +/* ADF4377 REG001F Map */ +#define ADF4377_BST_REF_MSK BIT(7) +#define ADF4377_FILT_REF_MSK BIT(6) +#define ADF4377_REF_SEL_MSK BIT(5) +#define ADF4377_R01F_RSV1_MSK GENMASK(4, 0) + +/* ADF4377 REG001F Bit Definition */ +#define ADF4377_BST_LARGE_REF_IN 0x0 +#define ADF4377_BST_SMALL_REF_IN 0x1 + +#define ADF4377_FILT_REF_OFF 0x0 +#define ADF4377_FILT_REF_ON 0x1 + +#define ADF4377_REF_SEL_DMA 0x0 +#define ADF4377_REF_SEL_LNA 0x1 + +/* ADF4377 REG0020 Map */ +#define ADF4377_RST_SYS_MSK BIT(4) +#define ADF4377_EN_ADC_CLK_MSK BIT(3) +#define ADF4377_R020_RSV1_MSK BIT(0) + +/* ADF4377 REG0020 Bit Definition */ +#define ADF4377_RST_SYS_INACTIVE 0x0 +#define ADF4377_RST_SYS_ACTIVE 0x1 + +#define ADF4377_EN_ADC_CLK_DIS 0x0 +#define ADF4377_EN_ADC_CLK_EN 0x1 + +/* ADF4377 REG0021 Bit Definition */ +#define ADF4377_R021_RSV1 0xD3 + +/* ADF4377 REG0022 Bit Definition */ +#define ADF4377_R022_RSV1 0x32 + +/* ADF4377 REG0023 Map */ +#define ADF4377_CAT_CT_SEL BIT(7) +#define ADF4377_R023_RSV1_MSK GENMASK(6, 0) + +/* ADF4377 REG0023 Bit Definition */ +#define ADF4377_R023_RSV1 0x18 + +/* ADF4377 REG0024 Map */ +#define ADF4377_DCLK_MODE_MSK BIT(2) + +/* ADF4377 REG0024 Bit Definition */ +#define ADF4377_DCLK_MODE_DIS 0x0 +#define ADF4377_DCLK_MODE_EN 0x1 + +/* ADF4377 REG0025 Map */ +#define ADF4377_CLKODIV_DB_MSK BIT(7) +#define ADF4377_DCLK_DB_MSK BIT(6) +#define ADF4377_R025_RSV1_MSK GENMASK(5, 0) + +/* ADF4377 REG0025 Bit Definition */ +#define ADF4377_CLKODIV_DB_DIS 0x0 +#define ADF4377_CLKODIV_DB_EN 0x1 + +#define ADF4377_DCLK_DIV_DB_DIS 0x0 +#define ADF4377_DCLK_DIV_DB_EN 0x1 + +/* ADF4377 REG0026 Map */ +#define ADF4377_VCO_BAND_DIV_MSK GENMASK(7, 0) + +/* ADF4377 REG0027 Map */ +#define ADF4377_SYNTH_LOCK_TO_LSB_MSK GENMASK(7, 0) + +/* ADF4377 REG0028 Map */ +#define ADF4377_O_VCO_DB_MSK BIT(7) +#define ADF4377_SYNTH_LOCK_TO_MSB_MSK GENMASK(6, 0) + +/* ADF4377 REG0028 Bit Definition */ +#define ADF4377_O_VCO_DB_DIS 0x0 +#define ADF4377_O_VCO_DB_EN 0x1 + +/* ADF4377 REG0029 Map */ +#define ADF4377_VCO_ALC_TO_LSB_MSK GENMASK(7, 0) + +/* ADF4377 REG002A Map */ +#define ADF4377_DEL_CTRL_DB_MSK BIT(7) +#define ADF4377_VCO_ALC_TO_MSB_MSK GENMASK(6, 0) + +/* ADF4377 REG002A Bit Definition */ +#define ADF4377_DEL_CTRL_DB_DIS 0x0 +#define ADF4377_DEL_CTRL_DB_EN 0x1 + +/* ADF4377 REG002C Map */ +#define ADF4377_R02C_RSV1 0xC0 + +/* ADF4377 REG002D Map */ +#define ADF4377_ADC_CLK_DIV_MSK GENMASK(7, 0) + +/* ADF4377 REG002E Map */ +#define ADF4377_EN_ADC_CNV_MSK BIT(7) +#define ADF4377_EN_ADC_MSK BIT(1) +#define ADF4377_ADC_A_CONV_MSK BIT(0) + +/* ADF4377 REG002E Bit Definition */ +#define ADF4377_EN_ADC_CNV_DIS 0x0 +#define ADF4377_EN_ADC_CNV_EN 0x1 + +#define ADF4377_EN_ADC_DIS 0x0 +#define ADF4377_EN_ADC_EN 0x1 + +#define ADF4377_ADC_A_CONV_ADC_ST_CNV 0x0 +#define ADF4377_ADC_A_CONV_VCO_CALIB 0x1 + +/* ADF4377 REG002F Map */ +#define ADF4377_DCLK_DIV1_MSK GENMASK(1, 0) + +/* ADF4377 REG002F Bit Definition */ +#define ADF4377_DCLK_DIV1_1 0x0 +#define ADF4377_DCLK_DIV1_2 0x1 +#define ADF4377_DCLK_DIV1_8 0x2 +#define ADF4377_DCLK_DIV1_32 0x3 + +/* ADF4377 REG0031 Bit Definition */ +#define ADF4377_R031_RSV1 0x09 + +/* ADF4377 REG0032 Map */ +#define ADF4377_ADC_CLK_SEL_MSK BIT(6) +#define ADF4377_R032_RSV1_MSK GENMASK(5, 0) + +/* ADF4377 REG0032 Bit Definition */ +#define ADF4377_R032_RSV1 0x9 + +/* ADF4377 REG0032 Bit Definition */ +#define ADF4377_ADC_CLK_SEL_N_OP 0x0 +#define ADF4377_ADC_CLK_SEL_SPI_CLK 0x1 + +/* ADF4377 REG0033 Bit Definition */ +#define ADF4377_R033_RSV1 0x18 + +/* ADF4377 REG0034 Bit Definition */ +#define ADF4377_R034_RSV1 0x08 + +/* ADF4377 REG003A Bit Definition */ +#define ADF4377_R03A_RSV1 0x5C + +/* ADF4377 REG003B Bit Definition */ +#define ADF4377_R03B_RSV1 0x2B + +/* ADF4377 REG003D Map */ +#define ADF4377_O_VCO_BAND_MSK BIT(3) +#define ADF4377_O_VCO_CORE_MSK BIT(2) +#define ADF4377_O_VCO_BIAS_MSK BIT(1) + +/* ADF4377 REG003D Bit Definition */ +#define ADF4377_O_VCO_BAND_VCO_CALIB 0x0 +#define ADF4377_O_VCO_BAND_M_VCO 0x1 + +#define ADF4377_O_VCO_CORE_VCO_CALIB 0x0 +#define ADF4377_O_VCO_CORE_M_VCO 0x1 + +#define ADF4377_O_VCO_BIAS_VCO_CALIB 0x0 +#define ADF4377_O_VCO_BIAS_M_VCO 0x1 + +/* ADF4377 REG0042 Map */ +#define ADF4377_R042_RSV1 0x05 + +/* ADF4377 REG0045 Map */ +#define ADF4377_ADC_ST_CNV_MSK BIT(0) + +/* ADF4377 REG0045 Bit Definition */ +#define ADF4377_ADC_ST_ADC_DIS 0x0 +#define ADF4377_ADC_ST_ADC_EN 0x1 + +/* ADF4377 REG0049 Map */ +#define ADF4377_EN_CLK2_MSK BIT(7) +#define ADF4377_EN_CLK1_MSK BIT(6) +#define ADF4377_REF_OK_MSK BIT(3) +#define ADF4377_ADC_BUSY_MSK BIT(2) +#define ADF4377_FSM_BUSY_MSK BIT(1) +#define ADF4377_LOCKED_MSK BIT(0) + +/* ADF4377 REG004B Map */ +#define ADF4377_VCO_CORE_MSK GENMASK(1, 0) + +/* ADF4377 REG004C Map */ +#define ADF4377_CHIP_TEMP_LSB_MSK GENMASK(7, 0) + +/* ADF4377 REG004D Map */ +#define ADF4377_CHIP_TEMP_MSB_MSK BIT(0) + +/* ADF4377 REG004F Map */ +#define ADF4377_VCO_BAND_MSK GENMASK(7, 0) + +/* ADF4377 REG0051 Map */ +#define ADF4377_VCO_BIAS_MSK GENMASK(3, 0) + +/* ADF4377 REG0054 Map */ +#define ADF4377_CHIP_VERSION_MSK GENMASK(7, 0) + +/* Specifications */ +#define ADF4377_SPI_READ_CMD BIT(7) +#define ADF4377_MAX_VCO_FREQ 12800000000ULL +#define ADF4377_MIN_VCO_FREQ 6400000000ULL +#define ADF4377_MAX_REFIN_FREQ 1000000000 +#define ADF4377_MIN_REFIN_FREQ 10000000 +#define ADF4377_MAX_FREQ_PFD 500000000 +#define ADF4377_MIN_FREQ_PFD 3000000 +#define ADF4377_MAX_CLKPN_FREQ ADF4377_MAX_VCO_FREQ +#define ADF4377_MIN_CLKPN_FREQ (ADF4377_MIN_VCO_FREQ / 8) +#define ADF4377_FREQ_PFD_80MHZ 80000000 +#define ADF4377_FREQ_PFD_125MHZ 125000000 +#define ADF4377_FREQ_PFD_160MHZ 160000000 +#define ADF4377_FREQ_PFD_250MHZ 250000000 +#define ADF4377_FREQ_PFD_320MHZ 320000000 + +enum adf4377_dev_type { + ADF4377, + ADF4378, +}; + +enum { + ADF4377_FREQ, +}; + +enum muxout_select_modes { + ADF4377_MUXOUT_HIGH_Z = 0x0, + ADF4377_MUXOUT_LKDET = 0x1, + ADF4377_MUXOUT_LOW = 0x2, + ADF4377_MUXOUT_DIV_RCLK_2 = 0x4, + ADF4377_MUXOUT_DIV_NCLK_2 = 0x5, + ADF4377_MUXOUT_HIGH = 0x8, +}; + +struct adf4377_state { + struct spi_device *spi; + enum adf4377_dev_type type; + struct regmap *regmap; + struct clk *clkin; + /* Protect against concurrent accesses to the device and data content */ + struct mutex lock; + struct notifier_block nb; + /* Reference Divider */ + unsigned int ref_div_factor; + /* PFD Frequency */ + unsigned int f_pfd; + /* Input Reference Clock */ + unsigned int clkin_freq; + /* CLKOUT Divider */ + u8 clkout_div_sel; + /* Feedback Divider (N) */ + u16 n_int; + u16 synth_lock_timeout; + u16 vco_alc_timeout; + u16 adc_clk_div; + u16 vco_band_div; + u8 dclk_div1; + u8 dclk_div2; + u8 dclk_mode; + unsigned int f_div_rclk; + struct gpio_desc *gpio_ce; + struct gpio_desc *gpio_enclk1; + struct gpio_desc *gpio_enclk2; + u8 buf[2] ____cacheline_aligned; +}; + +static const char * const adf4377_muxout_modes[] = { + [ADF4377_MUXOUT_HIGH_Z] = "high_z", + [ADF4377_MUXOUT_LKDET] = "lock_detect", + [ADF4377_MUXOUT_LOW] = "muxout_low", + [ADF4377_MUXOUT_DIV_RCLK_2] = "f_div_rclk_2", + [ADF4377_MUXOUT_DIV_NCLK_2] = "f_div_nclk_2", + [ADF4377_MUXOUT_HIGH] = "muxout_high", +}; + +static const struct regmap_config adf4377_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .read_flag_mask = BIT(7), + .max_register = 0x54, +}; + +static int adf4377_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int write_val, + unsigned int *read_val) +{ + struct adf4377_state *st = iio_priv(indio_dev); + + if (read_val) + return regmap_read(st->regmap, reg, read_val); + + return regmap_write(st->regmap, reg, write_val); +} + +static const struct iio_info adf4377_info = { + .debugfs_reg_access = &adf4377_reg_access, +}; + +static int adf4377_soft_reset(struct adf4377_state *st) +{ + unsigned int read_val; + int ret; + + ret = regmap_update_bits(st->regmap, 0x0, ADF4377_SOFT_RESET_MSK | + ADF4377_SOFT_RESET_R_MSK, + FIELD_PREP(ADF4377_SOFT_RESET_MSK, 1) | + FIELD_PREP(ADF4377_SOFT_RESET_R_MSK, 1)); + if (ret) + return ret; + + return regmap_read_poll_timeout(st->regmap, 0x0, read_val, + !(read_val & (ADF4377_SOFT_RESET_R_MSK | + ADF4377_SOFT_RESET_R_MSK)), 200, 200 * 100); +} + +static int adf4377_set_default(struct adf4377_state *st) +{ + int ret; + + /* Set default registers bits */ + ret = regmap_write(st->regmap, 0x0f, + FIELD_PREP(ADF4377_R00F_RSV1_MSK, 0x14)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x1c, ADF4377_R01C_RSV1_MSK, + FIELD_PREP(ADF4377_R01C_RSV1_MSK, 0x1)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x1f, ADF4377_R01F_RSV1_MSK, + FIELD_PREP(ADF4377_R01F_RSV1_MSK, 0x7)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x20, ADF4377_R020_RSV1_MSK, + FIELD_PREP(ADF4377_R020_RSV1_MSK, 0x1)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x21, ADF4377_R021_RSV1); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x22, ADF4377_R022_RSV1); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x23, ADF4377_R023_RSV1); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x25, ADF4377_R025_RSV1_MSK, + FIELD_PREP(ADF4377_R025_RSV1_MSK, 0x16)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x2C, ADF4377_R02C_RSV1); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x31, ADF4377_R031_RSV1); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x32, ADF4377_R032_RSV1_MSK, + FIELD_PREP(ADF4377_R032_RSV1_MSK, 0x9)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x33, ADF4377_R033_RSV1); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x34, ADF4377_R034_RSV1); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x3A, ADF4377_R03A_RSV1); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x3B, ADF4377_R03B_RSV1); + if (ret) + return ret; + + return regmap_write(st->regmap, 0x42, ADF4377_R042_RSV1); +} + +int adf4377_get_freq(struct adf4377_state *st, u64 *freq) +{ + unsigned int ref_div_factor, n_int; + u64 clkin_freq; + int ret; + + mutex_lock(&st->lock); + ret = regmap_read(st->regmap, 0x12, &ref_div_factor); + if (ret) + goto exit; + + ret = regmap_bulk_read(st->regmap, 0x10, st->buf, sizeof(st->buf)); + if (ret) + goto exit; + + clkin_freq = clk_get_rate(st->clkin); + ref_div_factor = FIELD_GET(ADF4377_R_DIV_MSK, ref_div_factor); + n_int = FIELD_GET(ADF4377_N_INT_LSB_MSK, st->buf[0]) | + (FIELD_GET(ADF4377_N_INT_MSB_MSK, st->buf[1]) << 8); + + *freq = div_u64(clkin_freq, ref_div_factor) * n_int; +exit: + mutex_unlock(&st->lock); + + return ret; +} + +int adf4377_set_freq(struct adf4377_state *st, u64 freq) +{ + unsigned int read_val; + u64 f_vco; + int ret; + + ret = regmap_update_bits(st->regmap, 0x1C, ADF4377_EN_DNCLK_MSK | ADF4377_EN_DRCLK_MSK, + FIELD_PREP(ADF4377_EN_DNCLK_MSK, ADF4377_EN_DNCLK_ON) | + FIELD_PREP(ADF4377_EN_DRCLK_MSK, ADF4377_EN_DRCLK_ON)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x11, ADF4377_EN_AUTOCAL_MSK | ADF4377_DCLK_DIV2_MSK, + FIELD_PREP(ADF4377_EN_AUTOCAL_MSK, ADF4377_VCO_CALIB_EN) | + FIELD_PREP(ADF4377_DCLK_DIV2_MSK, st->dclk_div2)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x2E, ADF4377_EN_ADC_CNV_MSK | ADF4377_EN_ADC_MSK | + ADF4377_ADC_A_CONV_MSK, + FIELD_PREP(ADF4377_EN_ADC_CNV_MSK, ADF4377_EN_ADC_CNV_EN) | + FIELD_PREP(ADF4377_EN_ADC_MSK, ADF4377_EN_ADC_EN) | + FIELD_PREP(ADF4377_ADC_A_CONV_MSK, ADF4377_ADC_A_CONV_VCO_CALIB)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x20, ADF4377_EN_ADC_CLK_MSK, + FIELD_PREP(ADF4377_EN_ADC_CLK_MSK, ADF4377_EN_ADC_CLK_EN)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x2F, ADF4377_DCLK_DIV1_MSK, + FIELD_PREP(ADF4377_DCLK_DIV1_MSK, st->dclk_div1)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x24, ADF4377_DCLK_MODE_MSK, + FIELD_PREP(ADF4377_DCLK_MODE_MSK, st->dclk_mode)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x27, + FIELD_PREP(ADF4377_SYNTH_LOCK_TO_LSB_MSK, st->synth_lock_timeout)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x28, ADF4377_SYNTH_LOCK_TO_MSB_MSK, + FIELD_PREP(ADF4377_SYNTH_LOCK_TO_MSB_MSK, + st->synth_lock_timeout >> 8)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x29, + FIELD_PREP(ADF4377_VCO_ALC_TO_LSB_MSK, st->vco_alc_timeout)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x2A, ADF4377_VCO_ALC_TO_MSB_MSK, + FIELD_PREP(ADF4377_VCO_ALC_TO_MSB_MSK, st->vco_alc_timeout >> 8)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x26, + FIELD_PREP(ADF4377_VCO_BAND_DIV_MSK, st->vco_band_div)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x2D, + FIELD_PREP(ADF4377_ADC_CLK_DIV_MSK, st->adc_clk_div)); + if (ret) + return ret; + + st->clkout_div_sel = 0; + + if (freq > ADF4377_MAX_CLKPN_FREQ || freq < ADF4377_MIN_CLKPN_FREQ) { + ret = -EINVAL; + return ret; + } + + f_vco = freq; + + while (f_vco < ADF4377_MIN_VCO_FREQ) { + f_vco <<= 1; + st->clkout_div_sel++; + } + + st->n_int = div_u64(freq, st->f_pfd); + + ret = regmap_update_bits(st->regmap, 0x11, ADF4377_EN_RDBLR_MSK | ADF4377_N_INT_MSB_MSK, + FIELD_PREP(ADF4377_EN_RDBLR_MSK, ADF4377_REF_DBLR_DIS) | + FIELD_PREP(ADF4377_N_INT_MSB_MSK, st->n_int >> 8)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x12, ADF4377_R_DIV_MSK | ADF4377_CLKOUT_DIV_MSK, + FIELD_PREP(ADF4377_CLKOUT_DIV_MSK, st->clkout_div_sel) | + FIELD_PREP(ADF4377_R_DIV_MSK, st->ref_div_factor)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, 0x10, + FIELD_PREP(ADF4377_N_INT_LSB_MSK, st->n_int)); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(st->regmap, 0x49, read_val, + !(read_val & (ADF4377_FSM_BUSY_MSK)), 200, 200 * 100); + if (ret) + return ret; + + /* Disable EN_DNCLK, EN_DRCLK */ + ret = regmap_update_bits(st->regmap, 0x1C, ADF4377_EN_DNCLK_MSK | ADF4377_EN_DRCLK_MSK, + FIELD_PREP(ADF4377_EN_DNCLK_MSK, ADF4377_EN_DNCLK_OFF) | + FIELD_PREP(ADF4377_EN_DRCLK_MSK, ADF4377_EN_DRCLK_OFF)); + if (ret) + return ret; + + /* Disable EN_ADC_CLK */ + ret = regmap_update_bits(st->regmap, 0x20, ADF4377_EN_ADC_CLK_MSK, + FIELD_PREP(ADF4377_EN_ADC_CLK_MSK, ADF4377_EN_ADC_CLK_DIS)); + if (ret) + return ret; + + /* Set output Amplitude */ + return regmap_update_bits(st->regmap, 0x19, ADF4377_CLKOUT2_OP_MSK | ADF4377_CLKOUT1_OP_MSK, + FIELD_PREP(ADF4377_CLKOUT1_OP_MSK, ADF4377_CLKOUT_420MV) | + FIELD_PREP(ADF4377_CLKOUT2_OP_MSK, ADF4377_CLKOUT_420MV)); +} + +static void adf4377_gpio_init(struct adf4377_state *st) +{ + if (st->gpio_ce) + gpiod_set_value(st->gpio_ce, 1); + + if (st->gpio_enclk1) + gpiod_set_value(st->gpio_enclk1, 1); + + if (st->gpio_enclk2 && st->type == ADF4377) + gpiod_set_value(st->gpio_enclk2, 1); +} + +static int adf4377_init(struct adf4377_state *st) +{ + int ret; + + /* GPIO Inititalization */ + adf4377_gpio_init(st); + + /* Software reset */ + ret = adf4377_soft_reset(st); + if (ret) + return ret; + + /* Set Default Registers */ + ret = adf4377_set_default(st); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x15, ADF4377_CP_I_MSK, + FIELD_PREP(ADF4377_CP_I_MSK, ADF4377_CP_10MA1)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, 0x00, + ADF4377_SDO_ACTIVE_MSK | ADF4377_SDO_ACTIVE_R_MSK, + FIELD_PREP(ADF4377_SDO_ACTIVE_MSK, ADF4377_SDO_ACTIVE_SPI_4W) | + FIELD_PREP(ADF4377_SDO_ACTIVE_R_MSK, ADF4377_SDO_ACTIVE_SPI_4W)); + if (ret) + return ret; + + st->clkin_freq = clk_get_rate(st->clkin); + + /* Power Up */ + ret = regmap_write(st->regmap, 0x1a, + FIELD_PREP(ADF4377_PD_ALL_MSK, ADF4377_PD_ALL_N_OP) | + FIELD_PREP(ADF4377_PD_RDIV_MSK, ADF4377_PD_RDIV_N_OP) | + FIELD_PREP(ADF4377_PD_NDIV_MSK, ADF4377_PD_NDIV_N_OP) | + FIELD_PREP(ADF4377_PD_VCO_MSK, ADF4377_PD_VCO_N_OP) | + FIELD_PREP(ADF4377_PD_LD_MSK, ADF4377_PD_LD_N_OP) | + FIELD_PREP(ADF4377_PD_PFDCP_MSK, ADF4377_PD_PFDCP_N_OP) | + FIELD_PREP(ADF4377_PD_CLKOUT1_MSK, ADF4377_PD_CLKOUT1_N_OP) | + FIELD_PREP(ADF4377_PD_CLKOUT2_MSK, ADF4377_PD_CLKOUT2_N_OP)); + if (ret) + return ret; + + /* Compute PFD */ + st->ref_div_factor = 0; + do { + st->ref_div_factor++; + st->f_pfd = st->clkin_freq / st->ref_div_factor; + } while (st->f_pfd > ADF4377_MAX_FREQ_PFD); + + if (st->f_pfd > ADF4377_MAX_FREQ_PFD || st->f_pfd < ADF4377_MIN_FREQ_PFD) + return -EINVAL; + + st->f_div_rclk = st->f_pfd; + + if (st->f_pfd <= ADF4377_FREQ_PFD_80MHZ) { + st->dclk_div1 = ADF4377_DCLK_DIV1_1; + st->dclk_div2 = ADF4377_DCLK_DIV2_1; + st->dclk_mode = ADF4377_DCLK_MODE_DIS; + } else if (st->f_pfd <= ADF4377_FREQ_PFD_125MHZ) { + st->dclk_div1 = ADF4377_DCLK_DIV1_1; + st->dclk_div2 = ADF4377_DCLK_DIV2_1; + st->dclk_mode = ADF4377_DCLK_MODE_EN; + } else if (st->f_pfd <= ADF4377_FREQ_PFD_160MHZ) { + st->dclk_div1 = ADF4377_DCLK_DIV1_2; + st->dclk_div2 = ADF4377_DCLK_DIV2_1; + st->dclk_mode = ADF4377_DCLK_MODE_DIS; + st->f_div_rclk /= 2; + } else if (st->f_pfd <= ADF4377_FREQ_PFD_250MHZ) { + st->dclk_div1 = ADF4377_DCLK_DIV1_2; + st->dclk_div2 = ADF4377_DCLK_DIV2_1; + st->dclk_mode = ADF4377_DCLK_MODE_EN; + st->f_div_rclk /= 2; + } else if (st->f_pfd <= ADF4377_FREQ_PFD_320MHZ) { + st->dclk_div1 = ADF4377_DCLK_DIV1_2; + st->dclk_div2 = ADF4377_DCLK_DIV2_2; + st->dclk_mode = ADF4377_DCLK_MODE_DIS; + st->f_div_rclk /= 4; + } else { + st->dclk_div1 = ADF4377_DCLK_DIV1_2; + st->dclk_div2 = ADF4377_DCLK_DIV2_2; + st->dclk_mode = ADF4377_DCLK_MODE_EN; + st->f_div_rclk /= 4; + } + + st->synth_lock_timeout = DIV_ROUND_UP(st->f_div_rclk, 50000); + st->vco_alc_timeout = DIV_ROUND_UP(st->f_div_rclk, 20000); + st->vco_band_div = DIV_ROUND_UP(st->f_div_rclk, 150000 * 16 * (1 << st->dclk_mode)); + st->adc_clk_div = DIV_ROUND_UP((st->f_div_rclk / 400000 - 2), 4); + + return 0; +} + +static ssize_t adf4377_read(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + struct adf4377_state *st = iio_priv(indio_dev); + u64 val = 0; + int ret; + + switch ((u32)private) { + case ADF4377_FREQ: + ret = adf4377_get_freq(st, &val); + break; + default: + ret = -EINVAL; + val = 0; + break; + } + + return ret ?: sysfs_emit(buf, "%llu\n", val); +} + +static ssize_t adf4377_write(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, const char *buf, + size_t len) +{ + struct adf4377_state *st = iio_priv(indio_dev); + unsigned long long freq; + int ret; + + mutex_lock(&st->lock); + switch ((u32)private) { + case ADF4377_FREQ: + ret = kstrtoull(buf, 10, &freq); + if (ret) + break; + + ret = adf4377_set_freq(st, freq); + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static int adf4377_set_muxout_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct adf4377_state *st = iio_priv(indio_dev); + + return regmap_update_bits(st->regmap, 0x1D, + ADF4377_MUXOUT_MSK, + FIELD_PREP(ADF4377_MUXOUT_MSK, mode)); +} + +static int adf4377_get_muxout_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct adf4377_state *st = iio_priv(indio_dev); + unsigned int mode; + int ret; + + ret = regmap_read(st->regmap, 0x1D, &mode); + + return ret ? : FIELD_GET(ADF4377_MUXOUT_MSK, mode); +} + +static const struct iio_enum adf4377_muxout_enum = { + .items = adf4377_muxout_modes, + .num_items = ARRAY_SIZE(adf4377_muxout_modes), + .get = adf4377_get_muxout_mode, + .set = adf4377_set_muxout_mode, +}; + +#define _ADF4377_EXT_INFO(_name, _shared, _ident) { \ + .name = _name, \ + .read = adf4377_read, \ + .write = adf4377_write, \ + .private = _ident, \ + .shared = _shared, \ + } + +static const struct iio_chan_spec_ext_info adf4377_ext_info[] = { + /* + * Usually we use IIO_CHAN_INFO_FREQUENCY, but there are + * values > 2^32 in order to support the entire frequency range + * in Hz. + */ + _ADF4377_EXT_INFO("frequency", IIO_SHARED_BY_ALL, ADF4377_FREQ), + IIO_ENUM("muxout_select", IIO_SHARED_BY_ALL, &adf4377_muxout_enum), + IIO_ENUM_AVAILABLE_SHARED("muxout_select", IIO_SHARED_BY_ALL, &adf4377_muxout_enum), + { }, +}; + +static const struct iio_chan_spec adf4377_channels[] = { + { + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .output = 1, + .channel = 0, + .ext_info = adf4377_ext_info, + }, +}; + +static int adf4377_properties_parse(struct adf4377_state *st) +{ + struct spi_device *spi = st->spi; + + st->clkin = devm_clk_get(&spi->dev, "ref_in"); + if (IS_ERR(st->clkin)) + return dev_err_probe(&spi->dev, PTR_ERR(st->clkin), + "failed to get the reference input clock\n"); + + st->gpio_ce = devm_gpiod_get_optional(&st->spi->dev, "ce-en", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_ce)) + return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_ce), + "failed to get the CE GPIO\n"); + + st->gpio_enclk1 = devm_gpiod_get_optional(&st->spi->dev, "enclk1", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_enclk1)) + return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_enclk1), + "failed to get the CE GPIO\n"); + + if (st->type == ADF4377) { + st->gpio_enclk2 = devm_gpiod_get_optional(&st->spi->dev, "enclk2", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_enclk2)) + return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_enclk2), + "failed to get the CE GPIO\n"); + } + + return 0; +} + +static int adf4377_freq_change(struct notifier_block *nb, unsigned long action, void *data) +{ + struct adf4377_state *st = container_of(nb, struct adf4377_state, nb); + int ret; + + if (action == POST_RATE_CHANGE) { + mutex_lock(&st->lock); + ret = notifier_from_errno(adf4377_init(st)); + mutex_unlock(&st->lock); + return ret; + } + + return NOTIFY_OK; +} + +static void adf4377_clk_disable(void *data) +{ + clk_disable_unprepare(data); +} + +static void adf4377_clk_notifier_unreg(void *data) +{ + struct adf4377_state *st = data; + + clk_notifier_unregister(st->clkin, &st->nb); +} + +static int adf4377_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct regmap *regmap; + struct adf4377_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + regmap = devm_regmap_init_spi(spi, &adf4377_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + st = iio_priv(indio_dev); + + indio_dev->info = &adf4377_info; + indio_dev->name = "adf4377"; + indio_dev->channels = adf4377_channels; + indio_dev->num_channels = ARRAY_SIZE(adf4377_channels); + + st->regmap = regmap; + st->spi = spi; + st->type = spi_get_device_id(spi)->driver_data; + mutex_init(&st->lock); + + ret = adf4377_properties_parse(st); + if (ret) + return ret; + + ret = clk_prepare_enable(st->clkin); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&spi->dev, adf4377_clk_disable, st->clkin); + if (ret) + return ret; + + st->nb.notifier_call = adf4377_freq_change; + ret = clk_notifier_register(st->clkin, &st->nb); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&spi->dev, adf4377_clk_notifier_unreg, st); + if (ret) + return ret; + + ret = adf4377_init(st); + if (ret) { + dev_err(&spi->dev, "adf4377 init failed\n"); + return ret; + } + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct spi_device_id adf4377_id[] = { + { "adf4377", ADF4377 }, + { "adf4378", ADF4378 }, + {}, +}; +MODULE_DEVICE_TABLE(spi, adf4377_id); + +static const struct of_device_id adf4377_of_match[] = { + { .compatible = "adi,adf4377" }, + { .compatible = "adi,adf4378" }, + {}, +}; +MODULE_DEVICE_TABLE(of, adf4377_of_match); + +static struct spi_driver adf4377_driver = { + .driver = { + .name = "adf4377", + .of_match_table = adf4377_of_match, + }, + .probe = adf4377_probe, + .id_table = adf4377_id, +}; +module_spi_driver(adf4377_driver); + +MODULE_AUTHOR("Antoniu Miclaus "); +MODULE_AUTHOR("Dragos Bogdan "); +MODULE_DESCRIPTION("Analog Devices ADF4377"); +MODULE_LICENSE("GPL v2"); From ebe8136507f108da222dcbf6a1567eb9338f0925 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 28 Mar 2022 13:30:52 +0300 Subject: [PATCH 291/407] iio: frequency: adf4377: Add sysfs ABI doc Add initial ABI documentation for adf4377 frequency sysfs interface. Signed-off-by: Antoniu Miclaus --- .../testing/sysfs-bus-iio-frequency-adf4377 | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4377 diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4377 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4377 new file mode 100644 index 00000000000000..0324de5c932830 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4377 @@ -0,0 +1,32 @@ +What: /sys/bus/iio/devices/iio:deviceX/frequency +KernelVersion: +Contact: linux-iio@vger.kernel.org +Description: + Stores the PLL frequency in Hz for output channels. + Reading returns the frequency in Hz. + +What: /sys/bus/iio/devices/iio:deviceX/muxout_select +KernelVersion: +Contact: linux-iio@vger.kernel.org +Description: + The mux output allows the user to access various internal points on + the chip. Valid values that can be written are: + * high_z -> high impedance output + * lock_detect -> digital lock detector output + * muxout_low -> low output + * f_div_rclk_2 -> fdiv_rclk/2 + * f_div_nclk_2 -> fdiv_nclk/2 + * muxout_high -> high output + +What: /sys/bus/iio/devices/iio:deviceX/muxout_select_available +KernelVersion: +Contact: linux-iio@vger.kernel.org +Description: + Reading this returns the valid values that can be written to the + muxout_mode attribute: + * high_z + * lock_detect + * muxout_low + * f_div_rclk_2 + * f_div_nclk_2 + * muxout_high From 976df57b21a95a7383801db994bb4c2d631612e4 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 28 Mar 2022 13:37:18 +0300 Subject: [PATCH 292/407] drivers: iio: Kconfig.adi: add ADF4377 Add ADF4377 to the IIO_ALL_ADI_DRIVERS kconfig. Signed-off-by: Antoniu Miclaus --- drivers/iio/Kconfig.adi | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/Kconfig.adi b/drivers/iio/Kconfig.adi index 74652d77191850..350a44675af2a2 100644 --- a/drivers/iio/Kconfig.adi +++ b/drivers/iio/Kconfig.adi @@ -111,6 +111,7 @@ config IIO_ALL_ADI_DRIVERS select ADF4350 select ADF4360 select ADF4371 + select ADF4377 select ADF5355 select ADL5960 select ADMV1013 From bac8254d25c080cd05a71a8b25670428239de310 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 6 Apr 2022 12:05:19 +0300 Subject: [PATCH 293/407] arch: arm: dts: add zed dts for eval adf4377 Add device tree example for the EVAL-ADF4377 board with zed carrier. Signed-off-by: Antoniu Miclaus --- .../arm/boot/dts/zynq-zed-adv7511-adf4377.dts | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 arch/arm/boot/dts/zynq-zed-adv7511-adf4377.dts diff --git a/arch/arm/boot/dts/zynq-zed-adv7511-adf4377.dts b/arch/arm/boot/dts/zynq-zed-adv7511-adf4377.dts new file mode 100644 index 00000000000000..e4dfb9e8e666e7 --- /dev/null +++ b/arch/arm/boot/dts/zynq-zed-adv7511-adf4377.dts @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices ADF4377 + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-frequency/adf4377 + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2022 Analog Devices Inc. + */ +/dts-v1/; + +#include "zynq-zed.dtsi" +#include "zynq-zed-adv7511.dtsi" +#include + +/ { + clocks { + adf4377_clkin: clock@0 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <100000000>; + }; + }; +}; + +&spi0 { + status = "okay"; + + adf4377: frequency@0 { + compatible = "adi,adf4377"; + reg = <0>; + spi-max-frequency = <1000000>; + + ce-en-gpios = <&gpio0 89 GPIO_ACTIVE_HIGH>; + enclk1-gpios = <&gpio0 90 GPIO_ACTIVE_HIGH>; + enclk2-gpios = <&gpio0 88 GPIO_ACTIVE_HIGH>; + + clocks = <&adf4377_clkin>; + clock-names = "ref_in"; + }; +}; From 12fec242eaf8f3f86aad8577fbb2244b80d909df Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 24 Mar 2022 08:47:27 +0100 Subject: [PATCH 294/407] dts: vcu118_quad_ad9081_204b_txmode_5_rxmode_6: New M4, L2 8B10B mode This setup assumes 500MHz clock into J41 (0 dBm) ad9081_204b_txmode_5_rxmode_6: Np 16 use case with low lane rate * 2Txs / 2Rxs per MxFE * DAC_CLK = 4GSPS * ADC_CLK = 4GSPS * Tx I/Q Rate: 125 MSPS (Interpolation of 4x8) * Rx I/Q Rate: 125 MSPS (Decimation of 4x8) * DAC JESD204B: Mode 5, L=2, M=4, N=N'=16 * ADC JESD204B: Mode 6, L=2, M=4, N=N'=16 * DAC-Side JESD204B Lane Rate: 5.00Gbps * ADC-Side JESD204B Lane Rate: 5.00Gbps Signed-off-by: Michael Hennerich --- ...118_quad_ad9081_204b_txmode_5_rxmode_6.dts | 722 ++++++++++++++++++ ...204b_txmode_5_rxmode_6_onchip_pll_revc.dts | 94 +++ ..._txmode_5_rxmode_6_onchip_pll_revc_nz1.dts | 28 + ...uad_ad9081_204b_txmode_5_rxmode_6_revc.dts | 155 ++++ 4 files changed, 999 insertions(+) create mode 100644 arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6.dts create mode 100644 arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_onchip_pll_revc.dts create mode 100644 arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_onchip_pll_revc_nz1.dts create mode 100644 arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_revc.dts diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6.dts new file mode 100644 index 00000000000000..ae4271f342aed4 --- /dev/null +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6.dts @@ -0,0 +1,722 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices Quad-MxFE + * https://wiki.analog.com/resources/eval/user-guides/quadmxfe + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 + * https://wiki.analog.com/resources/eval/user-guides/ad_quadmxfe1_ebz/ad_quadmxfe1_ebz_hdl + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2022 Analog Devices Inc. + */ + +#include +#include +#include + +#include "vcu118_quad_ad9081.dtsi" + +// This setup assumes 500MHz clock into J41 (0 dBm) +// ad9081_204b_txmode_5_rxmode_6: Np 16 use case with low lane rate +// * 2Txs / 2Rxs per MxFE +// * DAC_CLK = 4GSPS +// * ADC_CLK = 4GSPS +// * Tx I/Q Rate: 125 MSPS (Interpolation of 4x8) +// * Rx I/Q Rate: 125 MSPS (Decimation of 4x8) +// * DAC JESD204B: Mode 5, L=2, M=4, N=N'=16 +// * ADC JESD204B: Mode 6, L=2, M=4, N=N'=16 +// * DAC-Side JESD204B Lane Rate: 5.00Gbps +// * ADC-Side JESD204B Lane Rate: 5.00Gbps + +#define ADRF4360_RFx_FREQUENCY_HZ 4000000000 + +#define HMC7043_FPGA_XCVR_CLKDIV 2 +#define HMC7043_FPGA_LINK_CLKDIV 4 +#define HMC7043_SYSREF_CLKDIV 256 +#define HMC7043_SYSREF_TIMER (HMC7043_SYSREF_CLKDIV * 4) + +#define AD9081_DAC_FREQUENCY ADRF4360_RFx_FREQUENCY_HZ +#define AD9081_ADC_FREQUENCY ADRF4360_RFx_FREQUENCY_HZ + + /* TX path */ +#define AD9081_TX_MAIN_INTERPOLATION 4 +#define AD9081_TX_CHAN_INTERPOLATION 8 + +#ifndef AD9081_TX_MAIN_NCO_SHIFT +#define AD9081_TX_MAIN_NCO_SHIFT 433000000 +#endif +#ifndef AD9081_TX_CHAN_NCO_SHIFT +#define AD9081_TX_CHAN_NCO_SHIFT 0 +#endif + +#define AD9081_GAIN 2048 + +#define AD9081_TX_JESD_MODE 5 +#define AD9081_TX_JESD_SUBCLASS 1 +#define AD9081_TX_JESD_VERSION 1 +#define AD9081_TX_JESD_M 4 +#define AD9081_TX_JESD_F 4 +#define AD9081_TX_JESD_K 32 +#define AD9081_TX_JESD_N 16 +#define AD9081_TX_JESD_NP 16 +#define AD9081_TX_JESD_CS 0 +#define AD9081_TX_JESD_L 2 +#define AD9081_TX_JESD_S 1 +#define AD9081_TX_JESD_HD 0 + +/* RX path */ +#define AD9081_RX_MAIN_DECIMATION 4 +#define AD9081_RX_CHAN_DECIMATION 8 + +#ifndef AD9081_RX_MAIN_NCO_SHIFT +#define AD9081_RX_MAIN_NCO_SHIFT 433000000 +#endif +#ifndef AD9081_RX_CHAN_NCO_SHIFT +#define AD9081_RX_CHAN_NCO_SHIFT 0 +#endif + +#ifndef AD9081_ADC_NYQUIST_ZONE +#define AD9081_ADC_NYQUIST_ZONE AD9081_ADC_NYQUIST_ZONE_EVEN +#endif + +#define AD9081_RX_JESD_MODE 6 +#define AD9081_RX_JESD_SUBCLASS 1 +#define AD9081_RX_JESD_VERSION 1 +#define AD9081_RX_JESD_M 4 +#define AD9081_RX_JESD_F 4 +#define AD9081_RX_JESD_K 32 +#define AD9081_RX_JESD_N 16 +#define AD9081_RX_JESD_NP 16 +#define AD9081_RX_JESD_CS 0 +#define AD9081_RX_JESD_L 2 +#define AD9081_RX_JESD_S 1 +#define AD9081_RX_JESD_HD 0 + +&axi_ad9081_adxcvr_rx { + adi,sys-clk-select = ; + adi,out-clk-select = ; +}; + +&axi_ad9081_adxcvr_tx { + adi,sys-clk-select = ; + adi,out-clk-select = ; +}; + +&axi_gpio { + /delete-node/ adrf5020_ctrl; + adrf5020_ctrl { + gpio-hog; + gpios = <34 GPIO_ACTIVE_HIGH>; +#if ADRF4360_RFx_FREQUENCY_HZ < 8000000000 +#define ADF4371_OUTPUT 1 + output-low; /* output-low for the RF2 <-> clk-rfaux8 output */ +#else +#define ADF4371_OUTPUT 2 + output-high; /* output-high for the RF2 <-> clk-rf16 output */ +#endif + line-name = "ADRF5020_CTRL"; + }; +}; + +&adf4371_clk0 { + channel@ADF4371_OUTPUT { + reg = ; + adi,power-up-frequency = /bits/ 64 ; + }; +}; + +&adf4371_clk1 { + channel@ADF4371_OUTPUT { + reg = ; + adi,power-up-frequency = /bits/ 64 ; + }; +}; + +&adf4371_clk2 { + channel@ADF4371_OUTPUT { + reg = ; + adi,power-up-frequency = /bits/ 64 ; + }; +}; + +&adf4371_clk3 { + channel@ADF4371_OUTPUT { + reg = ; + adi,power-up-frequency = /bits/ 64 ; + }; +}; + +&hmc7043 { + hmc7043_c0: channel@0 { + reg = <0>; + adi,extended-name = "FPGA_REFCLK"; + adi,divider = ; + adi,driver-mode = ; + }; + hmc7043_c8: channel@8 { + reg = <8>; + adi,extended-name = "CORE_LINK_CLK"; + adi,divider = ; + adi,driver-mode = ; + }; + hmc7043_c1: channel@1 { + reg = <1>; + adi,extended-name = "SYSREF_MXFE0"; + adi,divider = ; + adi,driver-mode = ; + adi,coarse-digital-delay = <0>; + adi,fine-analog-delay = <24>; /* max analog */ + adi,output-mux-mode = <1>; + adi,jesd204-sysref-chan; + }; + hmc7043_c3: channel@3 { + reg = <3>; + adi,extended-name = "SYSREF_MXFE1"; + adi,divider = ; + adi,driver-mode = ; + adi,coarse-digital-delay = <1>; /* 1 ns */ + adi,fine-analog-delay = <0>; + adi,output-mux-mode = <0>; + adi,jesd204-sysref-chan; + }; + hmc7043_c5: channel@5 { + reg = <5>; + adi,extended-name = "SYSREF_MXFE2"; + adi,divider = ; + adi,driver-mode = ; + adi,coarse-digital-delay = <0>; + adi,fine-analog-delay = <16>; + adi,output-mux-mode = <1>; + adi,jesd204-sysref-chan; + }; + hmc7043_c7: channel@7 { + reg = <7>; + adi,extended-name = "SYSREF_MXFE3"; + adi,divider = ; + adi,driver-mode = ; + adi,coarse-digital-delay = <0>; + adi,fine-analog-delay = <0>; + adi,output-mux-mode = <0>; + adi,jesd204-sysref-chan; + }; + hmc7043_c9: channel@9 { + reg = <9>; + adi,extended-name = "SYSREF_FPGA"; + adi,divider = ; + adi,driver-mode = ; + adi,jesd204-sysref-chan; + }; +}; + +&trx0_ad9081 { + clocks = <&adf4371_clk0 ADF4371_OUTPUT>; + + adi,tx-dacs { + #size-cells = <0>; + #address-cells = <1>; + adi,dac-frequency-hz = /bits/ 64 ; + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = ; + trx0_ad9081_dac0: dac@0 { + reg = <0>; + adi,crossbar-select = <&trx0_ad9081_tx_fddc_chan0>; + adi,nco-frequency-shift-hz = /bits/ 64 ; /* 100 MHz */ + }; + trx0_ad9081_dac1: dac@1 { + reg = <1>; + adi,crossbar-select = <&trx0_ad9081_tx_fddc_chan1>; + adi,nco-frequency-shift-hz = /bits/ 64 ; /* 200 MHz */ + }; + }; + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = ; + trx0_ad9081_tx_fddc_chan0: channel@0 { + reg = <0>; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + trx0_ad9081_tx_fddc_chan1: channel@1 { + reg = <1>; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + }; + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + trx0_ad9081_tx_jesd_l0: link@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + adi,logical-lane-mapping = /bits/ 8 <0 1 2 3 4 5 6 7>; + adi,link-mode = ; /* JESD Quick Configuration Mode */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ + adi,version = ; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,converters-per-device = ; /* JESD M */ + adi,octets-per-frame = ; /* JESD F */ + adi,frames-per-multiframe = ; /* JESD K */ + adi,converter-resolution = ; /* JESD N */ + adi,bits-per-sample = ; /* JESD NP' */ + adi,control-bits-per-sample = ; /* JESD CS */ + adi,lanes-per-device = ; /* JESD L */ + adi,samples-per-converter-per-frame = ; /* JESD S */ + adi,high-density = ; /* JESD HD */ + }; + }; + }; + adi,rx-adcs { + #size-cells = <0>; + #address-cells = <1>; + adi,adc-frequency-hz = /bits/ 64 ; + adi,nyquist-zone = ; + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + trx0_ad9081_adc0: adc@0 { + reg = <0>; + adi,decimation = ; + adi,nco-frequency-shift-hz = /bits/ 64 ; + adi,nco-mixer-mode = ; + //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ + }; + trx0_ad9081_adc1: adc@1 { + reg = <1>; + adi,decimation = ; + adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; + adi,nco-mixer-mode = ; + //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ + }; + }; + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + trx0_ad9081_rx_fddc_chan0: channel@0 { + reg = <0>; + adi,decimation = ; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + trx0_ad9081_rx_fddc_chan1: channel@1 { + reg = <1>; + adi,decimation = ; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + }; + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + trx0_ad9081_rx_jesd_l0: link@0 { + reg = <0>; + adi,converter-select = + <&trx0_ad9081_rx_fddc_chan0 FDDC_I>, <&trx0_ad9081_rx_fddc_chan0 FDDC_Q>, + <&trx0_ad9081_rx_fddc_chan1 FDDC_I>, <&trx0_ad9081_rx_fddc_chan1 FDDC_Q>; + adi,logical-lane-mapping = /bits/ 8 <0 1 2 3 4 5 6 7>; + adi,link-mode = ; /* JESD Quick Configuration Mode */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ + adi,version = ; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,device-id = <0>; + adi,converters-per-device = ; /* JESD M */ + adi,octets-per-frame = ; /* JESD F */ + adi,frames-per-multiframe = ; /* JESD K */ + adi,converter-resolution = ; /* JESD N */ + adi,bits-per-sample = ; /* JESD NP' */ + adi,control-bits-per-sample = ; /* JESD CS */ + adi,lanes-per-device = ; /* JESD L */ + adi,samples-per-converter-per-frame = ; /* JESD S */ + adi,high-density = ; /* JESD HD */ + }; + }; + }; +}; + +&trx1_ad9081 { + clocks = <&adf4371_clk1 ADF4371_OUTPUT>; + + adi,tx-dacs { + #size-cells = <0>; + #address-cells = <1>; + adi,dac-frequency-hz = /bits/ 64 ; + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = ; + trx1_ad9081_dac0: dac@0 { + reg = <0>; + adi,crossbar-select = <&trx1_ad9081_tx_fddc_chan0>; + adi,nco-frequency-shift-hz = /bits/ 64 ; /* 100 MHz */ + }; + trx1_ad9081_dac1: dac@1 { + reg = <1>; + adi,crossbar-select = <&trx1_ad9081_tx_fddc_chan1>; + adi,nco-frequency-shift-hz = /bits/ 64 ; /* 200 MHz */ + }; + }; + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = ; + trx1_ad9081_tx_fddc_chan0: channel@0 { + reg = <0>; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + trx1_ad9081_tx_fddc_chan1: channel@1 { + reg = <1>; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + }; + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + trx1_ad9081_tx_jesd_l0: link@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + adi,logical-lane-mapping = /bits/ 8 <0 1 2 3 4 5 6 7>; + adi,link-mode = ; /* JESD Quick Configuration Mode */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ + adi,version = ; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,converters-per-device = ; /* JESD M */ + adi,octets-per-frame = ; /* JESD F */ + adi,frames-per-multiframe = ; /* JESD K */ + adi,converter-resolution = ; /* JESD N */ + adi,bits-per-sample = ; /* JESD NP' */ + adi,control-bits-per-sample = ; /* JESD CS */ + adi,lanes-per-device = ; /* JESD L */ + adi,samples-per-converter-per-frame = ; /* JESD S */ + adi,high-density = ; /* JESD HD */ + }; + }; + }; + adi,rx-adcs { + #size-cells = <0>; + #address-cells = <1>; + adi,adc-frequency-hz = /bits/ 64 ; + adi,nyquist-zone = ; + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + trx1_ad9081_adc0: adc@0 { + reg = <0>; + adi,decimation = ; + adi,nco-frequency-shift-hz = /bits/ 64 ; + adi,nco-mixer-mode = ; + //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan0>, <&trx1_ad9081_rx_fddc_chan2>; /* Static for now */ + }; + trx1_ad9081_adc1: adc@1 { + reg = <1>; + adi,decimation = ; + adi,nco-frequency-shift-hz = /bits/ 64 ; + adi,nco-mixer-mode = ; + //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan1>, <&trx1_ad9081_rx_fddc_chan3>; /* Static for now */ + }; + }; + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + trx1_ad9081_rx_fddc_chan0: channel@0 { + reg = <0>; + adi,decimation = ; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + trx1_ad9081_rx_fddc_chan1: channel@1 { + reg = <1>; + adi,decimation = ; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + }; + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + trx1_ad9081_rx_jesd_l0: link@0 { + reg = <0>; + adi,converter-select = + <&trx1_ad9081_rx_fddc_chan0 FDDC_I>, <&trx1_ad9081_rx_fddc_chan0 FDDC_Q>, + <&trx1_ad9081_rx_fddc_chan1 FDDC_I>, <&trx1_ad9081_rx_fddc_chan1 FDDC_Q>; + adi,logical-lane-mapping = /bits/ 8 <0 1 2 3 4 5 6 7>; + adi,link-mode = ; /* JESD Quick Configuration Mode */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ + adi,version = ; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,device-id = <1>; + adi,converters-per-device = ; /* JESD M */ + adi,octets-per-frame = ; /* JESD F */ + adi,frames-per-multiframe = ; /* JESD K */ + adi,converter-resolution = ; /* JESD N */ + adi,bits-per-sample = ; /* JESD NP' */ + adi,control-bits-per-sample = ; /* JESD CS */ + adi,lanes-per-device = ; /* JESD L */ + adi,samples-per-converter-per-frame = ; /* JESD S */ + adi,high-density = ; /* JESD HD */ + }; + }; + }; +}; + +&trx2_ad9081 { + clocks = <&adf4371_clk2 ADF4371_OUTPUT>; + + adi,tx-dacs { + #size-cells = <0>; + #address-cells = <1>; + adi,dac-frequency-hz = /bits/ 64 ; + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = ; + trx2_ad9081_dac0: dac@0 { + reg = <0>; + adi,crossbar-select = <&trx2_ad9081_tx_fddc_chan0>; + adi,nco-frequency-shift-hz = /bits/ 64 ; /* 100 MHz */ + }; + trx2_ad9081_dac1: dac@1 { + reg = <1>; + adi,crossbar-select = <&trx2_ad9081_tx_fddc_chan1>; + adi,nco-frequency-shift-hz = /bits/ 64 ; /* 200 MHz */ + }; + }; + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = ; + trx2_ad9081_tx_fddc_chan0: channel@0 { + reg = <0>; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + trx2_ad9081_tx_fddc_chan1: channel@1 { + reg = <1>; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + }; + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + trx2_ad9081_tx_jesd_l0: link@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + adi,logical-lane-mapping = /bits/ 8 <0 1 2 3 4 5 6 7>; + adi,link-mode = ; /* JESD Quick Configuration Mode */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ + adi,version = ; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,converters-per-device = ; /* JESD M */ + adi,octets-per-frame = ; /* JESD F */ + adi,frames-per-multiframe = ; /* JESD K */ + adi,converter-resolution = ; /* JESD N */ + adi,bits-per-sample = ; /* JESD NP' */ + adi,control-bits-per-sample = ; /* JESD CS */ + adi,lanes-per-device = ; /* JESD L */ + adi,samples-per-converter-per-frame = ; /* JESD S */ + adi,high-density = ; /* JESD HD */ + }; + }; + }; + adi,rx-adcs { + #size-cells = <0>; + #address-cells = <1>; + adi,adc-frequency-hz = /bits/ 64 ; + adi,nyquist-zone = ; + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + trx2_ad9081_adc0: adc@0 { + reg = <0>; + adi,decimation = ; + adi,nco-frequency-shift-hz = /bits/ 64 ; + adi,nco-mixer-mode = ; + //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan0>, <&trx2_ad9081_rx_fddc_chan2>; /* Static for now */ + }; + trx2_ad9081_adc1: adc@1 { + reg = <1>; + adi,decimation = ; + adi,nco-frequency-shift-hz = /bits/ 64 ; + adi,nco-mixer-mode = ; + //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan1>, <&trx2_ad9081_rx_fddc_chan3>; /* Static for now */ + }; + }; + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + trx2_ad9081_rx_fddc_chan0: channel@0 { + reg = <0>; + adi,decimation = ; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + trx2_ad9081_rx_fddc_chan1: channel@1 { + reg = <1>; + adi,decimation = ; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + }; + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + trx2_ad9081_rx_jesd_l0: link@0 { + reg = <0>; + adi,converter-select = + <&trx2_ad9081_rx_fddc_chan0 FDDC_I>, <&trx2_ad9081_rx_fddc_chan0 FDDC_Q>, + <&trx2_ad9081_rx_fddc_chan1 FDDC_I>, <&trx2_ad9081_rx_fddc_chan1 FDDC_Q>; + adi,logical-lane-mapping = /bits/ 8 <0 1 2 3 4 5 6 7>; + adi,link-mode = ; /* JESD Quick Configuration Mode */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ + adi,version = ; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,device-id = <2>; + adi,converters-per-device = ; /* JESD M */ + adi,octets-per-frame = ; /* JESD F */ + adi,frames-per-multiframe = ; /* JESD K */ + adi,converter-resolution = ; /* JESD N */ + adi,bits-per-sample = ; /* JESD NP' */ + adi,control-bits-per-sample = ; /* JESD CS */ + adi,lanes-per-device = ; /* JESD L */ + adi,samples-per-converter-per-frame = ; /* JESD S */ + adi,high-density = ; /* JESD HD */ + }; + }; + }; +}; + +&trx3_ad9081 { + clocks = <&adf4371_clk3 ADF4371_OUTPUT>; + + adi,tx-dacs { + #size-cells = <0>; + #address-cells = <1>; + adi,dac-frequency-hz = /bits/ 64 ; + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = ; + trx3_ad9081_dac0: dac@0 { + reg = <0>; + adi,crossbar-select = <&trx3_ad9081_tx_fddc_chan0>; + adi,nco-frequency-shift-hz = /bits/ 64 ; /* 100 MHz */ + }; + trx3_ad9081_dac1: dac@1 { + reg = <1>; + adi,crossbar-select = <&trx3_ad9081_tx_fddc_chan1>; + adi,nco-frequency-shift-hz = /bits/ 64 ; /* 200 MHz */ + }; + }; + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + adi,interpolation = ; + trx3_ad9081_tx_fddc_chan0: channel@0 { + reg = <0>; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + trx3_ad9081_tx_fddc_chan1: channel@1 { + reg = <1>; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + }; + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + trx3_ad9081_tx_jesd_l0: link@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + adi,logical-lane-mapping = /bits/ 8 <0 1 2 3 4 5 6 7>; + adi,link-mode = ; /* JESD Quick Configuration Mode */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ + adi,version = ; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,converters-per-device = ; /* JESD M */ + adi,octets-per-frame = ; /* JESD F */ + adi,frames-per-multiframe = ; /* JESD K */ + adi,converter-resolution = ; /* JESD N */ + adi,bits-per-sample = ; /* JESD NP' */ + adi,control-bits-per-sample = ; /* JESD CS */ + adi,lanes-per-device = ; /* JESD L */ + adi,samples-per-converter-per-frame = ; /* JESD S */ + adi,high-density = ; /* JESD HD */ + }; + }; + }; + adi,rx-adcs { + #size-cells = <0>; + #address-cells = <1>; + adi,adc-frequency-hz = /bits/ 64 ; + adi,nyquist-zone = ; + adi,main-data-paths { + #address-cells = <1>; + #size-cells = <0>; + trx3_ad9081_adc0: adc@0 { + reg = <0>; + adi,decimation = ; + adi,nco-frequency-shift-hz = /bits/ 64 ; + adi,nco-mixer-mode = ; + //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan0>, <&trx3_ad9081_rx_fddc_chan2>; /* Static for now */ + }; + trx3_ad9081_adc1: adc@1 { + reg = <1>; + adi,decimation = ; + adi,nco-frequency-shift-hz = /bits/ 64 ; + adi,nco-mixer-mode = ; + //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan1>, <&trx3_ad9081_rx_fddc_chan3>; /* Static for now */ + }; + }; + adi,channelizer-paths { + #address-cells = <1>; + #size-cells = <0>; + trx3_ad9081_rx_fddc_chan0: channel@0 { + reg = <0>; + adi,decimation = ; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + trx3_ad9081_rx_fddc_chan1: channel@1 { + reg = <1>; + adi,decimation = ; + adi,gain = ; /* value * 10^(gain_dB/20) */ + adi,nco-frequency-shift-hz = /bits/ 64 ; + }; + }; + adi,jesd-links { + #size-cells = <0>; + #address-cells = <1>; + trx3_ad9081_rx_jesd_l0: link@0 { + reg = <0>; + adi,converter-select = + <&trx3_ad9081_rx_fddc_chan0 FDDC_I>, <&trx3_ad9081_rx_fddc_chan0 FDDC_Q>, + <&trx3_ad9081_rx_fddc_chan1 FDDC_I>, <&trx3_ad9081_rx_fddc_chan1 FDDC_Q>; + adi,logical-lane-mapping = /bits/ 8 <0 1 2 3 4 5 6 7>; + adi,link-mode = ; /* JESD Quick Configuration Mode */ + adi,subclass = ; /* JESD SUBCLASS 0,1,2 */ + adi,version = ; /* JESD VERSION 0=204A,1=204B,2=204C */ + adi,dual-link = <0>; /* JESD Dual Link Mode */ + adi,device-id = <3>; + adi,converters-per-device = ; /* JESD M */ + adi,octets-per-frame = ; /* JESD F */ + adi,frames-per-multiframe = ; /* JESD K */ + adi,converter-resolution = ; /* JESD N */ + adi,bits-per-sample = ; /* JESD NP' */ + adi,control-bits-per-sample = ; /* JESD CS */ + adi,lanes-per-device = ; /* JESD L */ + adi,samples-per-converter-per-frame = ; /* JESD S */ + adi,high-density = ; /* JESD HD */ + }; + }; + }; +}; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_onchip_pll_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_onchip_pll_revc.dts new file mode 100644 index 00000000000000..e3d723ee226154 --- /dev/null +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_onchip_pll_revc.dts @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices Quad-MxFE (using internal PLL) + * https://wiki.analog.com/resources/eval/user-guides/quadmxfe + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 + * https://wiki.analog.com/resources/eval/user-guides/ad_quadmxfe1_ebz/ad_quadmxfe1_ebz_hdl + * + * hdl_project: + * board_revision: + * + * Copyright (C) 2022 Analog Devices Inc. + */ + +// For MxFE0 +// * Cap rotate: DNI C886, Populate C1118 +// * Cap rotate: DNI C887, Populate C1119 +// For MxFE1 +// * Cap rotate: DNI C936, Populate C1120 +// * Cap rotate: DNI C937, Populate C1267 +// For MxFE2 +// * Cap rotate: DNI C986, Populate C1293 +// * Cap rotate: DNI C987, Populate C1312 +// For MxFE3 +// * Cap rotate: DNI C1036, Populate C1325 +// * Cap rotate: DNI C1037, Populate C1326 + +#define HMC7043_MXFE_CLKIN_CLKDIV 1 + +#include "vcu118_quad_ad9081_204b_txmode_5_rxmode_6_revc.dts" + +&adf4371_clk0 { + adi,chip-powerdown-and-exit-enable; +}; + +&adf4371_clk1 { + adi,chip-powerdown-and-exit-enable; +}; + +&adf4371_clk2 { + adi,chip-powerdown-and-exit-enable; +}; + +&adf4371_clk3 { + adi,chip-powerdown-and-exit-enable; +}; + +&hmc7043 { + adi,high-performance-mode-clock-dist-enable; + + hmc7043_c6: channel@6 { + reg = <6>; + adi,extended-name = "CLKIN_MXFE0"; + adi,divider = ; + adi,driver-mode = ; + }; + hmc7043_c8: channel@8 { + reg = <8>; + adi,extended-name = "CLKIN_MXFE1"; + adi,divider = ; + adi,driver-mode = ; + }; + hmc7043_c10: channel@10 { + reg = <10>; + adi,extended-name = "CLKIN_MXFE0"; + adi,divider = ; + adi,driver-mode = ; + }; + hmc7043_c12: channel@12 { + reg = <12>; + adi,extended-name = "CLKIN_MXFE0"; + adi,divider = ; + adi,driver-mode = ; + }; +}; + +&trx0_ad9081 { + clocks = <&hmc7043 6>; + /delete-property/ dev_clk-clock-scales; +}; + +&trx1_ad9081 { + clocks = <&hmc7043 8>; + /delete-property/ dev_clk-clock-scales; +}; + +&trx2_ad9081 { + clocks = <&hmc7043 10>; + /delete-property/ dev_clk-clock-scales; +}; + +&trx3_ad9081 { + clocks = <&hmc7043 12>; + /delete-property/ dev_clk-clock-scales; +}; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_onchip_pll_revc_nz1.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_onchip_pll_revc_nz1.dts new file mode 100644 index 00000000000000..74e78d44290496 --- /dev/null +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_onchip_pll_revc_nz1.dts @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices Quad-MxFE AD-QUADMXFE2-EBZ first Nyquist Zone operation + * https://wiki.analog.com/resources/eval/user-guides/quadmxfe + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 + * https://wiki.analog.com/resources/eval/user-guides/ad_quadmxfe1_ebz/ad_quadmxfe1_ebz_hdl + * + * hdl_project: + * board_revision: + * + * Copyright (C) 2022 Analog Devices Inc. + */ + +#include + +#define AD9081_TX_MAIN_NCO_SHIFT 1000000000 +#define AD9081_TX_CHAN_NCO_SHIFT 0 + +#define AD9081_RX_MAIN_NCO_SHIFT 1000000000 +#define AD9081_RX_CHAN_NCO_SHIFT 0 + +#define AD9081_ADC_NYQUIST_ZONE AD9081_ADC_NYQUIST_ZONE_ODD + +#include "vcu118_quad_ad9081_204b_txmode_5_rxmode_6_onchip_pll_revc.dts" + +/ { + model = "Analog Devices AD-QUADMXFE2-EBZ"; +}; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_revc.dts new file mode 100644 index 00000000000000..62d4e657a213fb --- /dev/null +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6_revc.dts @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices Quad-MxFE + * https://wiki.analog.com/resources/eval/user-guides/quadmxfe + * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 + * https://wiki.analog.com/resources/eval/user-guides/ad_quadmxfe1_ebz/ad_quadmxfe1_ebz_hdl + * + * hdl_project: + * board_revision: + * + * Copyright (C) 2022 Analog Devices Inc. + */ + +#include "vcu118_quad_ad9081_204b_txmode_5_rxmode_6.dts" + +/ { + model = "Analog Devices AD-QUADMXFE1-EBZ Rev.C"; +}; + +&gpio_hmc425a { + compatible = "adi,hmc540s"; + ctrl-gpios = <&axi_gpio 38 GPIO_ACTIVE_HIGH>, + <&axi_gpio 37 GPIO_ACTIVE_HIGH>, + <&axi_gpio 36 GPIO_ACTIVE_HIGH>, + <&axi_gpio 35 GPIO_ACTIVE_HIGH>; +}; + +&fmc_i2c { + current_limiter@58 { + compatible = "adi,adm1177-iio"; + reg = <0x58>; + adi,r-sense-mohm = <10>; /* 10 mOhm */ + adi,shutdown-threshold-ma = <10000>; /* 10 A */ + adi,vrange-high-enable; + }; +}; + +&axi_ad9081_rx_jesd { + clocks = <&clk_bus_0>, <&hmc7043 2>, <&axi_ad9081_adxcvr_rx 1>, <&axi_ad9081_adxcvr_rx 0>; + clock-names = "s_axi_aclk", "device_clk", "link_clk", "lane_clk"; +}; + +&axi_ad9081_tx_jesd { + clocks = <&clk_bus_0>, <&hmc7043 4>, <&axi_ad9081_adxcvr_tx 1>, <&axi_ad9081_adxcvr_tx 0>; + clock-names = "s_axi_aclk", "device_clk", "link_clk", "lane_clk"; +}; + +&hmc7043 { + hmc7043_c0: channel@0 { + reg = <0>; + adi,extended-name = "FPGA_REFCLK"; + adi,divider = ; + adi,driver-mode = ; + }; + + hmc7043_c1: channel@1 { + reg = <1>; + adi,extended-name = "SYSREF_FPGA"; + adi,divider = ; + adi,driver-mode = ; + adi,coarse-digital-delay = <0>; + adi,fine-analog-delay = <0>; + adi,output-mux-mode = <0>; + adi,jesd204-sysref-chan; + }; + + hmc7043_c2: channel@2 { + reg = <2>; + adi,extended-name = "RX_CORE_LINK_CLK"; + adi,divider = ; + adi,driver-mode = ; + }; + + /delete-node/ hmc7043_c3; + + hmc7043_c4: channel@4 { + reg = <4>; + adi,extended-name = "TX_CORE_LINK_CLK"; + adi,divider = ; + adi,driver-mode = ; + }; + + /delete-node/ hmc7043_c5; + /delete-node/ hmc7043_c6; + + hmc7043_c7: channel@7 { + reg = <7>; + adi,extended-name = "SYSREF_MXFE0"; + adi,divider = ; + adi,driver-mode = ; + adi,coarse-digital-delay = <0>; + adi,fine-analog-delay = <0>; + adi,output-mux-mode = <0>; + adi,jesd204-sysref-chan; + }; + + /delete-node/ hmc7043_c8; + + hmc7043_c9: channel@9 { + reg = <9>; + adi,extended-name = "SYSREF_MXFE1"; + adi,divider = ; + adi,driver-mode = ; + adi,coarse-digital-delay = <0>; + adi,fine-analog-delay = <0>; + adi,output-mux-mode = <0>; + adi,jesd204-sysref-chan; + }; + + /delete-node/ hmc7043_c10; + + hmc7043_c11: channel@11 { + reg = <11>; + adi,extended-name = "SYSREF_MXFE2"; + adi,divider = ; + adi,driver-mode = ; + adi,coarse-digital-delay = <0>; + adi,fine-analog-delay = <0>; + adi,output-mux-mode = <0>; + adi,jesd204-sysref-chan; + }; + + /delete-node/ hmc7043_c12; + + hmc7043_c13: channel@13 { + reg = <13>; + adi,extended-name = "SYSREF_MXFE3"; + adi,divider = ; + adi,driver-mode = ; + adi,coarse-digital-delay = <0>; + adi,fine-analog-delay = <0>; + adi,output-mux-mode = <0>; + adi,jesd204-sysref-chan; + }; +}; + +&trx0_ad9081 { + /delete-property/ adi,jesd-sync-pins-01-swap-enable; + adi,jesd-sync-pin-0a-cmos-enable; +}; + +&trx1_ad9081 { + /delete-property/ adi,jesd-sync-pins-01-swap-enable; + adi,jesd-sync-pin-0a-cmos-enable; +}; + +&trx2_ad9081 { + /delete-property/ adi,jesd-sync-pins-01-swap-enable; + adi,jesd-sync-pin-0a-cmos-enable; +}; + +&trx3_ad9081 { + /delete-property/ adi,jesd-sync-pins-01-swap-enable; + adi,jesd-sync-pin-0a-cmos-enable; +}; From bc609328bca311ab7ef9f1bf86980bb3ec06460c Mon Sep 17 00:00:00 2001 From: Michael Bradley Date: Thu, 7 Apr 2022 11:16:14 -0700 Subject: [PATCH 295/407] arch: arm: zynq_xcomm_adv7511_defconfig: Enable dt/FPGA overlay support Enable dynamic loading and unloading of device tree overlays and FPGA bit streams. Signed-off-by: Michael Bradley --- arch/arm/configs/zynq_xcomm_adv7511_defconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/configs/zynq_xcomm_adv7511_defconfig b/arch/arm/configs/zynq_xcomm_adv7511_defconfig index 0e4180e7802f87..164376b76aaa10 100644 --- a/arch/arm/configs/zynq_xcomm_adv7511_defconfig +++ b/arch/arm/configs/zynq_xcomm_adv7511_defconfig @@ -70,6 +70,8 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_SPI_NOR=y +CONFIG_OF_OVERLAY=y +CONFIG_OF_CONFIGFS=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=16384 @@ -229,7 +231,11 @@ CONFIG_COMMON_CLK_AXI_CLKGEN=y CONFIG_MEMORY=y CONFIG_AXI_JESD204B=y CONFIG_FPGA=y +CONFIG_FPGA_MGR_ZYNQ_AFI_FPGA=y CONFIG_FPGA_MGR_ZYNQ_FPGA=y +CONFIG_FPGA_BRIDGE=y +CONFIG_FPGA_REGION=y +CONFIG_OF_FPGA_REGION=y CONFIG_MUX_GPIO=y CONFIG_MUX_MMIO=y CONFIG_EXT4_FS=y From 14bfb1d7fa4de9f3428c9080ae11d43aea23dd23 Mon Sep 17 00:00:00 2001 From: "Liviu.Iacob" Date: Thu, 7 Apr 2022 11:37:15 +0100 Subject: [PATCH 296/407] arch: arm64: dts: change jesd subclass for zynqmp-zcu102-rev10-ad9695 Add support for subclass 1 for ad9695 with zcu102 carrier. Signed-off-by: Liviu.Iacob --- .../dts/xilinx/zynqmp-zcu102-rev10-ad9695.dts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9695.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9695.dts index 918bf88f8cc684..b5242ee41f2b7a 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9695.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9695.dts @@ -46,6 +46,13 @@ clock-accuracy = <1000000000>; clock-output-names = "dev_clk"; }; + sysref: clock@2 { + #clock-cells = <0>; + compatible = "adjustable-clock"; + clock-frequency = <5078125>; + clock-accuracy = <1000000000>; + clock-output-names = "adc_sysref"; + }; }; fpga_axi: fpga-axi@0 { interrupt-parent = <&gic>; @@ -93,7 +100,7 @@ adi,octets-per-frame = <1>; adi,frames-per-multiframe = <32>; - adi,subclass = <0>; + adi,subclass = <1>; #clock-cells = <0>; clock-output-names = "jesd_adc_lane_clk"; @@ -136,8 +143,8 @@ spi-max-frequency = <5000000>; reg = <0>; - clocks = <&axi_ad9695_jesd>, <&ad9695_clkin>; - clock-names = "jesd_adc_clk", "adc_clk"; + clocks = <&axi_ad9695_jesd>, <&ad9695_clkin>, <&sysref>; + clock-names = "jesd_adc_clk", "adc_clk", "adc_sysref"; adi,powerdown-mode = ; @@ -163,7 +170,7 @@ adi,converters-per-device = <2>; adi,control-bits-per-sample = <0>; adi,lanes-per-device = <4>; - adi,subclass = <0>; + adi,subclass = <1>; #address-cells = <1>; #size-cells = <0>; From de27a655425615e105d60a50da592a3d0c84a463 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 8 Apr 2022 08:08:44 +0200 Subject: [PATCH 297/407] arm: configs: zynq_xcomm_adv7511_defconfig: Update using savedefconfig This cleans a bit our zynq_xcomm_adv7511_defconfig. Signed-off-by: Michael Hennerich --- arch/arm/configs/zynq_xcomm_adv7511_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/zynq_xcomm_adv7511_defconfig b/arch/arm/configs/zynq_xcomm_adv7511_defconfig index 164376b76aaa10..7d47f05eb985df 100644 --- a/arch/arm/configs/zynq_xcomm_adv7511_defconfig +++ b/arch/arm/configs/zynq_xcomm_adv7511_defconfig @@ -231,8 +231,8 @@ CONFIG_COMMON_CLK_AXI_CLKGEN=y CONFIG_MEMORY=y CONFIG_AXI_JESD204B=y CONFIG_FPGA=y -CONFIG_FPGA_MGR_ZYNQ_AFI_FPGA=y CONFIG_FPGA_MGR_ZYNQ_FPGA=y +CONFIG_FPGA_MGR_ZYNQ_AFI_FPGA=y CONFIG_FPGA_BRIDGE=y CONFIG_FPGA_REGION=y CONFIG_OF_FPGA_REGION=y From 33310c8df8587d90e10521bf370dce2e582727d3 Mon Sep 17 00:00:00 2001 From: Lucas Stankus Date: Wed, 1 Sep 2021 16:14:54 -0300 Subject: [PATCH 298/407] iio: accel: Add driver support for ADXL313 ADXL313 is a small, thin, low power, 3-axis accelerometer with high resolution measurement up to +/-4g. It includes an integrated 32-level FIFO and has activity and inactivity sensing capabilities. Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf Signed-off-by: Lucas Stankus Reviewed-by: Alexandru Ardelean Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/d16e2d1967e46bb2b1024b6d23bc4889da77dc6b.1630523106.git.lucas.p.stankus@gmail.com Signed-off-by: Jonathan Cameron (cherry picked from commit 636d44633039348c955947cee561f372846b478b) --- MAINTAINERS | 6 + drivers/iio/accel/Kconfig | 29 +++ drivers/iio/accel/Makefile | 3 + drivers/iio/accel/adxl313.h | 54 +++++ drivers/iio/accel/adxl313_core.c | 332 +++++++++++++++++++++++++++++++ drivers/iio/accel/adxl313_i2c.c | 66 ++++++ drivers/iio/accel/adxl313_spi.c | 92 +++++++++ 7 files changed, 582 insertions(+) create mode 100644 drivers/iio/accel/adxl313.h create mode 100644 drivers/iio/accel/adxl313_core.c create mode 100644 drivers/iio/accel/adxl313_i2c.c create mode 100644 drivers/iio/accel/adxl313_spi.c diff --git a/MAINTAINERS b/MAINTAINERS index 11ffd1804eb443..a06dcfe038d4fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -570,6 +570,12 @@ S: Maintained F: Documentation/scsi/advansys.rst F: drivers/scsi/advansys.c +ADXL313 THREE-AXIS DIGITAL ACCELEROMETER DRIVER +M: Lucas Stankus +S: Supported +F: Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml +F: drivers/iio/accel/adxl313* + ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346) M: Michael Hennerich S: Supported diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 2a97f80fd5dfa1..f4ac0e6d036eed 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -30,6 +30,35 @@ config ADIS16209 To compile this driver as a module, say M here: the module will be called adis16209. +config ADXL313 + tristate + +config ADXL313_I2C + tristate "Analog Devices ADXL313 3-Axis Digital Accelerometer I2C Driver" + depends on I2C + select ADXL313 + select REGMAP_I2C + help + Say Y here if you want to build i2c support for the Analog Devices + ADXL313 3-axis digital accelerometer. + + To compile this driver as a module, choose M here: the module + will be called adxl313_i2c and you will also get adxl313_core + for the core module. + +config ADXL313_SPI + tristate "Analog Devices ADXL313 3-Axis Digital Accelerometer SPI Driver" + depends on SPI + select ADXL313 + select REGMAP_SPI + help + Say Y here if you want to build spi support for the Analog Devices + ADXL313 3-axis digital accelerometer. + + To compile this driver as a module, choose M here: the module + will be called adxl313_spi and you will also get adxl313_core + for the core module. + config ADXL345 tristate diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index b9abd58531a5ef..72485a26b62c76 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -6,6 +6,9 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ADIS16201) += adis16201.o obj-$(CONFIG_ADIS16209) += adis16209.o +obj-$(CONFIG_ADXL313) += adxl313_core.o +obj-$(CONFIG_ADXL313_I2C) += adxl313_i2c.o +obj-$(CONFIG_ADXL313_SPI) += adxl313_spi.o obj-$(CONFIG_ADXL345) += adxl345_core.o obj-$(CONFIG_ADXL345_I2C) += adxl345_i2c.o obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o diff --git a/drivers/iio/accel/adxl313.h b/drivers/iio/accel/adxl313.h new file mode 100644 index 00000000000000..4415f2fc07e176 --- /dev/null +++ b/drivers/iio/accel/adxl313.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * ADXL313 3-Axis Digital Accelerometer + * + * Copyright (c) 2021 Lucas Stankus + */ + +#ifndef _ADXL313_H_ +#define _ADXL313_H_ + +/* ADXL313 register definitions */ +#define ADXL313_REG_DEVID0 0x00 +#define ADXL313_REG_DEVID1 0x01 +#define ADXL313_REG_PARTID 0x02 +#define ADXL313_REG_XID 0x04 +#define ADXL313_REG_SOFT_RESET 0x18 +#define ADXL313_REG_OFS_AXIS(index) (0x1E + (index)) +#define ADXL313_REG_THRESH_ACT 0x24 +#define ADXL313_REG_ACT_INACT_CTL 0x27 +#define ADXL313_REG_BW_RATE 0x2C +#define ADXL313_REG_POWER_CTL 0x2D +#define ADXL313_REG_INT_MAP 0x2F +#define ADXL313_REG_DATA_FORMAT 0x31 +#define ADXL313_REG_DATA_AXIS(index) (0x32 + ((index) * 2)) +#define ADXL313_REG_FIFO_CTL 0x38 +#define ADXL313_REG_FIFO_STATUS 0x39 + +#define ADXL313_DEVID0 0xAD +#define ADXL313_DEVID1 0x1D +#define ADXL313_PARTID 0xCB +#define ADXL313_SOFT_RESET 0x52 + +#define ADXL313_RATE_MSK GENMASK(3, 0) +#define ADXL313_RATE_BASE 6 + +#define ADXL313_POWER_CTL_MSK GENMASK(3, 2) +#define ADXL313_MEASUREMENT_MODE BIT(3) + +#define ADXL313_RANGE_MSK GENMASK(1, 0) +#define ADXL313_RANGE_4G 3 + +#define ADXL313_FULL_RES BIT(3) +#define ADXL313_SPI_3WIRE BIT(6) +#define ADXL313_I2C_DISABLE BIT(6) + +extern const struct regmap_access_table adxl313_readable_regs_table; + +extern const struct regmap_access_table adxl313_writable_regs_table; + +int adxl313_core_probe(struct device *dev, + struct regmap *regmap, + const char *name, + int (*setup)(struct device *, struct regmap *)); +#endif /* _ADXL313_H_ */ diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c new file mode 100644 index 00000000000000..0d243341f1a757 --- /dev/null +++ b/drivers/iio/accel/adxl313_core.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADXL313 3-Axis Digital Accelerometer + * + * Copyright (c) 2021 Lucas Stankus + * + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf + */ + +#include +#include +#include +#include + +#include "adxl313.h" + +static const struct regmap_range adxl313_readable_reg_range[] = { + regmap_reg_range(ADXL313_REG_DEVID0, ADXL313_REG_XID), + regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET), + regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)), + regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL), + regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_FIFO_STATUS), +}; + +const struct regmap_access_table adxl313_readable_regs_table = { + .yes_ranges = adxl313_readable_reg_range, + .n_yes_ranges = ARRAY_SIZE(adxl313_readable_reg_range), +}; +EXPORT_SYMBOL_GPL(adxl313_readable_regs_table); + +static const struct regmap_range adxl313_writable_reg_range[] = { + regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET), + regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)), + regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL), + regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_INT_MAP), + regmap_reg_range(ADXL313_REG_DATA_FORMAT, ADXL313_REG_DATA_FORMAT), + regmap_reg_range(ADXL313_REG_FIFO_CTL, ADXL313_REG_FIFO_CTL), +}; + +const struct regmap_access_table adxl313_writable_regs_table = { + .yes_ranges = adxl313_writable_reg_range, + .n_yes_ranges = ARRAY_SIZE(adxl313_writable_reg_range), +}; +EXPORT_SYMBOL_GPL(adxl313_writable_regs_table); + +struct adxl313_data { + struct regmap *regmap; + struct mutex lock; /* lock to protect transf_buf */ + __le16 transf_buf ____cacheline_aligned; +}; + +static const int adxl313_odr_freqs[][2] = { + [0] = { 6, 250000 }, + [1] = { 12, 500000 }, + [2] = { 25, 0 }, + [3] = { 50, 0 }, + [4] = { 100, 0 }, + [5] = { 200, 0 }, + [6] = { 400, 0 }, + [7] = { 800, 0 }, + [8] = { 1600, 0 }, + [9] = { 3200, 0 }, +}; + +#define ADXL313_ACCEL_CHANNEL(index, axis) { \ + .type = IIO_ACCEL, \ + .address = index, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_type = { \ + .realbits = 13, \ + }, \ +} + +static const struct iio_chan_spec adxl313_channels[] = { + ADXL313_ACCEL_CHANNEL(0, X), + ADXL313_ACCEL_CHANNEL(1, Y), + ADXL313_ACCEL_CHANNEL(2, Z), +}; + +static int adxl313_set_odr(struct adxl313_data *data, + unsigned int freq1, unsigned int freq2) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(adxl313_odr_freqs); i++) { + if (adxl313_odr_freqs[i][0] == freq1 && + adxl313_odr_freqs[i][1] == freq2) + break; + } + + if (i == ARRAY_SIZE(adxl313_odr_freqs)) + return -EINVAL; + + return regmap_update_bits(data->regmap, ADXL313_REG_BW_RATE, + ADXL313_RATE_MSK, + FIELD_PREP(ADXL313_RATE_MSK, ADXL313_RATE_BASE + i)); +} + +static int adxl313_read_axis(struct adxl313_data *data, + struct iio_chan_spec const *chan) +{ + int ret; + + mutex_lock(&data->lock); + + ret = regmap_bulk_read(data->regmap, + ADXL313_REG_DATA_AXIS(chan->address), + &data->transf_buf, sizeof(data->transf_buf)); + if (ret) + goto unlock_ret; + + ret = le16_to_cpu(data->transf_buf); + +unlock_ret: + mutex_unlock(&data->lock); + return ret; +} + +static int adxl313_read_freq_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = (const int *)adxl313_odr_freqs; + *length = ARRAY_SIZE(adxl313_odr_freqs) * 2; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int adxl313_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct adxl313_data *data = iio_priv(indio_dev); + unsigned int regval; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = adxl313_read_axis(data, chan); + if (ret < 0) + return ret; + + *val = sign_extend32(ret, chan->scan_type.realbits - 1); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* + * Scale for any g range is given in datasheet as + * 1024 LSB/g = 0.0009765625 * 9.80665 = 0.009576806640625 m/s^2 + */ + *val = 0; + *val2 = 9576806; + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_CALIBBIAS: + ret = regmap_read(data->regmap, + ADXL313_REG_OFS_AXIS(chan->address), ®val); + if (ret) + return ret; + + /* + * 8-bit resolution at +/- 0.5g, that is 4x accel data scale + * factor at full resolution + */ + *val = sign_extend32(regval, 7) * 4; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = regmap_read(data->regmap, ADXL313_REG_BW_RATE, ®val); + if (ret) + return ret; + + ret = FIELD_GET(ADXL313_RATE_MSK, regval) - ADXL313_RATE_BASE; + *val = adxl313_odr_freqs[ret][0]; + *val2 = adxl313_odr_freqs[ret][1]; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int adxl313_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct adxl313_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_CALIBBIAS: + /* + * 8-bit resolution at +/- 0.5g, that is 4x accel data scale + * factor at full resolution + */ + if (clamp_val(val, -128 * 4, 127 * 4) != val) + return -EINVAL; + + return regmap_write(data->regmap, + ADXL313_REG_OFS_AXIS(chan->address), + val / 4); + case IIO_CHAN_INFO_SAMP_FREQ: + return adxl313_set_odr(data, val, val2); + default: + return -EINVAL; + } +} + +static const struct iio_info adxl313_info = { + .read_raw = adxl313_read_raw, + .write_raw = adxl313_write_raw, + .read_avail = adxl313_read_freq_avail, +}; + +static int adxl313_setup(struct device *dev, struct adxl313_data *data, + int (*setup)(struct device *, struct regmap *)) +{ + unsigned int regval; + int ret; + + /* Ensures the device is in a consistent state after start up */ + ret = regmap_write(data->regmap, ADXL313_REG_SOFT_RESET, + ADXL313_SOFT_RESET); + if (ret) + return ret; + + if (setup) { + ret = setup(dev, data->regmap); + if (ret) + return ret; + } + + ret = regmap_read(data->regmap, ADXL313_REG_DEVID0, ®val); + if (ret) + return ret; + + if (regval != ADXL313_DEVID0) { + dev_err(dev, "Invalid manufacturer ID: 0x%02x\n", regval); + return -ENODEV; + } + + ret = regmap_read(data->regmap, ADXL313_REG_DEVID1, ®val); + if (ret) + return ret; + + if (regval != ADXL313_DEVID1) { + dev_err(dev, "Invalid mems ID: 0x%02x\n", regval); + return -ENODEV; + } + + ret = regmap_read(data->regmap, ADXL313_REG_PARTID, ®val); + if (ret) + return ret; + + if (regval != ADXL313_PARTID) { + dev_err(dev, "Invalid device ID: 0x%02x\n", regval); + return -ENODEV; + } + + /* Sets the range to +/- 4g */ + ret = regmap_update_bits(data->regmap, ADXL313_REG_DATA_FORMAT, + ADXL313_RANGE_MSK, + FIELD_PREP(ADXL313_RANGE_MSK, ADXL313_RANGE_4G)); + if (ret) + return ret; + + /* Enables full resolution */ + ret = regmap_update_bits(data->regmap, ADXL313_REG_DATA_FORMAT, + ADXL313_FULL_RES, ADXL313_FULL_RES); + if (ret) + return ret; + + /* Enables measurement mode */ + return regmap_update_bits(data->regmap, ADXL313_REG_POWER_CTL, + ADXL313_POWER_CTL_MSK, + ADXL313_MEASUREMENT_MODE); +} + +/** + * adxl313_core_probe() - probe and setup for adxl313 accelerometer + * @dev: Driver model representation of the device + * @regmap: Register map of the device + * @name: Device name buffer reference + * @setup: Setup routine to be executed right before the standard device + * setup, can also be set to NULL if not required + * + * Return: 0 on success, negative errno on error cases + */ +int adxl313_core_probe(struct device *dev, + struct regmap *regmap, + const char *name, + int (*setup)(struct device *, struct regmap *)) +{ + struct adxl313_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->regmap = regmap; + mutex_init(&data->lock); + + indio_dev->name = name; + indio_dev->info = &adxl313_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adxl313_channels; + indio_dev->num_channels = ARRAY_SIZE(adxl313_channels); + + ret = adxl313_setup(dev, data, setup); + if (ret) { + dev_err(dev, "ADXL313 setup failed\n"); + return ret; + } + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_GPL(adxl313_core_probe); + +MODULE_AUTHOR("Lucas Stankus "); +MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c new file mode 100644 index 00000000000000..82e9fb2db1e6dc --- /dev/null +++ b/drivers/iio/accel/adxl313_i2c.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADXL313 3-Axis Digital Accelerometer + * + * Copyright (c) 2021 Lucas Stankus + * + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf + */ + +#include +#include +#include +#include + +#include "adxl313.h" + +static const struct regmap_config adxl313_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .rd_table = &adxl313_readable_regs_table, + .wr_table = &adxl313_writable_regs_table, + .max_register = 0x39, +}; + +static int adxl313_i2c_probe(struct i2c_client *client) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, &adxl313_i2c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Error initializing i2c regmap: %ld\n", + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return adxl313_core_probe(&client->dev, regmap, client->name, NULL); +} + +static const struct i2c_device_id adxl313_i2c_id[] = { + { "adxl313" }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, adxl313_i2c_id); + +static const struct of_device_id adxl313_of_match[] = { + { .compatible = "adi,adxl313" }, + { } +}; + +MODULE_DEVICE_TABLE(of, adxl313_of_match); + +static struct i2c_driver adxl313_i2c_driver = { + .driver = { + .name = "adxl313_i2c", + .of_match_table = adxl313_of_match, + }, + .probe_new = adxl313_i2c_probe, + .id_table = adxl313_i2c_id, +}; + +module_i2c_driver(adxl313_i2c_driver); + +MODULE_AUTHOR("Lucas Stankus "); +MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer I2C driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c new file mode 100644 index 00000000000000..a6162f36ef52ef --- /dev/null +++ b/drivers/iio/accel/adxl313_spi.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADXL313 3-Axis Digital Accelerometer + * + * Copyright (c) 2021 Lucas Stankus + * + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf + */ + +#include +#include +#include +#include + +#include "adxl313.h" + +static const struct regmap_config adxl313_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .rd_table = &adxl313_readable_regs_table, + .wr_table = &adxl313_writable_regs_table, + .max_register = 0x39, + /* Setting bits 7 and 6 enables multiple-byte read */ + .read_flag_mask = BIT(7) | BIT(6), +}; + +static int adxl313_spi_setup(struct device *dev, struct regmap *regmap) +{ + struct spi_device *spi = container_of(dev, struct spi_device, dev); + int ret; + + if (spi->mode & SPI_3WIRE) { + ret = regmap_write(regmap, ADXL313_REG_DATA_FORMAT, + ADXL313_SPI_3WIRE); + if (ret) + return ret; + } + + return regmap_update_bits(regmap, ADXL313_REG_POWER_CTL, + ADXL313_I2C_DISABLE, ADXL313_I2C_DISABLE); +} + +static int adxl313_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct regmap *regmap; + int ret; + + spi->mode |= SPI_MODE_3; + ret = spi_setup(spi); + if (ret) + return ret; + + regmap = devm_regmap_init_spi(spi, &adxl313_spi_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Error initializing spi regmap: %ld\n", + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return adxl313_core_probe(&spi->dev, regmap, id->name, + &adxl313_spi_setup); +} + +static const struct spi_device_id adxl313_spi_id[] = { + { "adxl313" }, + { } +}; + +MODULE_DEVICE_TABLE(spi, adxl313_spi_id); + +static const struct of_device_id adxl313_of_match[] = { + { .compatible = "adi,adxl313" }, + { } +}; + +MODULE_DEVICE_TABLE(of, adxl313_of_match); + +static struct spi_driver adxl313_spi_driver = { + .driver = { + .name = "adxl313_spi", + .of_match_table = adxl313_of_match, + }, + .probe = adxl313_spi_probe, + .id_table = adxl313_spi_id, +}; + +module_spi_driver(adxl313_spi_driver); + +MODULE_AUTHOR("Lucas Stankus "); +MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer SPI driver"); +MODULE_LICENSE("GPL v2"); From de8462868aaf5da3ed3858ee8be6c37460059919 Mon Sep 17 00:00:00 2001 From: Lucas Stankus Date: Wed, 1 Sep 2021 16:14:28 -0300 Subject: [PATCH 299/407] dt-bindings: iio: accel: Add binding documentation for ADXL313 Add device tree binding documentation for ADXL313 3-axis accelerometer. Signed-off-by: Lucas Stankus Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/2eff22d1d22f7e72efdabdc681d02e922682c434.1630523106.git.lucas.p.stankus@gmail.com Signed-off-by: Jonathan Cameron (cherry picked from commit af1c6b50a2947cee3ffffb32aa8debb100c786bb) --- .../bindings/iio/accel/adi,adxl313.yaml | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml new file mode 100644 index 00000000000000..d6afc1b8c27287 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/accel/adi,adxl313.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADXL313 3-Axis Digital Accelerometer + +maintainers: + - Lucas Stankus + +description: | + Analog Devices ADXL313 3-Axis Digital Accelerometer that supports + both I2C & SPI interfaces. + https://www.analog.com/en/products/adxl313.html + +properties: + compatible: + enum: + - adi,adxl313 + + reg: + maxItems: 1 + + spi-3wire: true + + spi-max-frequency: true + + vs-supply: + description: Regulator that supplies power to the accelerometer + + vdd-supply: + description: Regulator that supplies the digital interface supply voltage + + interrupts: + minItems: 1 + maxItems: 2 + + interrupt-names: + minItems: 1 + maxItems: 2 + items: + enum: + - INT1 + - INT2 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + #include + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + /* Example for a I2C device node */ + accelerometer@53 { + compatible = "adi,adxl313"; + reg = <0x53>; + interrupt-parent = <&gpio0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "INT1"; + }; + }; + - | + #include + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + + /* Example for a SPI device node */ + accelerometer@0 { + compatible = "adi,adxl313"; + reg = <0>; + spi-max-frequency = <5000000>; + interrupt-parent = <&gpio0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "INT1"; + }; + }; From 6b62b86d3dc7e95ea0e72fada1584634cdd04e8f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:27 +0000 Subject: [PATCH 300/407] iio:accel:adxl313: Move exports into IIO_ADXL313 namespace In order to avoid unnecessary pollution of the global symbol namespace move the driver core exports into their own namespace and import that into the two bus modules. Signed-off-by: Jonathan Cameron Cc: Lucas Stankus Link: https://lore.kernel.org/r/20220116180535.2367780-6-jic23@kernel.org (cherry picked from commit fa4df5a9036e1a68b18a01c714c69961040d2f9b) --- drivers/iio/accel/adxl313_core.c | 6 +++--- drivers/iio/accel/adxl313_i2c.c | 1 + drivers/iio/accel/adxl313_spi.c | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c index 0d243341f1a757..9e4193e64765f8 100644 --- a/drivers/iio/accel/adxl313_core.c +++ b/drivers/iio/accel/adxl313_core.c @@ -26,7 +26,7 @@ const struct regmap_access_table adxl313_readable_regs_table = { .yes_ranges = adxl313_readable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl313_readable_reg_range), }; -EXPORT_SYMBOL_GPL(adxl313_readable_regs_table); +EXPORT_SYMBOL_NS_GPL(adxl313_readable_regs_table, IIO_ADXL313); static const struct regmap_range adxl313_writable_reg_range[] = { regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET), @@ -41,7 +41,7 @@ const struct regmap_access_table adxl313_writable_regs_table = { .yes_ranges = adxl313_writable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl313_writable_reg_range), }; -EXPORT_SYMBOL_GPL(adxl313_writable_regs_table); +EXPORT_SYMBOL_NS_GPL(adxl313_writable_regs_table, IIO_ADXL313); struct adxl313_data { struct regmap *regmap; @@ -325,7 +325,7 @@ int adxl313_core_probe(struct device *dev, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_GPL(adxl313_core_probe); +EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, IIO_ADXL313); MODULE_AUTHOR("Lucas Stankus "); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver"); diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c index 82e9fb2db1e6dc..c329765dbf60f0 100644 --- a/drivers/iio/accel/adxl313_i2c.c +++ b/drivers/iio/accel/adxl313_i2c.c @@ -64,3 +64,4 @@ module_i2c_driver(adxl313_i2c_driver); MODULE_AUTHOR("Lucas Stankus "); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer I2C driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADXL313); diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c index a6162f36ef52ef..a3c6d553462d88 100644 --- a/drivers/iio/accel/adxl313_spi.c +++ b/drivers/iio/accel/adxl313_spi.c @@ -90,3 +90,4 @@ module_spi_driver(adxl313_spi_driver); MODULE_AUTHOR("Lucas Stankus "); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADXL313); From cd70001df83cc81a60ecc9376f55303234698c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Wed, 20 Apr 2022 16:57:42 +0200 Subject: [PATCH 301/407] ci: fix building inside docker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With new git versions, git will stop executing when looking at .git directories with different ownership from the current user. This is fixing some vulnerabilities recently found in git. More info in [1]. In our case, this will happen because we are running the build inside a container which is running as the root user (not sharing UID with the host) while the repository is being checked out by the host system (azure VM) with a different UID. Fix it by adding the docker path to git safe.directory. At some point we should just stop doing builds inside docker wih azure (it runs it's own vm per job already). [1]: https://github.blog/2022-04-12-git-security-vulnerability-announced/ Signed-off-by: Nuno Sá --- ci/travis/run-build.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ci/travis/run-build.sh b/ci/travis/run-build.sh index 3cd404dd24c327..261d8847bc1007 100755 --- a/ci/travis/run-build.sh +++ b/ci/travis/run-build.sh @@ -189,6 +189,11 @@ build_default() { APT_LIST="$APT_LIST git" apt_update_install $APT_LIST + + # make sure git does not complain about unsafe repositories when + # building inside docker. + [ -d /docker_build_dir ] && git config --global --add safe.directory /docker_build_dir + make ${DEFCONFIG} if [[ "${SYSTEM_PULLREQUEST_TARGETBRANCH}" =~ ^rpi-.* || "${BUILD_SOURCEBRANCH}" =~ ^refs/heads/rpi-.* \ || "${BUILD_SOURCEBRANCH}" =~ ^refs/heads/staging-rpi ]]; then From 9f35dd52dbcc847126ef59376288d8dc37ae8973 Mon Sep 17 00:00:00 2001 From: Sergiu Arpadi Date: Wed, 20 Apr 2022 17:04:56 +0300 Subject: [PATCH 302/407] arch: arm: dts: zynq-coraz7s: add sysid support Add axi sysid node in device tree to enable sysid for coraz7s based designs Signed-off-by: Sergiu Arpadi --- arch/arm/boot/dts/zynq-coraz7s.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/zynq-coraz7s.dtsi b/arch/arm/boot/dts/zynq-coraz7s.dtsi index 09d8740a80bb73..7257bf30bfee48 100644 --- a/arch/arm/boot/dts/zynq-coraz7s.dtsi +++ b/arch/arm/boot/dts/zynq-coraz7s.dtsi @@ -41,6 +41,11 @@ #address-cells = <0x1>; #size-cells = <0x1>; ranges; + + axi_sysid_0: axi-sysid-0@45000000 { + compatible = "adi,axi-sysid-1.00.a"; + reg = <0x45000000 0x10000>; + }; }; }; From 7a11ad895b935913a0ec27bf0f976b480986800c Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Tue, 3 Aug 2021 17:47:07 +0300 Subject: [PATCH 303/407] net: phy: adin1100: Add ADIN1110 PHY_ID The PHY encapsulated in the ADIN1110 MAC-PHY is identical with the stand-alone version. Add the ADIN1110 PHY to the maatch device ID list in order to be discovered by the PAL after ADIN1110 registers its own MDIO bus. Signed-off-by: Alexandru Tachici --- drivers/net/phy/adin1100.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/phy/adin1100.c b/drivers/net/phy/adin1100.c index 6ec6c367484ca7..a165c737b51415 100644 --- a/drivers/net/phy/adin1100.c +++ b/drivers/net/phy/adin1100.c @@ -15,6 +15,7 @@ #include #define PHY_ID_ADIN1100 0x0283bc81 +#define PHY_ID_ADIN1110 0x0283bc91 static const int phy_10_features_array[] = { ETHTOOL_LINK_MODE_10baseT_Full_BIT, @@ -128,6 +129,8 @@ static int adin_match_phy_device(struct phy_device *phydev) switch (id) { case PHY_ID_ADIN1100: return 1; + case PHY_ID_ADIN1110: + return 1; default: return 0; } @@ -502,6 +505,7 @@ module_phy_driver(adin_driver); static struct mdio_device_id __maybe_unused adin_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1100) }, + { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1110) }, { } }; From 757a6117f7ff1bdc08e01f8ffca92b033c91e8e1 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Tue, 3 Aug 2021 17:58:00 +0300 Subject: [PATCH 304/407] net: adi: adin1110: Add initial support The ADIN1110 is a low power single port 10BASE-T1L MAC-PHY designed for industrial Ethernet applications. It integrates an Ethernet PHY core with a MAC and all the associated analog circuitry, input and output clock buffering. ADIN1110 MAC-PHY encapsulates the ADIN1100 PHY. The PHY registers can be accessed through the MDIO MAC registers. We are registering an MDIO bus with custom read/write in order to let the PHY to be discovered by the PAL. This will let the ADIN1100 Linux driver to probe and take control of the PHY. Co-developed-by: Lennart Franzen Signed-off-by: Lennart Franzen Signed-off-by: Alexandru Tachici --- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/adi/Kconfig | 28 + drivers/net/ethernet/adi/Makefile | 6 + drivers/net/ethernet/adi/adin1110.c | 968 ++++++++++++++++++++++++++++ 5 files changed, 1004 insertions(+) create mode 100644 drivers/net/ethernet/adi/Kconfig create mode 100644 drivers/net/ethernet/adi/Makefile create mode 100644 drivers/net/ethernet/adi/adin1110.c diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index de50e8b9e65628..22520f312afce9 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -116,6 +116,7 @@ config LANTIQ_XRX200 Support for the PMAC of the Gigabit switch (GSWIP) inside the Lantiq / Intel VRX200 VDSL SoC +source "drivers/net/ethernet/adi/Kconfig" source "drivers/net/ethernet/marvell/Kconfig" source "drivers/net/ethernet/mediatek/Kconfig" source "drivers/net/ethernet/mellanox/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index f8f38dcb5f8a05..0dabe43f1b4969 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_NET_VENDOR_3COM) += 3com/ obj-$(CONFIG_NET_VENDOR_8390) += 8390/ obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/ +obj-$(CONFIG_NET_VENDOR_ADI) += adi/ obj-$(CONFIG_GRETH) += aeroflex/ obj-$(CONFIG_NET_VENDOR_AGERE) += agere/ obj-$(CONFIG_NET_VENDOR_ALACRITECH) += alacritech/ diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig new file mode 100644 index 00000000000000..edb9a6b4921374 --- /dev/null +++ b/drivers/net/ethernet/adi/Kconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +# +# Analog Devices device configuration +# + +config NET_VENDOR_ADI + bool "Analog Devices devices" + default y + depends on SPI + help + If you have a network (Ethernet) card belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about ADI devices. If you say Y, you will be asked + for your specific card in the following questions. + +if NET_VENDOR_ADI + +config ADIN1110 + tristate "Analog Devices ADIN1110 MAC-PHY" + depends on SPI + select CRC8 + help + Say yes here to build support for Analog Devices ADIN1110 + Low Power 10BASE-T1L Ethernet MAC-PHY. + +endif # NET_VENDOR_ADI diff --git a/drivers/net/ethernet/adi/Makefile b/drivers/net/ethernet/adi/Makefile new file mode 100644 index 00000000000000..d0383d94303c80 --- /dev/null +++ b/drivers/net/ethernet/adi/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +# +# Makefile for the Analog Devices network device drivers. +# + +obj-$(CONFIG_ADIN1110) += adin1110.o diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c new file mode 100644 index 00000000000000..9ba74bd08d950c --- /dev/null +++ b/drivers/net/ethernet/adi/adin1110.c @@ -0,0 +1,968 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* ADIN1110 Low Power 10BASE-T1L Ethernet MAC-PH + * + * Copyright 2021 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ADIN1110_PHY_ID 0x1 + +#define ADIN1110_CONFIG2 0x06 +#define ADIN1110_CRC_APPEND BIT(5) +#define ADIN1110_FWD_UNK2HOST BIT(2) + +#define ADIN1110_STATUS0 0x08 + +#define ADIN1110_STATUS1 0x09 +#define ADIN1110_SPI_ERR BIT(10) +#define ADIN1110_RX_RDY BIT(4) +#define ADIN1110_TX_RDY BIT(3) + +#define ADIN1110_IMASK1 0x0D +#define ADIN1110_SPI_ERR_IRQ BIT(10) +#define ADIN1110_RX_RDY_IRQ BIT(4) +#define ADIN1110_TX_RDY_IRQ BIT(3) +#define ADIN1110_LINK_CHANGE_IRQ BIT(1) + +#define ADIN1110_MDIOACC 0x20 +#define ADIN1110_MDIO_TRDONE BIT(31) +#define ADIN1110_MDIO_TAERR BIT(30) +#define ADIN1110_MDIO_ST GENMASK(29, 28) +#define ADIN1110_MDIO_OP GENMASK(27, 26) +#define ADIN1110_MDIO_PRTAD GENMASK(25, 21) +#define ADIN1110_MDIO_DEVAD GENMASK(20, 16) +#define ADIN1110_MDIO_DATA GENMASK(15, 0) + +#define ADIN1110_TX_FSIZE 0x30 +#define ADIN1110_TX 0x31 +#define ADIN1110_TX_SPACE 0x32 +#define ADIN1110_RX_THRESH 0x33 +#define ADIN1110_TX_THRESH 0x34 + +#define ADIN1110_FIFO_CLR 0x36 +#define ADIN1110_FIFO_SIZE 0x3E +#define ADIN1110_TFC 0x3F + +#define ADIN1110_MAC_ADDR_FILTER_UPR 0x50 +#define ADIN1110_MAC_ADDR_APPLY2PORT BIT(30) +#define ADIN1110_MAC_ADDR_HOST_PRI BIT(19) +#define ADIN1110_MAC_ADDR_TO_HOST BIT(16) +#define ADIN1110_MAC_ADDR GENMASK(15, 0) + +#define ADIN1110_MAC_ADDR_FILTER_LWR 0x51 + +#define ADIN1110_MAC_ADDR_MASK_UPR 0x70 +#define ADIN1110_MAC_ADDR_MASK_LWR 0x71 + +#define ADIN1110_RX_FSIZE 0x90 +#define ADIN1110_RX 0x91 + +#define ADIN1110_RX_FRM_CNT 0xA0 +#define ADIN1110_RX_MCAST_CNT 0xA2 +#define ADIN1110_RX_CRC_ERR_CNT 0xA4 +#define ADIN1110_RX_ALGN_ERR_CNT 0xA5 +#define ADIN1110_RX_LS_ERR_CNT 0xA6 +#define ADIN1110_RX_PHY_ERR_CNT 0xA7 +#define ADIN1110_RX_DROP_FULL_CNT 0xAC + +#define ADIN1110_TX_FRM_CNT 0xA8 +#define ADIN1110_TX_MCAST_CNT 0xAA + +#define ADIN1110_CLEAR_STATUS0 0x1F7F +#define ADIN1110_CLEAR_STATUS1 0x1F01D0A + +/* MDIO_OP codes */ +#define ADIN1110_MDIO_OP_WR 0x1 +#define ADIN1110_MDIO_OP_RD 0x3 + +#define ADIN1110_CD BIT(7) +#define ADIN1110_WRITE BIT(5) + +#define ADIN1110_MAX_BUFF 2048 +#define ADIN1110_WR_HEADER_LEN 2 +#define ADIN1110_FRAME_HEADER_LEN 2 +#define ADIN1110_INTERNAL_SIZE_HEADER_LEN 2 +#define ADIN1110_RD_HEADER_LEN 3 +#define ADIN1110_REG_LEN 4 +#define ADIN1110_FEC_LEN 4 + +#define ADIN1110_PHY_ID_VAL 0x0283BC91 + +#define ADIN1110_TX_SPACE_MAX 0x0FFF + +DECLARE_CRC8_TABLE(adin1110_crc_table); + +struct adin1110_priv { + struct mutex lock; /* protect spi */ + spinlock_t state_lock; /* protect RX mode */ + struct work_struct tx_work; + u32 tx_space; + u64 rx_bytes; + u64 tx_bytes; + struct work_struct rx_mode_work; + u32 flags; + struct sk_buff_head txq; + struct mii_bus *mii_bus; + struct phy_device *phydev; + struct net_device *netdev; + struct spi_device *spidev; + bool append_crc; + int irq; + u8 data[ADIN1110_MAX_BUFF] ____cacheline_aligned; +}; + +static u8 adin1110_crc_data(u8 *data, u32 len) +{ + return crc8(adin1110_crc_table, data, len, 0); +} + +static int adin1110_read_reg(struct adin1110_priv *priv, u16 reg, u32 *val) +{ + struct spi_transfer t[2] = {0}; + __le16 __reg = cpu_to_le16(reg); + u32 header_len = ADIN1110_RD_HEADER_LEN; + u32 read_len = ADIN1110_REG_LEN; + int ret; + + priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), __reg); + priv->data[1] = FIELD_GET(GENMASK(7, 0), __reg); + priv->data[2] = 0x00; + + if (priv->append_crc) { + priv->data[2] = adin1110_crc_data(&priv->data[0], 2); + priv->data[3] = 0x00; + header_len++; + } + + t[0].tx_buf = &priv->data[0]; + t[0].len = header_len; + + if (priv->append_crc) + read_len++; + + memset(&priv->data[header_len], 0, read_len); + t[1].rx_buf = &priv->data[header_len]; + t[1].len = read_len; + + ret = spi_sync_transfer(priv->spidev, t, 2); + if (ret) + return ret; + + if (priv->append_crc) { + u8 recv_crc; + u8 crc; + + crc = adin1110_crc_data(&priv->data[header_len], ADIN1110_REG_LEN); + recv_crc = priv->data[header_len + ADIN1110_REG_LEN]; + + if (crc != recv_crc) { + netdev_err(priv->netdev, "CRC error."); + return -EBADMSG; + } + } + + *val = get_unaligned_be32(&priv->data[header_len]); + + return ret; +} + +static int adin1110_write_reg(struct adin1110_priv *priv, u16 reg, u32 val) +{ + u32 header_len = ADIN1110_WR_HEADER_LEN; + u32 write_len = ADIN1110_REG_LEN; + __le16 __reg = cpu_to_le16(reg); + + priv->data[0] = ADIN1110_CD | ADIN1110_WRITE | FIELD_GET(GENMASK(12, 8), __reg); + priv->data[1] = FIELD_GET(GENMASK(7, 0), __reg); + + if (priv->append_crc) { + priv->data[2] = adin1110_crc_data(&priv->data[0], header_len); + header_len++; + } + + put_unaligned_be32(val, &priv->data[header_len]); + if (priv->append_crc) { + priv->data[header_len + write_len] = adin1110_crc_data(&priv->data[header_len], + write_len); + write_len++; + } + + return spi_write(priv->spidev, &priv->data[0], header_len + write_len); +} + +static int adin1110_set_bits(struct adin1110_priv *priv, u16 reg, unsigned long mask, + unsigned long val) +{ + u32 write_val; + int ret; + + ret = adin1110_read_reg(priv, reg, &write_val); + if (ret < 0) + return ret; + + set_mask_bits(&write_val, mask, val); + + return adin1110_write_reg(priv, reg, write_val); +} + +static int adin1110_round_len(int len) +{ + /* can read/write only mutiples of 4 bytes of payload */ + len = ALIGN(len, 4); + + /* NOTE: ADIN1110_WR_HEADER_LEN should be used for write ops. */ + if (len + ADIN1110_RD_HEADER_LEN > ADIN1110_MAX_BUFF) + return -EINVAL; + + return len; +} + +static int adin1110_read_fifo(struct adin1110_priv *priv) +{ + u32 header_len = ADIN1110_RD_HEADER_LEN; + __le16 __reg = cpu_to_le16(ADIN1110_RX); + struct spi_transfer t[2] = {0}; + struct sk_buff *rxb; + u32 frame_size; + u32 frame_size_no_fcs; + int round_len; + int ret; + + ret = adin1110_read_reg(priv, ADIN1110_RX_FSIZE, &frame_size); + if (ret < 0) + return ret; + + /* the read frame size includes the extra 2 bytes from the ADIN1110 frame header */ + if (frame_size < ADIN1110_FRAME_HEADER_LEN + ADIN1110_FEC_LEN) + return ret; + + round_len = adin1110_round_len(frame_size); + if (round_len < 0) + return ret; + + frame_size_no_fcs = frame_size - ADIN1110_FRAME_HEADER_LEN - ADIN1110_FEC_LEN; + + rxb = netdev_alloc_skb(priv->netdev, frame_size_no_fcs); + if (!rxb) + return -ENOMEM; + + memset(priv->data, 0, round_len + ADIN1110_RD_HEADER_LEN); + + priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), __reg); + priv->data[1] = FIELD_GET(GENMASK(7, 0), __reg); + priv->data[2] = 0x00; + + if (priv->append_crc) { + priv->data[2] = adin1110_crc_data(&priv->data[0], 2); + priv->data[3] = 0x00; + header_len++; + } + + t[0].tx_buf = &priv->data[0]; + t[0].len = header_len; + + t[1].rx_buf = &priv->data[header_len]; + t[1].len = round_len; + + ret = spi_sync_transfer(priv->spidev, t, 2); + if (ret) { + kfree_skb(rxb); + return ret; + } + + skb_put(rxb, frame_size_no_fcs); + skb_copy_to_linear_data(rxb, &priv->data[header_len + ADIN1110_FRAME_HEADER_LEN], + frame_size_no_fcs); + + rxb->protocol = eth_type_trans(rxb, priv->netdev); + + netif_rx_ni(rxb); + + priv->rx_bytes += frame_size - ADIN1110_FRAME_HEADER_LEN; + + return 0; +} + +static int adin1110_write_fifo(struct adin1110_priv *priv, struct sk_buff *txb) +{ + __le16 __reg = cpu_to_le16(ADIN1110_TX); + u32 header_len = ADIN1110_WR_HEADER_LEN; + int padding = 0; + int round_len; + int padded_len; + int ret; + + /* Pad frame to 64 byte length, + * MAC nor PHY will otherwise add the + * required padding. + * The FEC will be added by the MAC internally. + */ + if (txb->len + ADIN1110_FEC_LEN < 64) + padding = 64 - (txb->len + ADIN1110_FEC_LEN); + + padded_len = txb->len + padding + ADIN1110_FRAME_HEADER_LEN; + + round_len = adin1110_round_len(padded_len); + if (round_len < 0) + return round_len; + + ret = adin1110_write_reg(priv, ADIN1110_TX_FSIZE, padded_len); + if (ret < 0) + return ret; + + memset(priv->data, 0, round_len + ADIN1110_WR_HEADER_LEN); + + priv->data[0] = ADIN1110_CD | ADIN1110_WRITE | FIELD_GET(GENMASK(12, 8), __reg); + priv->data[1] = FIELD_GET(GENMASK(7, 0), __reg); + if (priv->append_crc) { + priv->data[2] = adin1110_crc_data(&priv->data[0], 2); + header_len++; + } + + memcpy(&priv->data[header_len + ADIN1110_FRAME_HEADER_LEN], txb->data, txb->len); + + ret = spi_write(priv->spidev, &priv->data[0], round_len + header_len); + if (ret < 0) + return ret; + + priv->tx_bytes += txb->len; + + return 0; +} + +static int adin1110_read_mdio_acc(struct adin1110_priv *priv) +{ + u32 val; + int ret; + + ret = adin1110_read_reg(priv, ADIN1110_MDIOACC, &val); + if (ret < 0) + return 0; + + return val; +} + +static int adin1110_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + struct adin1110_priv *priv = bus->priv; + u32 val = 0; + int ret; + + mutex_lock(&priv->lock); + + val |= FIELD_PREP(ADIN1110_MDIO_OP, ADIN1110_MDIO_OP_RD); + val |= FIELD_PREP(ADIN1110_MDIO_ST, 0x1); + val |= FIELD_PREP(ADIN1110_MDIO_PRTAD, 0x1); + val |= FIELD_PREP(ADIN1110_MDIO_DEVAD, reg); + + /* write the clause 22 read command to the chip */ + ret = adin1110_write_reg(priv, ADIN1110_MDIOACC, val); + if (ret < 0) { + mutex_unlock(&priv->lock); + return ret; + } + + /* ADIN1110_MDIO_TRDONE BIT of the ADIN1110_MDIOACC + * register is set when the read is done. + * After the transaction is done, ADIN1110_MDIO_DATA + * bitfield of ADIN1110_MDIOACC register will contain + * the requested register value. + */ + ret = readx_poll_timeout(adin1110_read_mdio_acc, priv, val, (val & ADIN1110_MDIO_TRDONE), + 10000, 30000); + mutex_unlock(&priv->lock); + + if (ret < 0) + return ret; + + return (val & ADIN1110_MDIO_DATA); +} + +static int adin1110_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 reg_val) +{ + struct adin1110_priv *priv = bus->priv; + u32 val = 0; + int ret; + + mutex_lock(&priv->lock); + + val |= FIELD_PREP(ADIN1110_MDIO_OP, ADIN1110_MDIO_OP_WR); + val |= FIELD_PREP(ADIN1110_MDIO_ST, 0x1); + val |= FIELD_PREP(ADIN1110_MDIO_PRTAD, 0x1); + val |= FIELD_PREP(ADIN1110_MDIO_DEVAD, reg); + val |= FIELD_PREP(ADIN1110_MDIO_DATA, reg_val); + + /* write the clause 22 write command to the chip */ + ret = adin1110_write_reg(priv, ADIN1110_MDIOACC, val); + if (ret < 0) { + mutex_unlock(&priv->lock); + return ret; + } + + ret = readx_poll_timeout(adin1110_read_mdio_acc, priv, val, (val & ADIN1110_MDIO_TRDONE), + 10000, 30000); + mutex_unlock(&priv->lock); + + return ret; +} + +/* ADIN1110 MAC-PHY contains an ADIN1100 PHY. + * By registering a new MDIO bus we allow the PAL to discover + * the encapsulated PHY and probe the ADIN1100 driver. + */ +static int adin1110_register_mdiobus(struct adin1110_priv *priv, struct device *dev) +{ + struct mii_bus *mii_bus; + int ret; + + mii_bus = devm_mdiobus_alloc(dev); + if (!mii_bus) + return -ENOMEM; + + mii_bus->name = "adin1110_eth_mii"; + mii_bus->read = adin1110_mdio_read; + mii_bus->write = adin1110_mdio_write; + mii_bus->priv = priv; + mii_bus->parent = dev; + mii_bus->phy_mask = ~((u32)BIT(0)); + snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); + + ret = devm_mdiobus_register(dev, mii_bus); + if (ret) + return ret; + + priv->mii_bus = mii_bus; + + return 0; +} + +static void adin1110_read_frames(struct adin1110_priv *priv) +{ + u32 status1; + int ret; + + while (1) { + ret = adin1110_read_reg(priv, ADIN1110_STATUS1, &status1); + if (ret < 0) + return; + + if (!(status1 & ADIN1110_RX_RDY)) + break; + + ret = adin1110_read_fifo(priv); + if (ret < 0) + return; + } +} + +static irqreturn_t adin1110_irq(int irq, void *p) +{ + struct adin1110_priv *priv = p; + u32 status1; + u32 val; + int ret; + + mutex_lock(&priv->lock); + + adin1110_read_reg(priv, ADIN1110_STATUS1, &status1); + + if (priv->append_crc && (status1 & ADIN1110_SPI_ERR)) + netdev_warn(priv->netdev, "SPI CRC error on write.\n"); + + ret = adin1110_read_reg(priv, ADIN1110_TX_SPACE, &val); + if (ret < 0) { + mutex_unlock(&priv->lock); + return IRQ_HANDLED; + } + + priv->tx_space = val; + + if (status1 & ADIN1110_RX_RDY) + adin1110_read_frames(priv); + + /* clear IRQ sources */ + adin1110_write_reg(priv, ADIN1110_STATUS0, ADIN1110_CLEAR_STATUS0); + adin1110_write_reg(priv, ADIN1110_STATUS1, ADIN1110_CLEAR_STATUS1); + + mutex_unlock(&priv->lock); + + if (priv->tx_space > 0) + netif_wake_queue(priv->netdev); + + return IRQ_HANDLED; +} + +/* ADIN1110 can filter up to 16 MAC addresses, mac_nr here is the slot used */ +static int adin1110_write_mac_address(struct adin1110_priv *priv, int mac_nr, u8 *addr, u8 *mask) +{ + u32 offset = mac_nr * 2; + int ret; + u32 val; + + /* tell MAC to forward this DA to host */ + val = ADIN1110_MAC_ADDR_APPLY2PORT | ADIN1110_MAC_ADDR_TO_HOST; + val |= get_unaligned_be16(&addr[0]); + ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_FILTER_UPR + offset, val); + if (ret < 0) + return ret; + + val = get_unaligned_be32(&addr[2]); + ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_FILTER_LWR + offset, val); + if (ret < 0) + return ret; + + val = ADIN1110_MAC_ADDR_APPLY2PORT | ADIN1110_MAC_ADDR_TO_HOST; + val |= get_unaligned_be16(&mask[0]); + ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_UPR + offset, val); + if (ret < 0) + return ret; + + val = get_unaligned_be32(&mask[2]); + return adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_LWR + offset, val); +} + +static int adin1110_clear_mac_address(struct adin1110_priv *priv, int mac_nr) +{ + u32 offset = mac_nr * 2; + int ret; + + ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_FILTER_UPR + offset, 0); + if (ret < 0) + return ret; + + ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_FILTER_LWR + offset, 0); + if (ret < 0) + return ret; + + ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_UPR + offset, 0); + if (ret < 0) + return ret; + + return adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_LWR + offset, 0); +} + +static int adin1110_multicast_filter(struct adin1110_priv *priv, int mac_nr, bool accept_multicast) +{ + u8 mask[ETH_ALEN] = {0}; + u8 mac[ETH_ALEN] = {0}; + + if (accept_multicast) { + mask[0] = BIT(1); + mac[0] = BIT(1); + + return adin1110_write_mac_address(priv, mac_nr, mac, mask); + } + + return adin1110_clear_mac_address(priv, mac_nr); +} + +static int adin1110_set_mac_address(struct net_device *netdev, void *addr) +{ + struct adin1110_priv *priv = netdev_priv(netdev); + struct sockaddr *sa = addr; + u8 mask[ETH_ALEN]; + + if (netif_running(netdev)) + return -EBUSY; + + if (!is_valid_ether_addr(sa->sa_data)) + return -EADDRNOTAVAIL; + + ether_addr_copy(netdev->dev_addr, sa->sa_data); + memset(mask, 0xFF, ETH_ALEN); + + return adin1110_write_mac_address(priv, 0, netdev->dev_addr, mask); +} + +static int adin1110_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +{ + if (!netif_running(netdev)) + return -EINVAL; + + if (!netdev->phydev) + return -ENODEV; + + return phy_mii_ioctl(netdev->phydev, rq, cmd); +} + +static void adin1110_rx_mode_work(struct work_struct *work) +{ + struct adin1110_priv *priv = container_of(work, struct adin1110_priv, rx_mode_work); + + mutex_lock(&priv->lock); + + adin1110_set_bits(priv, ADIN1110_CONFIG2, ADIN1110_FWD_UNK2HOST, + (priv->flags & IFF_PROMISC) ? ADIN1110_FWD_UNK2HOST : 0); + + adin1110_multicast_filter(priv, 2, !!(priv->flags & IFF_ALLMULTI)); + + mutex_unlock(&priv->lock); +} + +static void adin1110_set_rx_mode(struct net_device *dev) +{ + struct adin1110_priv *priv = netdev_priv(dev); + + spin_lock(&priv->state_lock); + + priv->flags = dev->flags; + schedule_work(&priv->rx_mode_work); + + spin_unlock(&priv->state_lock); +} + +static int adin1110_init_mac(struct adin1110_priv *priv) +{ + struct net_device *netdev = priv->netdev; + u8 mask[ETH_ALEN]; + u8 mac[ETH_ALEN]; + int ret; + + memset(mask, 0xFF, ETH_ALEN); + ret = adin1110_write_mac_address(priv, 0, netdev->dev_addr, mask); + if (ret < 0) { + netdev_err(netdev, "Could not set MAC address: %pM, %d\n", mac, ret); + return ret; + } + + memset(mac, 0xFF, ETH_ALEN); + ret = adin1110_write_mac_address(priv, 1, mac, mask); + if (ret < 0) { + netdev_err(netdev, "Could not set Broadcast MAC address: %d\n", ret); + return ret; + } + + return 0; +} + +static int adin1110_net_open(struct net_device *net_dev) +{ + struct adin1110_priv *priv = netdev_priv(net_dev); + u32 val; + int ret; + + mutex_lock(&priv->lock); + + val = ADIN1110_CRC_APPEND; + ret = adin1110_set_bits(priv, ADIN1110_CONFIG2, val, val); + if (ret < 0) { + mutex_unlock(&priv->lock); + return ret; + } + + val = ADIN1110_TX_RDY_IRQ | ADIN1110_RX_RDY_IRQ | ADIN1110_LINK_CHANGE_IRQ | + ADIN1110_SPI_ERR_IRQ; + ret = adin1110_set_bits(priv, ADIN1110_IMASK1, val, 0); + if (ret < 0) { + netdev_err(net_dev, "Failed to enable chip IRQs: %d\n", ret); + mutex_unlock(&priv->lock); + return ret; + } + + ret = adin1110_read_reg(priv, ADIN1110_TX_SPACE, &val); + if (ret < 0) { + netdev_err(net_dev, "Failed to read TX FIFO space: %d\n", ret); + mutex_unlock(&priv->lock); + return ret; + } + + priv->tx_space = val; + + ret = adin1110_init_mac(priv); + if (ret < 0) + return ret; + + mutex_unlock(&priv->lock); + + phy_start(priv->phydev); + + /* ADIN1110 INT_N pin will be used to signal the host */ + ret = request_threaded_irq(net_dev->irq, NULL, adin1110_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + net_dev->name, priv); + + if (ret < 0) { + netdev_err(net_dev, "Failed to get IRQ: %d\n", ret); + return ret; + } + + netif_start_queue(priv->netdev); + + return ret; +} + +static int adin1110_net_stop(struct net_device *net_dev) +{ + struct adin1110_priv *priv = netdev_priv(net_dev); + + netif_stop_queue(priv->netdev); + flush_work(&priv->tx_work); + phy_stop(priv->phydev); + free_irq(net_dev->irq, priv); + + return 0; +} + +static void adin1110_tx_work(struct work_struct *work) +{ + struct adin1110_priv *priv = container_of(work, struct adin1110_priv, tx_work); + struct sk_buff *txb; + bool last; + int ret; + + mutex_lock(&priv->lock); + + last = skb_queue_empty(&priv->txq); + + while (!last) { + txb = skb_dequeue(&priv->txq); + last = skb_queue_empty(&priv->txq); + + if (txb) { + ret = adin1110_write_fifo(priv, txb); + if (ret < 0) + netdev_err(priv->netdev, "Frame write error: %d\n", ret); + + dev_kfree_skb(txb); + } + } + + mutex_unlock(&priv->lock); +} + +static netdev_tx_t adin1110_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct adin1110_priv *priv = netdev_priv(dev); + netdev_tx_t netdev_ret = NETDEV_TX_OK; + u32 tx_space_needed; + + spin_lock(&priv->state_lock); + + tx_space_needed = skb->len + ADIN1110_FRAME_HEADER_LEN + ADIN1110_INTERNAL_SIZE_HEADER_LEN; + if (tx_space_needed > priv->tx_space) { + netif_stop_queue(dev); + netdev_ret = NETDEV_TX_BUSY; + } else { + priv->tx_space -= tx_space_needed; + skb_queue_tail(&priv->txq, skb); + } + + spin_unlock(&priv->state_lock); + + schedule_work(&priv->tx_work); + + return netdev_ret; +} + +void adin1110_ndo_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage) +{ + struct adin1110_priv *priv = netdev_priv(dev); + u32 val; + + mutex_lock(&priv->lock); + + adin1110_read_reg(priv, ADIN1110_RX_FRM_CNT, &val); + storage->rx_packets = val; + + adin1110_read_reg(priv, ADIN1110_TX_FRM_CNT, &val); + storage->tx_packets = val; + + storage->rx_bytes = priv->rx_bytes; + storage->tx_bytes = priv->tx_bytes; + + adin1110_read_reg(priv, ADIN1110_RX_CRC_ERR_CNT, &val); + storage->rx_errors += val; + + adin1110_read_reg(priv, ADIN1110_RX_ALGN_ERR_CNT, &val); + storage->rx_errors += val; + + adin1110_read_reg(priv, ADIN1110_RX_LS_ERR_CNT, &val); + storage->rx_errors += val; + + adin1110_read_reg(priv, ADIN1110_RX_PHY_ERR_CNT, &val); + storage->rx_errors += val; + + adin1110_read_reg(priv, ADIN1110_RX_DROP_FULL_CNT, &val); + storage->rx_dropped = val; + + adin1110_read_reg(priv, ADIN1110_RX_MCAST_CNT, &val); + storage->multicast = val; + + mutex_unlock(&priv->lock); +} + +static const struct net_device_ops adin1110_netdev_ops = { + .ndo_open = adin1110_net_open, + .ndo_stop = adin1110_net_stop, + .ndo_do_ioctl = adin1110_ioctl, + .ndo_start_xmit = adin1110_start_xmit, + .ndo_set_mac_address = adin1110_set_mac_address, + .ndo_set_rx_mode = adin1110_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_get_stats64 = adin1110_ndo_get_stats64, +}; + +static void adin1110_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *di) +{ + strscpy(di->driver, "ADIN1110", sizeof(di->driver)); + strscpy(di->version, "1.00", sizeof(di->version)); + strscpy(di->bus_info, dev_name(dev->dev.parent), sizeof(di->bus_info)); +} + +static const struct ethtool_ops adin1110_ethtool_ops = { + .get_drvinfo = adin1110_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, +}; + +static void adin1110_adjust_link(struct net_device *dev) +{ + struct phy_device *phydev = dev->phydev; + + if (!phydev->link) + phy_print_status(phydev); +} + +/* PHY ID is stored in the MAC registers too, check spi connection by reading it */ +static int adin1110_check_spi(struct adin1110_priv *priv) +{ + int ret; + u32 val; + + ret = adin1110_read_reg(priv, ADIN1110_PHY_ID, &val); + if (ret < 0) + return ret; + + if (val != ADIN1110_PHY_ID_VAL) { + netdev_err(priv->netdev, "PHY ID read: %x\n", val); + return -EIO; + } + + snprintf(priv->netdev->name, IFNAMSIZ, "adin1110-%u", priv->spidev->chip_select); + + return 0; +} + +static void adin1110_disconnect_phy(void *data) +{ + phy_disconnect(data); +} + +static int adin1110_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct adin1110_priv *priv; + struct net_device *netdev; + const u8 *mac_addr; + u8 mac[ETH_ALEN]; + int ret; + + netdev = devm_alloc_etherdev(dev, sizeof(struct adin1110_priv)); + if (!netdev) + return -ENOMEM; + + priv = netdev_priv(netdev); + priv->spidev = spi; + priv->netdev = netdev; + spi->bits_per_word = 8; + SET_NETDEV_DEV(netdev, dev); + + mutex_init(&priv->lock); + spin_lock_init(&priv->state_lock); + + INIT_WORK(&priv->tx_work, adin1110_tx_work); + INIT_WORK(&priv->rx_mode_work, adin1110_rx_mode_work); + + /* use of CRC on control and data transactions is pin dependent */ + priv->append_crc = device_property_read_bool(dev, "adi,spi-crc"); + if (priv->append_crc) + crc8_populate_msb(adin1110_crc_table, 0x7); + + mac_addr = device_get_mac_address(dev, mac, ETH_ALEN); + if (!mac_addr) { + netdev_err(netdev, "MAC address invalid: %pM, %d\n", mac, ret); + return -EINVAL; + } + + ether_addr_copy(netdev->dev_addr, mac); + + ret = adin1110_check_spi(priv); + if (ret < 0) { + netdev_err(netdev, "SPI read failed: %d\n", ret); + return ret; + } + + ret = adin1110_register_mdiobus(priv, dev); + if (ret < 0) { + netdev_err(netdev, "Could not register MDIO bus %d\n", ret); + return ret; + } + + skb_queue_head_init(&priv->txq); + + netdev->irq = spi->irq; + + netif_carrier_off(priv->netdev); + + /* FIXME: This should be changed to 10BASET1L when introduced to PAL */ + netdev->if_port = IF_PORT_10BASET; + netdev->netdev_ops = &adin1110_netdev_ops; + netdev->ethtool_ops = &adin1110_ethtool_ops; + + ret = devm_register_netdev(dev, netdev); + if (ret) { + dev_err(dev, "failed to register network device\n"); + return ret; + } + + /* there is only one PHY connected to our registered MDIO bus */ + priv->phydev = phy_find_first(priv->mii_bus); + if (!priv->phydev) + return -ENODEV; + + priv->phydev = phy_connect(netdev, phydev_name(priv->phydev), + adin1110_adjust_link, PHY_INTERFACE_MODE_MII); + if (IS_ERR(priv->phydev)) + return PTR_ERR(priv->phydev); + + return devm_add_action_or_reset(dev, adin1110_disconnect_phy, priv->phydev); +} + +static const struct of_device_id adin1110_match_table[] = { + { .compatible = "adi,adin1110" }, + { } +}; +MODULE_DEVICE_TABLE(of, adin1110_match_table); + +static struct spi_driver adin1110_driver = { + .driver = { + .name = "adin1110", + .of_match_table = adin1110_match_table, + }, + .probe = adin1110_probe, +}; +module_spi_driver(adin1110_driver); + +MODULE_DESCRIPTION("ADIN1110 Network driver"); +MODULE_AUTHOR("Alexandru Tachici "); +MODULE_LICENSE("Dual BSD/GPL"); From a6d26bf201ca893ad1bffcef601ec9fc860094ef Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Fri, 27 Aug 2021 11:56:55 +0300 Subject: [PATCH 305/407] dt-bindings: net: adin1110: Add docs Add bindings for the ADIN1110 MAC-PHY. Signed-off-by: Alexandru Tachici --- .../devicetree/bindings/net/adi,adin1110.yaml | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/adi,adin1110.yaml diff --git a/Documentation/devicetree/bindings/net/adi,adin1110.yaml b/Documentation/devicetree/bindings/net/adi,adin1110.yaml new file mode 100644 index 00000000000000..24c53e1dacef7e --- /dev/null +++ b/Documentation/devicetree/bindings/net/adi,adin1110.yaml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/net/adi,adin1110.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: ADI ADIN1110 MAC-PHY + +allOf: + - $ref: "ethernet-controller.yaml#" + +maintainers: + - Alexandru Tachici + +description: | + The ADIN1110 is a low power single port 10BASE-T1L MAC- + PHY designed for industrial Ethernet applications. It integrates + an Ethernet PHY core with a MAC and all the associated analog + circuitry, input and output clock buffering. + + The device has a 4-wire SPI interface for communication + between the MAC and host processor. + +properties: + compatible: + const: adi,adin1110 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + reg: + maxItems: 1 + + adi,spi-crc: + description: | + Enable CRC8 checks on SPI read/writes. + type: boolean + + interrupts: + maxItems: 1 + + phy@0: + description: | + ADIN1100 PHY that is present on the same chip as the MAC. + type: object + + properties: + reg: + const: 0 + + compatible: + const: ethernet-phy-id0283.bc91 + + required: + - compatible + - reg + +required: + - compatible + - reg + - interrupts + - phy + +additionalProperties: false + +examples: + - | + spi0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ethernet@0 { + compatible = "adi,adin1110"; + reg = <0>; + spi-max-frequency = <1000000>; + + adi,spi-crc; + + #address-cells = <1>; + #size-cells = <0>; + + interrupt-parent = <&gpio>; + interrupts = <25 2>; + + mac-address = [ CA 2F B7 10 23 63 ]; + + phy@0 { + compatible = "ethernet-phy-id0283.bc91"; + reg = <0>; + }; + }; + }; From b269ff566b73daa6694a11d2d6c7fad35ecea9ff Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Mon, 30 Aug 2021 17:06:53 +0300 Subject: [PATCH 306/407] Kconfig.adi: select ADIN1110 for build Add adin1110 MAC-PHY to ADI build. Signed-off-by: Alexandru Tachici --- Kconfig.adi | 1 + 1 file changed, 1 insertion(+) diff --git a/Kconfig.adi b/Kconfig.adi index 6ab58ad40de6bb..a81b67f6a5409a 100644 --- a/Kconfig.adi +++ b/Kconfig.adi @@ -48,6 +48,7 @@ config KERNEL_ALL_ADI_DRIVERS select AD525X_DPOT_SPI select ADIN_PHY select ADIN1100_PHY + select ADIN1110 select IPV6 select BRIDGE select MEDIA_USB_SUPPORT From 4279e904c94abd33b7e96d2b8f6a2679353c7abd Mon Sep 17 00:00:00 2001 From: Sergiu Arpadi Date: Thu, 21 Apr 2022 14:14:19 +0300 Subject: [PATCH 307/407] arch: arm64: dts: zcu102-fmcomms8: add sysid support Device tree was missing sysid node Signed-off-by: Sergiu Arpadi --- .../dts/xilinx/zynqmp-zcu102-rev10-adrv9009-fmcomms8.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009-fmcomms8.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009-fmcomms8.dts index a97f3370fa0dc1..21ca4de7a18ca4 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009-fmcomms8.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009-fmcomms8.dts @@ -296,5 +296,10 @@ adi,axi-pl-fifo-enable; plddrbypass-gpios = <&gpio 146 0>; }; + + axi_sysid_0: axi-sysid-0@85000000 { + compatible = "adi,axi-sysid-1.00.a"; + reg = <0x85000000 0x2000>; + }; }; }; From 597a3d8d548e633cf4c5409bf546ede39e992bac Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 13 Apr 2022 15:57:59 +0200 Subject: [PATCH 308/407] iio: adc: ad9081: Move sync pin configuration after setup_[rx|tx] This will make sure these desired updates don't get clobbered. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 5e4525f4df5329..4b53835fddc0c3 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -2335,6 +2335,19 @@ static int ad9081_setup(struct spi_device *spi) } } + ret = ad9081_setup_tx(spi); + if (ret) + return ret; + + ret = ad9081_setup_rx(spi); + if (ret) + return ret; + + if (phy->config_sync_0a_cmos_en) { + adi_ad9081_jesd_rx_synca_mode_set(&phy->ad9081, 0); + adi_ad9081_hal_reg_set(&phy->ad9081, REG_SYNCA_CTRL_ADDR, 0x0); + } + if (phy->config_sync_01_swapped) { adi_ad9081_jesd_rx_syncb_driver_powerdown_set(&phy->ad9081, 0); adi_ad9081_hal_reg_set(&phy->ad9081, @@ -2353,20 +2366,6 @@ static int ad9081_setup(struct spi_device *spi) BF_SYNCB_RX_MODE_RC_INFO, 1); } - if (phy->config_sync_0a_cmos_en) { - adi_ad9081_jesd_rx_synca_mode_set(&phy->ad9081, 0); - adi_ad9081_hal_reg_set(&phy->ad9081, REG_SYNCA_CTRL_ADDR, 0x0); - } - - - ret = ad9081_setup_tx(spi); - if (ret) - return ret; - - ret = ad9081_setup_rx(spi); - if (ret) - return ret; - return 0; } From 637809a1929d8566fc94ce476e05c302b24b33d7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 13 Apr 2022 16:00:33 +0200 Subject: [PATCH 309/407] iio: adc: ad9081: Add attribute to control RX FFH GPIO mode This attribute allows switching between SPI and GPIO controlled FFH channel selection. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 43 +++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 4b53835fddc0c3..8a148072cd2c91 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -78,6 +78,7 @@ enum { CDDC_NCO_FREQ, TRX_ENABLE, CDDC_FFH_HOPF_SET, ADC_CDDC_FFH_TRIG_HOP_EN, + ADC_FFH_GPIO_MODE_SET, CDDC_FFH_INDEX_SET, DAC_FFH_GPIO_MODE_SET, DAC_FFH_FREQ_SET, @@ -238,6 +239,7 @@ struct ad9081_phy { u8 rx_main_ffh_mode[MAX_NUM_MAIN_DATAPATHS]; u8 rx_cddc_nco_channel_select_mode[MAX_NUM_MAIN_DATAPATHS]; bool rx_main_ffh_trig_en[MAX_NUM_MAIN_DATAPATHS]; + bool rx_main_ffh_gpio_en[MAX_NUM_MAIN_DATAPATHS]; adi_cms_chip_id_t chip_id; @@ -1214,15 +1216,15 @@ static ssize_t ad9081_ext_info_read(struct iio_dev *indio_dev, break; } - if (chan->output) { + if (chan->output) val = phy->tx_ffh_hopf_index[cddc_num]; - ret = 0; - } else { + else val = phy->rx_main_ffh_index[cddc_num]; - ret = 0; - } + + ret = 0; break; case ADC_CDDC_FFH_TRIG_HOP_EN: + case ADC_FFH_GPIO_MODE_SET: case DAC_FFH_GPIO_MODE_SET: if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { ret = -EOPNOTSUPP; @@ -1231,11 +1233,13 @@ static ssize_t ad9081_ext_info_read(struct iio_dev *indio_dev, if (chan->output) { val = phy->tx_ffh_hopf_via_gpio_en; - ret = 0; } else { - val = phy->rx_main_ffh_trig_en[cddc_num]; - ret = 0; + if (private == ADC_FFH_GPIO_MODE_SET) + val = phy->rx_main_ffh_gpio_en[cddc_num]; + else + val = phy->rx_main_ffh_trig_en[cddc_num]; } + ret = 0; break; case DAC_FFH_FREQ_SET: if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { @@ -1536,6 +1540,7 @@ static ssize_t ad9081_ext_info_write(struct iio_dev *indio_dev, } break; case ADC_CDDC_FFH_TRIG_HOP_EN: + case ADC_FFH_GPIO_MODE_SET: case DAC_FFH_GPIO_MODE_SET: if (conv->id == CHIPID_AD9988 || conv->id == CHIPID_AD9986) { ret = -EOPNOTSUPP; @@ -1555,10 +1560,17 @@ static ssize_t ad9081_ext_info_write(struct iio_dev *indio_dev, adi_ad9081_jesd_rx_syncb_driver_powerdown_set(&phy->ad9081, !enable); } else { - ret = adi_ad9081_adc_ddc_coarse_trig_hop_en_set(&phy->ad9081, - cddc_mask, enable); - if (!ret) - phy->rx_main_ffh_trig_en[cddc_num] = enable; + if (private == ADC_FFH_GPIO_MODE_SET) { + ret = adi_ad9081_adc_ddc_coarse_nco_channel_select_via_gpio_set(&phy->ad9081, + cddc_mask, enable ? phy->rx_cddc_nco_channel_select_mode[cddc_num] : 0); + if (!ret) + phy->rx_main_ffh_gpio_en[cddc_num] = enable; + } else { + ret = adi_ad9081_adc_ddc_coarse_trig_hop_en_set(&phy->ad9081, + cddc_mask, enable); + if (!ret) + phy->rx_main_ffh_trig_en[cddc_num] = enable; + } } break; case DAC_FFH_FREQ_SET: @@ -1696,6 +1708,13 @@ static struct iio_chan_spec_ext_info rxadc_ext_info[] = { .shared = false, .private = ADC_CDDC_FFH_TRIG_HOP_EN, }, + { + .name = "main_ffh_gpio_mode_en", + .read = ad9081_ext_info_read, + .write = ad9081_ext_info_write, + .shared = false, + .private = ADC_FFH_GPIO_MODE_SET, + }, {}, }; From a8f4e19bc7c4d450a604f1903eaa3676a5d1cda4 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 13 Apr 2022 16:09:24 +0200 Subject: [PATCH 310/407] iio: adc: ad9081: GPIO_X resource sharing between NCO sync and DAC FFH This patch allows to reallocate GPIO_[0..5] for FFHx functions, while they can still be used for NCO master-slave synchronization. A device driver controlled GPIO can hereby used to control an external mux. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 50 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 8a148072cd2c91..1d3949cd618b35 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -164,6 +164,7 @@ struct ad9081_phy { struct gpio_desc *rx2_en_gpio; struct gpio_desc *tx1_en_gpio; struct gpio_desc *tx2_en_gpio; + struct gpio_desc *ms_sync_en_gpio; struct regulator *supply_reg; struct clk *clks[NUM_AD9081_CLKS]; @@ -322,6 +323,27 @@ static int adi_ad9081_adc_nco_sync(adi_ad9081_device_t *device, return API_CMS_ERROR_OK; } +int adi_ad9081_device_gpio_set_highz(adi_ad9081_device_t *device, u8 gpio_index) +{ + int err; + + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + AD9081_INVALID_PARAM_RETURN(gpio_index > 5); + + if ((gpio_index & 1) == 0) { + err = adi_ad9081_hal_bf_set(device, + REG_GPIO_CFG0_ADDR + (gpio_index >> 1), 0x0400, 0); + AD9081_ERROR_RETURN(err); + } else { + err = adi_ad9081_hal_bf_set(device, + REG_GPIO_CFG0_ADDR + (gpio_index >> 1), 0x0404, 0); + AD9081_ERROR_RETURN(err); + } + + return API_CMS_ERROR_OK; +} + static int ad9081_nco_sync(struct ad9081_phy *phy, bool master) { int ret; @@ -4582,6 +4604,9 @@ static int ad9081_jesd204_link_running(struct jesd204_dev *jdev, adi_ad9081_dac_duc_main_nco_hopf_gpio_as_hop_en_set(&phy->ad9081, phy->tx_ffh_hopf_via_gpio_en); + if (phy->ms_sync_en_gpio) + gpiod_set_value(phy->ms_sync_en_gpio, 0); + return JESD204_STATE_CHANGE_DONE; } @@ -4607,8 +4632,12 @@ static int ad9081_jesd204_setup_stage1(struct jesd204_dev *jdev, adi_cms_jesd_subclass_e subclass = JESD_SUBCLASS_0; int ret; - if (reason != JESD204_STATE_OP_REASON_INIT) + if (reason != JESD204_STATE_OP_REASON_INIT) { + if (phy->ms_sync_en_gpio) + gpiod_set_value(phy->ms_sync_en_gpio, 0); + return JESD204_STATE_CHANGE_DONE; + } dev_dbg(dev, "%s:%d reason %s\n", __func__, __LINE__, jesd204_state_op_reason_str(reason)); @@ -4663,6 +4692,16 @@ static int ad9081_jesd204_setup_stage1(struct jesd204_dev *jdev, if (ret != 0) return ret; + if (phy->ms_sync_en_gpio) + gpiod_set_value(phy->ms_sync_en_gpio, 1); + + if (jesd204_dev_is_top(jdev)) { + /* We need to make sure the master-slave master GPIO is enabled before we move on */ + ret = adi_ad9081_device_nco_sync_gpio_set(&phy->ad9081, phy->sync_ms_gpio_num, 1); + if (ret != 0) + return ret; + } + return JESD204_STATE_CHANGE_DONE; } @@ -4705,6 +4744,10 @@ static int ad9081_jesd204_setup_stage3(struct jesd204_dev *jdev, if (ret != 0) return ret; + ret = adi_ad9081_device_gpio_set_highz(&phy->ad9081, phy->sync_ms_gpio_num); + if (ret != 0) + return ret; + return JESD204_STATE_CHANGE_DONE; } @@ -4895,6 +4938,11 @@ static int ad9081_probe(struct spi_device *spi) if (IS_ERR(phy->tx2_en_gpio)) return PTR_ERR(phy->tx2_en_gpio); + phy->ms_sync_en_gpio = + devm_gpiod_get_optional(&spi->dev, "ms-sync-enable", GPIOD_OUT_LOW); + if (IS_ERR(phy->ms_sync_en_gpio)) + return PTR_ERR(phy->ms_sync_en_gpio); + ret = ad9081_parse_dt(phy, &spi->dev); if (ret < 0) { dev_err(&spi->dev, "Parsing devicetree failed (%d)\n", ret); From a68201fde384a6bd924261a6ed67fa3a5ce1e94a Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 13 Apr 2022 16:46:07 +0200 Subject: [PATCH 311/407] dts: vcu118_quad_ad9081.dtsi: Let the driver control GPIO_0 HDL mux mode The driver will control this mux, and move it to * 0 - Software controlled GPIO * 1 - LMFC based Master-Slave NCO sync Signed-off-by: Michael Hennerich --- arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi b/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi index 85565d849de8f2..85fe059bc9d739 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi @@ -273,15 +273,6 @@ }; }; -&axi_gpio_2 { - ad9081_gpio0_mux { - gpio-hog; - gpios = <44 GPIO_ACTIVE_HIGH>; - output-high; /* output-high gpio_mode - connect GPIO_0 of MxFE3 (output) to GPIO_0 of MxFE0,1,2 (input) */ - line-name = "GPIO_0 HDL mux mode"; - }; -}; - / { vref: regulator-vref { compatible = "regulator-fixed"; @@ -624,4 +615,6 @@ rx1-enable-gpios = <&axi_gpio 48 0>; tx2-enable-gpios = <&axi_gpio 60 0>; tx1-enable-gpios = <&axi_gpio 56 0>; + /* output-high gpio_mode - connect GPIO_0 of MxFE3 (output) to GPIO_0 of MxFE0,1,2 (input) */ + ms-sync-enable-gpios = <&axi_gpio_2 44 GPIO_ACTIVE_HIGH>; }; From d51a0565eec38a6ccbd5367a15468cd3f11fb1c6 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 13 Apr 2022 16:58:55 +0200 Subject: [PATCH 312/407] dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10: Add Rx/Tx FFH support This adds support for both SPI and GPIO controlled fast frequency hopping. Due to PCB limitations, TX can support 7 hop frequencies when controlled via GPIOs. Rx supports 16 hops. Signed-off-by: Michael Hennerich --- ...18_quad_ad9081_204b_txmode_9_rxmode_10.dts | 136 +++++++++++++++++- 1 file changed, 135 insertions(+), 1 deletion(-) diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts index 74256459462bf2..9f702b2856612d 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts @@ -8,7 +8,7 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2019-2020 Analog Devices Inc. + * Copyright (C) 2019-2022 Analog Devices Inc. */ #include @@ -95,6 +95,96 @@ #define AD9081_RX_JESD_S 1 #define AD9081_RX_JESD_HD 0 +#define AD9081_FFH_CHAN_SEL_MODE AD9081_FFH_CHAN_SEL_3GPIO_MODE + +&axi_ad9081_adxcvr_rx { + adi,sys-clk-select = ; + adi,out-clk-select = ; +}; + +&axi_ad9081_adxcvr_tx { + adi,sys-clk-select = ; + adi,out-clk-select = ; +}; + +/ { + mux0: mux-controller0 { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&axi_gpio_2 0 0>, <&axi_gpio_2 1 0>, <&axi_gpio_2 2 0>; + }; + + tx_mux0: mux-txffh { + compatible = "adi,gen_mux"; + mux-controls = <&mux0>; + mux-state-names = + "0", "1", "2", "3", "4", "5", "6", "7"; + label = "mux-txffh"; + }; + + mux1: mux-controller1 { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&axi_gpio_2 6 0>, <&axi_gpio_2 7 0>, + <&axi_gpio_2 8 0>, <&axi_gpio_2 9 0>; + }; + + rx_mux1: mux-rxffh { + compatible = "adi,gen_mux"; + mux-controls = <&mux1>; + mux-state-names = + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15"; + label = "mux-rxffh"; + }; + + mux2: mux-controller2 { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&axi_gpio_2 11 0>, <&axi_gpio_2 12 0>; + }; + + rx_mux2: mux-rxnco { + compatible = "adi,gen_mux"; + mux-controls = <&mux2>; + mux-state-names = + "0", "1", "2", "3"; + label = "mux-rxnco"; + }; + + mux3: mux-controller3 { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&axi_gpio_2 13 0>, <&axi_gpio_2 14 0>; + }; + + rx_mux3: mux-txnco { + compatible = "adi,gen_mux"; + mux-controls = <&mux3>; + mux-state-names = + "0", "1", "2", "3"; + label = "mux-txnco"; + }; +}; + +&axi_gpio_2 { + ad9081_gpio10 { + gpio-hog; + gpios = <10 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "GPIO_10 high"; + }; + ad9081_gpio5 { + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "GPIO_5 high"; + }; +}; &rx_dma { adi,channels { @@ -294,6 +384,13 @@ #address-cells = <1>; adi,adc-frequency-hz = /bits/ 64 ; adi,nyquist-zone = ; + adi,ffh-gpio-mux-sel = /bits/ 8 < + AD9081_PERI_SEL_SYNCINB1_N + AD9081_PERI_SEL_SYNCINB1_P + AD9081_PERI_SEL_GPIO6 + AD9081_PERI_SEL_GPIO7 + AD9081_PERI_SEL_GPIO8 + AD9081_PERI_SEL_GPIO9>; adi,main-data-paths { #address-cells = <1>; #size-cells = <0>; @@ -302,6 +399,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan0>, <&trx0_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx0_ad9081_adc1: adc@1 { @@ -309,6 +407,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 <(AD9081_RX_MAIN_NCO_SHIFT)>; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan1>, <&trx0_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx0_ad9081_adc2: adc@2 { @@ -316,6 +415,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan4>, <&trx0_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx0_ad9081_adc3: adc@3 { @@ -323,6 +423,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx0_ad9081_rx_fddc_chan5>, <&trx0_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -469,6 +570,13 @@ #address-cells = <1>; adi,adc-frequency-hz = /bits/ 64 ; adi,nyquist-zone = ; + adi,ffh-gpio-mux-sel = /bits/ 8 < + AD9081_PERI_SEL_SYNCINB1_N + AD9081_PERI_SEL_SYNCINB1_P + AD9081_PERI_SEL_GPIO6 + AD9081_PERI_SEL_GPIO7 + AD9081_PERI_SEL_GPIO8 + AD9081_PERI_SEL_GPIO9>; adi,main-data-paths { #address-cells = <1>; #size-cells = <0>; @@ -477,6 +585,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan0>, <&trx1_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx1_ad9081_adc1: adc@1 { @@ -484,6 +593,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan1>, <&trx1_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx1_ad9081_adc2: adc@2 { @@ -491,6 +601,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan4>, <&trx1_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx1_ad9081_adc3: adc@3 { @@ -498,6 +609,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx1_ad9081_rx_fddc_chan5>, <&trx1_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -644,6 +756,13 @@ #address-cells = <1>; adi,adc-frequency-hz = /bits/ 64 ; adi,nyquist-zone = ; + adi,ffh-gpio-mux-sel = /bits/ 8 < + AD9081_PERI_SEL_SYNCINB1_N + AD9081_PERI_SEL_SYNCINB1_P + AD9081_PERI_SEL_GPIO6 + AD9081_PERI_SEL_GPIO7 + AD9081_PERI_SEL_GPIO8 + AD9081_PERI_SEL_GPIO9>; adi,main-data-paths { #address-cells = <1>; #size-cells = <0>; @@ -652,6 +771,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan0>, <&trx2_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx2_ad9081_adc1: adc@1 { @@ -659,6 +779,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan1>, <&trx2_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx2_ad9081_adc2: adc@2 { @@ -666,6 +787,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan4>, <&trx2_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx2_ad9081_adc3: adc@3 { @@ -673,6 +795,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx2_ad9081_rx_fddc_chan5>, <&trx2_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; @@ -819,6 +942,13 @@ #address-cells = <1>; adi,adc-frequency-hz = /bits/ 64 ; adi,nyquist-zone = ; + adi,ffh-gpio-mux-sel = /bits/ 8 < + AD9081_PERI_SEL_SYNCINB1_N + AD9081_PERI_SEL_SYNCINB1_P + AD9081_PERI_SEL_GPIO6 + AD9081_PERI_SEL_GPIO7 + AD9081_PERI_SEL_GPIO8 + AD9081_PERI_SEL_GPIO9>; adi,main-data-paths { #address-cells = <1>; #size-cells = <0>; @@ -827,6 +957,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan0>, <&trx3_ad9081_rx_fddc_chan2>; /* Static for now */ }; trx3_ad9081_adc1: adc@1 { @@ -834,6 +965,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan1>, <&trx3_ad9081_rx_fddc_chan3>; /* Static for now */ }; trx3_ad9081_adc2: adc@2 { @@ -841,6 +973,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan4>, <&trx3_ad9081_rx_fddc_chan6>; /* Static for now */ }; trx3_ad9081_adc3: adc@3 { @@ -848,6 +981,7 @@ adi,decimation = ; adi,nco-frequency-shift-hz = /bits/ 64 ; adi,nco-mixer-mode = ; + adi,nco-channel-select-mode = /bits/ 8 ; //adi,crossbar-select = <&trx3_ad9081_rx_fddc_chan5>, <&trx3_ad9081_rx_fddc_chan7>; /* Static for now */ }; }; From c7dc7dde5cc3bf3fd637a932d4ceac5060ade789 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 13 Apr 2022 17:00:12 +0200 Subject: [PATCH 313/407] dts: zynqmp-zcu102-rev10-ad9081-m8-l4-ffh: Use gpio-muxes for FFH Use gpio-muxes for FFH instead of individual GPIO controls. Signed-off-by: Michael Hennerich --- .../zynqmp-zcu102-rev10-ad9081-m8-l4-ffh.dts | 152 +++++++++--------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-ffh.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-ffh.dts index dd25913a5d5ba0..95c7e54da53c7d 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-ffh.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9081-m8-l4-ffh.dts @@ -13,79 +13,79 @@ #include "zynqmp-zcu102-rev10-ad9081-m8-l4.dts" / { - ad9081_gpio_control@0 { - compatible = "adi,one-bit-adc-dac"; - #address-cells = <1>; - #size-cells = <0>; - - out-gpios = <&gpio 110 0>, <&gpio 111 0>, <&gpio 112 0>, - <&gpio 113 0>, <&gpio 114 0>, <&gpio 115 0>, - <&gpio 116 0>, <&gpio 117 0>, <&gpio 118 0>, - <&gpio 119 0>, <&gpio 120 0>, <&gpio 138 0>, - <&gpio 139 0>, <&gpio 140 0>, <&gpio 141 0>; - - label = "ad9081_gpio"; - - channel@0 { - reg = <0>; - label = "GPIO_0"; - }; - channel@1 { - reg = <1>; - label = "GPIO_1"; - }; - channel@2 { - reg = <2>; - label = "GPIO_2"; - }; - channel@3 { - reg = <3>; - label = "GPIO_3"; - }; - channel@4 { - reg = <4>; - label = "GPIO_4"; - }; - channel@5 { - reg = <5>; - label = "GPIO_5"; - }; - channel@6 { - reg = <6>; - label = "GPIO_6"; - }; - channel@7 { - reg = <7>; - label = "GPIO_7"; - }; - channel@8 { - reg = <8>; - label = "GPIO_8"; - }; - channel@9 { - reg = <9>; - label = "GPIO_9"; - }; - channel@10 { - reg = <10>; - label = "GPIO_10"; - }; - channel@11 { - reg = <11>; - label = "GPIO_SYNCIN1P"; - }; - channel@12 { - reg = <12>; - label = "GPIO_SYNCIN1N"; - }; - channel@13 { - reg = <13>; - label = "GPIO_SYNCOUT1P"; - }; - channel@14 { - reg = <14>; - label = "GPIO_SYNCOUT1N"; - }; + mux0: mux-controller0 { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&gpio 110 0>, <&gpio 111 0>, <&gpio 112 0>, + <&gpio 113 0>, <&gpio 114 0>; + }; + + tx_mux0: mux-txffh { + compatible = "adi,gen_mux"; + mux-controls = <&mux0>; + mux-state-names = + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "30"; + label = "mux-txffh"; + }; + + mux1: mux-controller1 { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&gpio 116 0>, <&gpio 117 0>, <&gpio 118 0>, + <&gpio 119 0>; + }; + + rx_mux1: mux-rxffh { + compatible = "adi,gen_mux"; + mux-controls = <&mux1>; + mux-state-names = + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15"; + label = "mux-rxffh"; + }; + + mux2: mux-controller2 { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&gpio 140 0>, <&gpio 141 0>; + }; + + rx_mux2: mux-rxnco { + compatible = "adi,gen_mux"; + mux-controls = <&mux2>; + mux-state-names = + "0", "1", "2", "3"; + label = "mux-rxnco"; + }; + + mux3: mux-controller3 { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&gpio 138 0>, <&gpio 139 0>; + }; + + rx_mux3: mux-txnco { + compatible = "adi,gen_mux"; + mux-controls = <&mux3>; + mux-state-names = + "0", "1", "2", "3"; + label = "mux-txnco"; + }; +}; + +&gpio { + ad9081_gpio5 { + gpio-hog; + gpios = <115 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "GPIO_5 high"; }; }; @@ -106,13 +106,13 @@ }; &ad9081_adc1 { - adi,nco-channel-select-mode = /bits/ 8 ; + adi,nco-channel-select-mode = /bits/ 8 ; }; &ad9081_adc2 { - adi,nco-channel-select-mode = /bits/ 8 ; + adi,nco-channel-select-mode = /bits/ 8 ; }; &ad9081_adc3 { - adi,nco-channel-select-mode = /bits/ 8 ; + adi,nco-channel-select-mode = /bits/ 8 ; }; From 86b17f42574093c9312f7399b2a9abeb0792eb3d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 13 Apr 2022 17:01:37 +0200 Subject: [PATCH 314/407] iio: adc: ad9361: Fix type for split_gain_table_abs_gain This needs to be signed since we handle signed values. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9361.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad9361.c b/drivers/iio/adc/ad9361.c index ae85e1a42f319c..b21e2129e27c84 100644 --- a/drivers/iio/adc/ad9361.c +++ b/drivers/iio/adc/ad9361.c @@ -543,7 +543,7 @@ static const u8 split_gain_table[RXGAIN_TBLS_END][SIZE_SPLIT_TABLE][3] = }}; -static const u8 split_gain_table_abs_gain[RXGAIN_TBLS_END][SIZE_SPLIT_TABLE] = +static const s8 split_gain_table_abs_gain[RXGAIN_TBLS_END][SIZE_SPLIT_TABLE] = {{ /* 800 MHz */ -1, -1, -1, -1, -1, -1, -1, 2, 8, 13, 19, 20, 21, 22, 23, 24, From 5236801e249bd3404519f2307311d499dbde7c2f Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 14 Apr 2022 13:22:22 +0200 Subject: [PATCH 315/407] microblaze: configs: adi_mb_defconfig: Add IIO generic MUX support This adds the generic MUX support used for AD9081 FFH. Signed-off-by: Michael Hennerich --- arch/microblaze/configs/adi_mb_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/microblaze/configs/adi_mb_defconfig b/arch/microblaze/configs/adi_mb_defconfig index 24147f2cf65f41..ab70c2722f1d65 100644 --- a/arch/microblaze/configs/adi_mb_defconfig +++ b/arch/microblaze/configs/adi_mb_defconfig @@ -166,8 +166,10 @@ CONFIG_AXI_ADXCVR=y CONFIG_AXI_JESD204B=y CONFIG_AXI_JESD204_TX=y CONFIG_AXI_JESD204_RX=y +CONFIG_IIO_GEN_MUX=y CONFIG_JESD204=y CONFIG_NVMEM_AXI_SYSID=y +CONFIG_MUX_GPIO=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y From de1ad2ef20148a413d20ef2215074724b2f3f1e4 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 14 Apr 2022 17:38:48 +0200 Subject: [PATCH 316/407] iio: multiplexer: iio-gen-mux: Fix potential NULL pointer access In case the user provided state strings are < max_states a NULL pointer might be accessed. Test for it. Signed-off-by: Michael Hennerich --- drivers/iio/multiplexer/iio-gen-mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/multiplexer/iio-gen-mux.c b/drivers/iio/multiplexer/iio-gen-mux.c index c29ba904f92b68..b97a00248c41cb 100644 --- a/drivers/iio/multiplexer/iio-gen-mux.c +++ b/drivers/iio/multiplexer/iio-gen-mux.c @@ -170,7 +170,7 @@ static ssize_t gen_mux_show(struct device *dev, break; case 1: for (i = 0; i < st->max_states; i++) { - if (strlen(st->strings[i])) + if (st->strings[i] && strlen(st->strings[i])) ret += sysfs_emit_at(buf, ret, "%s ", st->strings[i]); } From 10ef59d417caed25bd579714cb4ecdac90edf27d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 25 Apr 2022 16:30:41 +0200 Subject: [PATCH 317/407] ci: fix build inside docker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is yet another try to fix the build when using docker. It was already wrongly tried in commit b4f54a952278 ("ci: use latest ubuntu stable image for docker builds"). The issue is that by using the latest tag, the distro version used to build might change under our feet and break things. This was indeed happening as ubuntu:latest now points to 22.04 which brings gcc-arm 11.2 which does not work with our kernel tree. Fix this by using a version tag (in this case ubuntu 20.04) instead of latest as that should not change in a way that major updates will occur in it's packages and hence breaking the build. Fixes: b4f54a952278 ("ci: use latest ubuntu stable image for docker builds") Signed-off-by: Nuno Sá --- ci/travis/run-build-docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/travis/run-build-docker.sh b/ci/travis/run-build-docker.sh index 31cc7c4e427e09..44c362ef19f03b 100755 --- a/ci/travis/run-build-docker.sh +++ b/ci/travis/run-build-docker.sh @@ -18,7 +18,7 @@ else fi done export OS_TYPE=ubuntu - export OS_VERSION=latest + export OS_VERSION=20.04 prepare_docker_image run_docker_script run-build.sh fi From cc66b4c74349add7cc204edd8746f211c4bb440f Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 27 Apr 2022 13:03:26 +0200 Subject: [PATCH 318/407] dts: zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual: Remove node Remove duplicated data_offload nodes. Signed-off-by: Michael Hennerich --- ...v10-ad9082-204c-txmode22-rxmode23-dual.dts | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts index e6911b75ade197..ce52800338ee2c 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts @@ -184,26 +184,6 @@ adi,out-clk-select = ; }; -&fpga_axi { - axi_data_offload_tx0: axi-data-offload-tx0@9c440000 { - compatible = "adi,axi-data-offload-1.0.a"; - reg = <0x9c440000 0x10000>; - // adi,bringup; - // adi,oneshot; - // adi,bypass; - // adi,sync-config = <2>; - // adi,transfer-length = /bits/ 64 <0x10000>; // 2**16 bytes - }; - - axi_data_offload_rx0: axi-data-offload-rx0@9c450000 { - compatible = "adi,axi-data-offload-1.0.a"; - reg = <0x9c450000 0x10000>; - }; -}; - -&axi_ad9081_core_tx { - adi,axi-data-offload-connected = <&axi_data_offload_tx0>; -}; &spi1 { status = "okay"; From 515aeaab9bde8a0b63661c7f38eac84997493dd7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 27 Apr 2022 13:05:13 +0200 Subject: [PATCH 319/407] jesd204: jesd204-fsm: Fix paused/resume notice messages This fixes the paused/resume notice messages. They should print like the other messages the link_id and not the link index. Signed-off-by: Michael Hennerich --- drivers/jesd204/jesd204-fsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/jesd204/jesd204-fsm.c b/drivers/jesd204/jesd204-fsm.c index 4a8af5ecc0d405..2c162fe30bda7b 100644 --- a/drivers/jesd204/jesd204-fsm.c +++ b/drivers/jesd204/jesd204-fsm.c @@ -1200,7 +1200,7 @@ static void jesd204_fsm_set_paused_state(struct jesd204_dev *jdev, return; jesd204_notice(jdev, "JESD204[%u] %s state %s\n", - link_idx, + ol->link.link_id, paused ? "paused at" : "resuming from", jesd204_state_str(table[0].state)); @@ -1215,7 +1215,7 @@ static void jesd204_fsm_set_paused_state(struct jesd204_dev *jdev, continue; jesd204_notice(jdev, "JESD204[%u] %s state %s\n", - link_idx, + ol->link.link_id, paused ? "paused at" : "resuming from", jesd204_state_str(table[0].state)); From f458c9bd92746b16f235d2ff6146974f1e18dc84 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 27 Apr 2022 13:06:53 +0200 Subject: [PATCH 320/407] iio: jesd204: axi_jesd204_[rx|tx].c: Fix uninit for optional clocks Like in the init path we should use IS_ERR_OR_NULL. Signed-off-by: Michael Hennerich --- drivers/iio/jesd204/axi_jesd204_rx.c | 2 +- drivers/iio/jesd204/axi_jesd204_tx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/jesd204/axi_jesd204_rx.c b/drivers/iio/jesd204/axi_jesd204_rx.c index 5cb71ecd9fb060..576a6f385cdded 100644 --- a/drivers/iio/jesd204/axi_jesd204_rx.c +++ b/drivers/iio/jesd204/axi_jesd204_rx.c @@ -930,7 +930,7 @@ static int axi_jesd204_rx_jesd204_clks_enable(struct jesd204_dev *jdev, case JESD204_STATE_OP_REASON_UNINIT: if (__clk_is_enabled(jesd->device_clk)) clk_disable_unprepare(jesd->device_clk); - if (!IS_ERR(jesd->link_clk)) { + if (!IS_ERR_OR_NULL(jesd->link_clk)) { if (__clk_is_enabled(jesd->link_clk)) clk_disable_unprepare(jesd->link_clk); } diff --git a/drivers/iio/jesd204/axi_jesd204_tx.c b/drivers/iio/jesd204/axi_jesd204_tx.c index d816da5ba854b1..7544dcede88540 100644 --- a/drivers/iio/jesd204/axi_jesd204_tx.c +++ b/drivers/iio/jesd204/axi_jesd204_tx.c @@ -688,7 +688,7 @@ static int axi_jesd204_tx_jesd204_link_setup(struct jesd204_dev *jdev, clk_disable_unprepare(jesd->lane_clk); if (__clk_is_enabled(jesd->device_clk)) clk_disable_unprepare(jesd->device_clk); - if (!IS_ERR(jesd->link_clk)) { + if (!IS_ERR_OR_NULL(jesd->link_clk)) { if (__clk_is_enabled(jesd->link_clk)) clk_disable_unprepare(jesd->link_clk); } From 6e39082f8a72e16fc60c434ab2453df78d7cd4f3 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 27 Apr 2022 13:24:14 +0200 Subject: [PATCH 321/407] jesd204: jesd204-fsm: FSM messages include topology_id Instead of printing just JESD204[link_id] we prepend the topology_id as well: JESD204[topology_id:link_id]. This improves readability. Signed-off-by: Michael Hennerich --- drivers/jesd204/jesd204-fsm.c | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/jesd204/jesd204-fsm.c b/drivers/jesd204/jesd204-fsm.c index 2c162fe30bda7b..e005ab2d4f9a60 100644 --- a/drivers/jesd204/jesd204-fsm.c +++ b/drivers/jesd204/jesd204-fsm.c @@ -414,8 +414,8 @@ static int __jesd204_link_fsm_update_state(struct jesd204_dev *jdev, if (fsm_data->cur_state != JESD204_STATE_DONT_CARE && fsm_data->nxt_state != JESD204_STATE_DONT_CARE) - jesd204_info(jdev, "JESD204[%u] transition %s -> %s\n", - ol->link.link_id, + jesd204_info(jdev, "JESD204[%u:%u] transition %s -> %s\n", + jesd204_dev_top_dev(jdev)->topo_id, ol->link.link_id, jesd204_state_str(fsm_data->cur_state), jesd204_state_str(fsm_data->nxt_state)); @@ -597,8 +597,8 @@ static int jesd204_fsm_handle_con_cb(struct jesd204_dev *jdev_it, if (ret < 0) { ol = &jdev_top->active_links[link_idx]; jesd204_err(jdev_it, - "JESD204[%u] In %s got error from cb: %d%s\n", - ol->link.link_id, + "JESD204[%u:%u] In %s got error from cb: %d%s\n", + jdev_top->topo_id, ol->link.link_id, jesd204_state_str(fsm_data->nxt_state), ret, ol->fsm_ignore_errors ? " (ignoring!)" : ""); @@ -693,8 +693,8 @@ static int jesd204_fsm_test_and_set_busy(struct jesd204_dev_top *jdev_top, if (link_idx != JESD204_LINKS_ALL) { ol = &jdev_top->active_links[link_idx]; if (test_and_set_bit(JESD204_FSM_BUSY, &ol->flags)) { - jesd204_err(jdev, "JESD204[%u]: FSM is busy\n", - ol->link.link_id); + jesd204_err(jdev, "JESD204[%u:%u]: FSM is busy\n", + jdev_top->topo_id, ol->link.link_id); return -EBUSY; } return 0; @@ -703,8 +703,8 @@ static int jesd204_fsm_test_and_set_busy(struct jesd204_dev_top *jdev_top, for (link_idx = 0; link_idx < jdev_top->num_links; link_idx++) { ol = &jdev_top->active_links[link_idx]; if (test_and_set_bit(JESD204_FSM_BUSY, &ol->flags)) { - jesd204_err(jdev, "JESD204[%u]: FSM is busy\n", - ol->link.link_id); + jesd204_err(jdev, "JESD204[%u:%u]: FSM is busy\n", + jdev_top->topo_id, ol->link.link_id); goto err_unwind_busy; } } @@ -758,8 +758,8 @@ static int jesd204_validate_lnk_state(struct jesd204_dev *jdev, return -EINVALID_STATE; jesd204_warn(jdev, - "JESD204[%u] invalid link state: %s, exp: %s, nxt: %s\n", - ol->link.link_id, + "JESD204[%u:%u] invalid link state: %s, exp: %s, nxt: %s\n", + jesd204_dev_top_dev(jdev)->topo_id, ol->link.link_id, jesd204_state_str(ol->state), jesd204_state_str(cur_state), jesd204_state_str(nxt_state)); @@ -778,14 +778,14 @@ static int jesd204_validate_resuming_state(struct jesd204_dev *jdev, return 0; if (ol->fsm_paused && !resuming) { - jesd204_warn(jdev, "JESD204[%u] FSM is paused; a resume is required\n", - ol->link.link_id); + jesd204_warn(jdev, "JESD204[%u:%u] FSM is paused; a resume is required\n", + jesd204_dev_top_dev(jdev)->topo_id, ol->link.link_id); return -EINVAL; } if (!ol->fsm_paused && resuming) { - jesd204_warn(jdev, "JESD204[%u] FSM is NOT paused; a transition is required\n", - ol->link.link_id); + jesd204_warn(jdev, "JESD204[%u:%u] FSM is NOT paused; a transition is required\n", + jesd204_dev_top_dev(jdev)->topo_id, ol->link.link_id); return -EINVAL; } @@ -1199,8 +1199,8 @@ static void jesd204_fsm_set_paused_state(struct jesd204_dev *jdev, if (ol->fsm_paused == paused) return; - jesd204_notice(jdev, "JESD204[%u] %s state %s\n", - ol->link.link_id, + jesd204_notice(jdev, "JESD204[%u:%u] %s state %s\n", + jdev_top->topo_id, ol->link.link_id, paused ? "paused at" : "resuming from", jesd204_state_str(table[0].state)); @@ -1214,8 +1214,8 @@ static void jesd204_fsm_set_paused_state(struct jesd204_dev *jdev, if (ol->fsm_paused == paused) continue; - jesd204_notice(jdev, "JESD204[%u] %s state %s\n", - ol->link.link_id, + jesd204_notice(jdev, "JESD204[%u:%u] %s state %s\n", + jdev_top->topo_id, ol->link.link_id, paused ? "paused at" : "resuming from", jesd204_state_str(table[0].state)); From 7beeea5e0d38e48c9d9ac7e3a66e999946d521f8 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 27 Apr 2022 13:39:48 +0200 Subject: [PATCH 322/407] iio/jesd204/axi_jesd204_[rx|tx]: link running increase retry count This increases the retry count and gives the link a bit more time to enter DATA before we return error. Signed-off-by: Michael Hennerich --- drivers/iio/jesd204/axi_jesd204_rx.c | 2 +- drivers/iio/jesd204/axi_jesd204_tx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/jesd204/axi_jesd204_rx.c b/drivers/iio/jesd204/axi_jesd204_rx.c index 576a6f385cdded..b26e84244df40b 100644 --- a/drivers/iio/jesd204/axi_jesd204_rx.c +++ b/drivers/iio/jesd204/axi_jesd204_rx.c @@ -1013,7 +1013,7 @@ static int axi_jesd204_rx_jesd204_link_running(struct jesd204_dev *jdev, struct device *dev = jesd204_dev_to_device(jdev); struct axi_jesd204_rx *jesd = dev_get_drvdata(dev); unsigned int link_status; - int retry = 10; + int retry = 20; dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, lnk->link_id, jesd204_state_op_reason_str(reason)); diff --git a/drivers/iio/jesd204/axi_jesd204_tx.c b/drivers/iio/jesd204/axi_jesd204_tx.c index 7544dcede88540..de857e5b638a7d 100644 --- a/drivers/iio/jesd204/axi_jesd204_tx.c +++ b/drivers/iio/jesd204/axi_jesd204_tx.c @@ -788,7 +788,7 @@ static int axi_jesd204_tx_jesd204_link_running(struct jesd204_dev *jdev, struct device *dev = jesd204_dev_to_device(jdev); struct axi_jesd204_tx *jesd = dev_get_drvdata(dev); unsigned int link_status; - int retry = 10; + int retry = 20; dev_dbg(dev, "%s:%d link_num %u reason %s\n", __func__, __LINE__, lnk->link_id, jesd204_state_op_reason_str(reason)); From 54af027f4f108ab6f35ebf8f73edc1f8f7c28189 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 28 Apr 2022 12:01:14 +0200 Subject: [PATCH 323/407] firmware: Talise[TDD|Rx|Tx]ArmFirmware: Update to ARM Revision: 6.2.1 Signed-off-by: Michael Hennerich --- firmware/TaliseRxArmFirmware.bin | Bin 114688 -> 114688 bytes firmware/TaliseTDDArmFirmware.bin | Bin 114688 -> 114688 bytes firmware/TaliseTxArmFirmware.bin | Bin 114688 -> 114688 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/firmware/TaliseRxArmFirmware.bin b/firmware/TaliseRxArmFirmware.bin index 447716676ab36d619da1fd7deec55d17739e7de4..7981657eb511297583f72b0ab0b6c1a0104e98c2 100644 GIT binary patch delta 30576 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

X<}Egw(w?S8)r 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 G|NS2VwPE1^ delta 30581 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 AWdHyG diff --git a/firmware/TaliseTDDArmFirmware.bin b/firmware/TaliseTDDArmFirmware.bin index 447716676ab36d619da1fd7deec55d17739e7de4..7981657eb511297583f72b0ab0b6c1a0104e98c2 100644 GIT binary patch delta 30576 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

X<}Egw(w?S8)r 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 G|NS2VwPE1^ delta 30581 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 AWdHyG diff --git a/firmware/TaliseTxArmFirmware.bin b/firmware/TaliseTxArmFirmware.bin index 447716676ab36d619da1fd7deec55d17739e7de4..7981657eb511297583f72b0ab0b6c1a0104e98c2 100644 GIT binary patch delta 30576 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

X<}Egw(w?S8)r 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 G|NS2VwPE1^ delta 30581 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 AWdHyG From 881a6c20eb05b0da9357c9c2e968a876c478d8fe Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 11 Feb 2022 13:34:42 +0100 Subject: [PATCH 324/407] iio: adc: talise: Update to Talise API version: 3.6.2.1 * Update to Talise API version: 3.6.2.1 * Fix some white-space issus Signed-off-by: Michael Hennerich --- drivers/iio/adc/talise/linux_hal.h | 4 +- drivers/iio/adc/talise/talise.c | 68 +++++- drivers/iio/adc/talise/talise.h | 12 +- drivers/iio/adc/talise/talise_agc.c | 30 +-- drivers/iio/adc/talise/talise_agc.h | 2 +- drivers/iio/adc/talise/talise_agc_types.h | 2 +- drivers/iio/adc/talise/talise_arm.c | 2 +- drivers/iio/adc/talise/talise_arm.h | 2 +- drivers/iio/adc/talise/talise_arm_macros.h | 2 +- drivers/iio/adc/talise/talise_arm_types.h | 2 +- drivers/iio/adc/talise/talise_cals.c | 190 ++++++++++++++-- drivers/iio/adc/talise/talise_cals.h | 45 +++- drivers/iio/adc/talise/talise_cals_types.h | 11 +- drivers/iio/adc/talise/talise_error.c | 13 +- drivers/iio/adc/talise/talise_error.h | 2 +- drivers/iio/adc/talise/talise_error_types.h | 11 +- drivers/iio/adc/talise/talise_gpio.c | 14 +- drivers/iio/adc/talise/talise_gpio.h | 20 +- drivers/iio/adc/talise/talise_gpio_types.h | 4 +- drivers/iio/adc/talise/talise_hal.c | 2 +- drivers/iio/adc/talise/talise_hal.h | 2 +- drivers/iio/adc/talise/talise_jesd204.c | 15 +- drivers/iio/adc/talise/talise_jesd204.h | 2 +- drivers/iio/adc/talise/talise_jesd204_types.h | 2 +- drivers/iio/adc/talise/talise_radioctrl.c | 42 ++-- drivers/iio/adc/talise/talise_radioctrl.h | 4 +- .../iio/adc/talise/talise_radioctrl_types.h | 4 +- .../iio/adc/talise/talise_reg_addr_macros.h | 17 +- drivers/iio/adc/talise/talise_rx.c | 16 +- drivers/iio/adc/talise/talise_rx.h | 4 +- drivers/iio/adc/talise/talise_rx_types.h | 2 +- drivers/iio/adc/talise/talise_tx.c | 215 +++++++++++++++++- drivers/iio/adc/talise/talise_tx.h | 31 ++- drivers/iio/adc/talise/talise_tx_types.h | 34 ++- drivers/iio/adc/talise/talise_types.h | 18 +- drivers/iio/adc/talise/talise_user.c | 2 +- drivers/iio/adc/talise/talise_user.h | 2 +- drivers/iio/adc/talise/talise_version.h | 6 +- 38 files changed, 705 insertions(+), 151 deletions(-) diff --git a/drivers/iio/adc/talise/linux_hal.h b/drivers/iio/adc/talise/linux_hal.h index 05440d664ab596..5432e815d6b52a 100644 --- a/drivers/iio/adc/talise/linux_hal.h +++ b/drivers/iio/adc/talise/linux_hal.h @@ -9,9 +9,9 @@ #define IIO_TALISE_LINUX_HAL_H_ struct adrv9009_hal { - struct spi_device *spi; + struct spi_device *spi; struct gpio_desc *reset_gpio; - unsigned int logLevel; + unsigned int logLevel; }; #endif /* IIO_TALISE_LINUX_HAL_H_ */ diff --git a/drivers/iio/adc/talise/talise.c b/drivers/iio/adc/talise/talise.c index 689013bc410dac..c48689035e9e9a 100644 --- a/drivers/iio/adc/talise/talise.c +++ b/drivers/iio/adc/talise/talise.c @@ -4,7 +4,7 @@ * \brief Contains top level functions to support initialization and ctrol of * the Talise transceiver device. * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -378,9 +378,64 @@ uint32_t TALISE_initialize(taliseDevice_t *device, taliseInit_t *init) uint8_t orxFirDecBitField = 0; uint8_t digDeviceClockDiv = 0; uint32_t digRefClock_MHz = 0; - taliseInfo_t clearInfo = {(taliseStates_t)0,0,0,0,0,{0,0,(taliseHsDiv_t)0,0,0}, - (taliseGainMode_t)0,{0,0,0,0,0,0,0,0},(taliseTxAttenStepSize_t)0, - 0,0,0,0,0,0,0,(taliseRxDdc_t)0,0,0,0}; + taliseInfo_t clearInfo = + { + .devState = TAL_STATE_POWERONRESET, + .initializedChannels = 0, + .profilesValid = 0, + .errSource = 0, + .errCode = 0, + .clocks = + { + .deviceClock_kHz = 0, + .clkPllVcoFreq_kHz = 0, + .clkPllHsDiv = TAL_HSDIV_2, + .hsDigClkDiv2_Hz = 0, + .hsDigClkDiv4or5_Hz = 0, + .rfPllUseExternalLo = 0 + }, + .gainMode = TAL_MGC, + .gainIndexes = + { + .rx1MinGainIndex = 0, + .rx1MaxGainIndex = 0, + .rx2MinGainIndex = 0, + .rx2MaxGainIndex = 0, + .orx1MinGainIndex = 0, + .orx1MaxGainIndex = 0, + .orx2MinGainIndex = 0, + .orx2MaxGainIndex = 0 + }, + .txAttenStepSize = TAL_TXATTEN_0P05_DB, + .orxAdcStitchingEnabled = 0, + .usedGpiopins = 0, + .usedGpio3p3pins = 0, + .rxFramerNp = 0, + .orxFramerNp = 0, + .rxOutputRate_kHz = 0, + .txInputRate_kHz = 0, + .rxDdcMode = TAL_RXDDC_BYPASS, + .rxDualBandEnabled = 0, + .rxTotalM = 0, + .rxBandwidth_Hz = 0, + .txBandwidth_Hz = 0, + .orxBandwidth_Hz = 0, + .swTest = 0, + .deviceSiRev = 0, + .talErrFunctionTable = + { + .talErrorFunctionTable = {} + }, + .talFhmFreqRange = + { + .fhmMinFreq_MHz = 0, + .fhmMaxFreq_MHz = 0 + }, + .talFhmTriggerMode = TAL_FHM_GPIO_MODE, + .talFhmInitHopFreq_Hz = 0, + .talFhmMcsSync = 0 + }; + uint32_t agcClock_Hz = 0; uint32_t gainUpdateCount = 0; taliseAdcSampleXbar_t adcXbar = {(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0}; @@ -1771,6 +1826,7 @@ uint32_t TALISE_programFir(taliseDevice_t *device, talisefirName_t filterToProgr uint32_t TALISE_calculateDigitalClocks(taliseDevice_t *device, taliseDigClocks_t *digClocks) { talRecoveryActions_t retVal = TALACT_NO_ACTION; + uint8_t hsDivTimes10 = 25; uint8_t hsClkDivHsDigClk4or5 = 20; uint32_t localHsDigClkDiv2_Hz = 0; @@ -2691,7 +2747,7 @@ uint32_t TALISE_initDigitalClocks(taliseDevice_t *device, taliseDigClocks_t *clo { /* scaledRefClkMhz = 46.08 MHz */ vcoCalOffset = (vcoIndex == 11 || (vcoIndex > 35 && vcoIndex <= 37) || (vcoIndex > 29 && vcoIndex <= 34)|| vcoIndex == 40 || vcoIndex == 44) ? 14 :(vcoIndex <= 10 || vcoIndex > 44) ? - 15 : ((vcoIndex > 12 && vcoIndex <= 22) || (vcoIndex > 23 && vcoIndex <= 23) || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 23 && vcoIndex <= 25) || vcoIndex == 35) ? + 15 : ((vcoIndex > 12 && vcoIndex <= 25) || (vcoIndex > 26 && vcoIndex <= 29) || vcoIndex == 35) ? 12 : 13; loopFilterIcp = icp_46p08[vcoIndex-1]; @@ -2718,7 +2774,7 @@ uint32_t TALISE_initDigitalClocks(taliseDevice_t *device, taliseDigClocks_t *clo { /* scaledRefClkMhz = 76.8 MHz */ vcoCalOffset = (vcoIndex == 11 || (vcoIndex > 35 && vcoIndex <= 37) || (vcoIndex > 29 && vcoIndex <= 34)|| vcoIndex == 40 || vcoIndex == 44) ? 14 :(vcoIndex <= 10 || vcoIndex > 44) ? - 15 : ((vcoIndex > 12 && vcoIndex <= 22) || (vcoIndex > 23 && vcoIndex <= 23) || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 23 && vcoIndex <= 25) || vcoIndex == 35) ? + 15 : ((vcoIndex > 12 && vcoIndex <= 25) || (vcoIndex > 26 && vcoIndex <= 29) || vcoIndex == 35) ? 12 : 13; loopFilterIcp = icp_76p8[vcoIndex-1]; diff --git a/drivers/iio/adc/talise/talise.h b/drivers/iio/adc/talise/talise.h index 293f222743a25f..1a5a7bf2250810 100644 --- a/drivers/iio/adc/talise/talise.h +++ b/drivers/iio/adc/talise/talise.h @@ -4,7 +4,7 @@ * \brief Contains top level Talise related function prototypes for * talise.c * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -165,7 +165,7 @@ uint32_t TALISE_shutdown(taliseDevice_t *device); * A bit value of 0 indicates that the sync has not occured. * * - * \pre This function can be called any time after the device has been initialized and PLL lock status has + * \pre This function can be called any time after the device has been initialized and PLL lock status has * been verified. * * \dep_begin @@ -252,7 +252,7 @@ uint32_t TALISE_serializerReset(taliseDevice_t *device); /** * \brief Sets up the chip for multichip LOs Phase synchronization * - * LOs on multiple chips can be phase synchronized to support active + * LOs on multiple chips can be phase synchronized to support active * antenna system and beam forming applications.This function should * be run after all transceivers have finished the TALISE_setRfPllFrequency(), * and before TALISE_runInitCals(). @@ -531,7 +531,7 @@ uint32_t TALISE_getApiVersion (taliseDevice_t *device, uint32_t *siVer, uint32_t /** * \brief Reads back the silicon revision for the Talise Device - * + * * revision's bit | Description * ----------------|----------------- * 3:0 | minor revision @@ -542,8 +542,8 @@ uint32_t TALISE_getApiVersion (taliseDevice_t *device, uint32_t *siVer, uint32_t * \dep_end * * \param device Structure pointer to the Talise data structure containing settings - * \param revision Return value of the Talise silicon revision in hex where - upper nibble (4 bits) indicates the major revision and the lower nibble + * \param revision Return value of the Talise silicon revision in hex where + upper nibble (4 bits) indicates the major revision and the lower nibble indicates the minor revision. * * \retval TALACT_WARN_RESET_LOG recovery action for log reset diff --git a/drivers/iio/adc/talise/talise_agc.c b/drivers/iio/adc/talise/talise_agc.c index 49fcc83e58e8f2..bd8a9e8e0c6926 100644 --- a/drivers/iio/adc/talise/talise_agc.c +++ b/drivers/iio/adc/talise/talise_agc.c @@ -3,7 +3,7 @@ * \file talise_agc.c * \brief Contains Talise API AGC function calls * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -40,7 +40,7 @@ uint32_t TALISE_setupRxAgc(taliseDevice_t *device, taliseAgcCfg_t *rxAgcCtrl) static const uint8_t underRangeLowPowerGainStepRecoveryBitMask = 0x1F; static const uint8_t powerMeasurementDurationBitMask = 0x1F; static const uint8_t agcSlowLoopSettlingDelayBitMask = 0x7F; - static const uint8_t ip3OverRangeThreshBitMask = 0x3F; + static const uint8_t ip3OverRangeThreshBitMask = 0x3F; static const uint8_t apdHighThreshMin = 0x07; static const uint8_t apdHighThreshMax = 0x31; static const uint8_t apdLowGainModeHighThreshMin = 0x07; @@ -433,7 +433,7 @@ uint32_t TALISE_setupRxAgc(taliseDevice_t *device, taliseAgcCfg_t *rxAgcCtrl) IF_ERR_RETURN_U32(retVal); } - if ((rxAgcCtrl->agcPeak.apdLowGainModeLowThresh < apdLowGainModeLowThreshMin) || + if ((rxAgcCtrl->agcPeak.apdLowGainModeLowThresh < apdLowGainModeLowThreshMin) || (rxAgcCtrl->agcPeak.apdLowGainModeLowThresh > apdLowGainModeLowThreshMax)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, @@ -607,7 +607,7 @@ uint32_t TALISE_setupRxAgc(taliseDevice_t *device, taliseAgcCfg_t *rxAgcCtrl) return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INV_AGC_PKK_HB2THRSHCFG_PARAM, retVal, TALACT_ERR_CHECK_PARAM); } - + /* Because this field was added after production, preserve the past behavior if 0 is passed by setting to default */ if (rxAgcCtrl->agcPeak.hb2UnderRangeLowThreshExceededCnt == 0) { @@ -616,7 +616,7 @@ uint32_t TALISE_setupRxAgc(taliseDevice_t *device, taliseAgcCfg_t *rxAgcCtrl) halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_AGC_ADCOVRG_LOW_INT0_COUNTER, rxAgcCtrl->agcPeak.hb2UnderRangeLowThreshExceededCnt); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); - + /* Because this field was added after production, preserve the past behavior if 0 is passed by setting to default */ if (rxAgcCtrl->agcPeak.hb2UnderRangeMidThreshExceededCnt == 0) { @@ -771,7 +771,7 @@ uint32_t TALISE_setupRxAgc(taliseDevice_t *device, taliseAgcCfg_t *rxAgcCtrl) retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } - + if ((rxAgcCtrl->agcPower.powerLogShift << 2) & ~powerLogShiftBitMask) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, @@ -783,13 +783,13 @@ uint32_t TALISE_setupRxAgc(taliseDevice_t *device, taliseAgcCfg_t *rxAgcCtrl) retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } - + /* Because this field was added after production, preserve the past behavior if 0 is passed by setting to default */ if (rxAgcCtrl->agcPower.overRangeLowPowerGainStepAttack == 0) { rxAgcCtrl->agcPower.overRangeLowPowerGainStepAttack = 4; } - + if ((rxAgcCtrl->agcPower.overRangeLowPowerGainStepAttack) & ~overRangeLowPowerGainStepAttackBitMask) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, @@ -801,13 +801,13 @@ uint32_t TALISE_setupRxAgc(taliseDevice_t *device, taliseAgcCfg_t *rxAgcCtrl) retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } - + /* Because this field was added after production, preserve the past behavior if 0 is passed by setting to default */ if (rxAgcCtrl->agcPower.overRangeHighPowerGainStepAttack == 0) { rxAgcCtrl->agcPower.overRangeHighPowerGainStepAttack = 4; } - + if ((rxAgcCtrl->agcPower.overRangeHighPowerGainStepAttack) & ~overRangeHighPowerGainStepAttackBitMask) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, @@ -819,7 +819,7 @@ uint32_t TALISE_setupRxAgc(taliseDevice_t *device, taliseAgcCfg_t *rxAgcCtrl) retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } - + return (uint32_t)retVal; } @@ -1152,11 +1152,11 @@ uint32_t TALISE_getAgcPeakRegisters(taliseDevice_t *device, taliseAgcPeak_t *agc halError = talSpiReadField(device->devHalInfo, TALISE_ADDR_AGC_CONFIG1, &agcPeak->hb2OvrgSel, hb2OvrgSelMask, 5); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); - + halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_AGC_ADCOVRG_LOW_INT0_COUNTER, &agcPeak->hb2UnderRangeLowThreshExceededCnt); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); - + halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_AGC_ADCOVRG_LOW_INT1_COUNTER, &agcPeak->hb2UnderRangeMidThreshExceededCnt); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); @@ -1263,11 +1263,11 @@ uint32_t TALISE_getAgcPowerRegisters(taliseDevice_t *device, taliseAgcPower_t *a halError = talSpiReadField(device->devHalInfo, TALISE_ADDR_AGC_UPPER_POWER_THRESHOLD, &agcPower->upper1PowerThresh, upper1PowerThreshMask, 0); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); - + halError = talSpiReadField(device->devHalInfo, TALISE_ADDR_UPPER0_THRESHOLD_GAIN_STEP, &agcPower->overRangeLowPowerGainStepAttack, overRangeLowPowerGainStepAttackBitMask, 0); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); - + halError = talSpiReadField(device->devHalInfo, TALISE_ADDR_UPPER1_THRESHOLD_GAIN_STEP, &agcPower->overRangeHighPowerGainStepAttack, overRangeHighPowerGainStepAttackBitMask, 0); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); diff --git a/drivers/iio/adc/talise/talise_agc.h b/drivers/iio/adc/talise/talise_agc.h index 103cf94586b004..a51573a026d3b4 100644 --- a/drivers/iio/adc/talise/talise_agc.h +++ b/drivers/iio/adc/talise/talise_agc.h @@ -3,7 +3,7 @@ * \file talise_agc.h * \brief Contains Talise API AGC function prototypes for talise_agc.c * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_agc_types.h b/drivers/iio/adc/talise/talise_agc_types.h index d84c9116fbdf31..88086fbd5d4d47 100644 --- a/drivers/iio/adc/talise/talise_agc_types.h +++ b/drivers/iio/adc/talise/talise_agc_types.h @@ -3,7 +3,7 @@ * \file talise_agc_types.h * \brief Contains Talise API AGC data types * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_arm.c b/drivers/iio/adc/talise/talise_arm.c index a770097119f7bd..e2640e61edb81d 100644 --- a/drivers/iio/adc/talise/talise_arm.c +++ b/drivers/iio/adc/talise/talise_arm.c @@ -4,7 +4,7 @@ * \brief Contains functions to support interfacing with the TALISE internal * ARM processor * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_arm.h b/drivers/iio/adc/talise/talise_arm.h index 034cd752aacc8a..57b7849839d0a3 100644 --- a/drivers/iio/adc/talise/talise_arm.h +++ b/drivers/iio/adc/talise/talise_arm.h @@ -3,7 +3,7 @@ * \file talise_arm.h * \brief Contains Talise ARM related function prototypes for talise_arm.c * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_arm_macros.h b/drivers/iio/adc/talise/talise_arm_macros.h index abb7cc82e4a6e8..28f85ca6d8e633 100644 --- a/drivers/iio/adc/talise/talise_arm_macros.h +++ b/drivers/iio/adc/talise/talise_arm_macros.h @@ -3,7 +3,7 @@ * \file talise_arm_macros.h * \brief Contains Talise API miscellaneous macro definitions for ARM * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_arm_types.h b/drivers/iio/adc/talise/talise_arm_types.h index 9085173025948f..e3a2f67233653a 100644 --- a/drivers/iio/adc/talise/talise_arm_types.h +++ b/drivers/iio/adc/talise/talise_arm_types.h @@ -3,7 +3,7 @@ * \file talise_arm_types.h * \brief Contains Talise ARM data types * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_cals.c b/drivers/iio/adc/talise/talise_cals.c index f409c6e3daf7dd..a6b96b50c04613 100644 --- a/drivers/iio/adc/talise/talise_cals.c +++ b/drivers/iio/adc/talise/talise_cals.c @@ -3,7 +3,7 @@ * \file talise_cals.c * \brief Contains functions to support Talise init and tracking calibrations * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -27,7 +27,6 @@ uint32_t TALISE_runInitCals(taliseDevice_t *device, uint32_t calMask) #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_runInitCals()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -65,7 +64,6 @@ uint32_t TALISE_waitInitCals(taliseDevice_t *device, uint32_t timeoutMs, uint8_t #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_waitInitCals()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -131,7 +129,6 @@ uint32_t TALISE_checkInitCalComplete(taliseDevice_t *device, uint8_t *areCalsRun #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_checkInitCalComplete()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -206,7 +203,6 @@ uint32_t TALISE_abortInitCals(taliseDevice_t *device, uint32_t *calsCompleted) #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_abortInitCals()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -291,7 +287,6 @@ uint32_t TALISE_getInitCalStatus(taliseDevice_t *device, uint32_t *calsSincePowe #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getInitCalStatus()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -407,7 +402,6 @@ uint32_t TALISE_enableTrackingCals(taliseDevice_t *device, uint32_t enableMask) #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_enableTrackingCals()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -485,7 +479,6 @@ uint32_t TALISE_getEnabledTrackingCals(taliseDevice_t *device, uint32_t *enableM #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getEnabledTrackingCals()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -548,7 +541,6 @@ uint32_t TALISE_rescheduleTrackingCal(taliseDevice_t *device, taliseTrackingCali #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_rescheduleTrackingCal()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -638,7 +630,6 @@ uint32_t TALISE_setAllTrackCalState(taliseDevice_t *device, uint32_t calSubsetMa #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_setAllTrackCalState()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -713,7 +704,6 @@ uint32_t TALISE_getAllTrackCalState(taliseDevice_t *device, uint32_t *resumeCalM #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getAllTrackCalState()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -781,7 +771,6 @@ uint32_t TALISE_getTxLolStatus(taliseDevice_t *device, taliseTxChannels_t channe #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getTxLolStatus()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -858,7 +847,6 @@ uint32_t TALISE_getTxQecStatus(taliseDevice_t *device, taliseTxChannels_t channe #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getTxQecStatus()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -935,7 +923,6 @@ uint32_t TALISE_getRxQecStatus(taliseDevice_t *device, taliseRxChannels_t channe #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getRxQecStatus()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1012,7 +999,6 @@ uint32_t TALISE_getOrxQecStatus(taliseDevice_t *device, taliseObsRxChannels_t ch #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getOrxQecStatus()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1089,7 +1075,6 @@ uint32_t TALISE_getRxHd2Status(taliseDevice_t *device, taliseRxChannels_t channe #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getRxHd2Status()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1387,7 +1372,6 @@ uint32_t TALISE_resetExtTxLolChannel(taliseDevice_t *device, taliseTxChannels_t #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_resetExtTxLolChannel()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1463,7 +1447,6 @@ uint32_t TALISE_setRxHd2Config(taliseDevice_t *device, taliseRxHd2Config_t *hd2C #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_setRxHd2Config()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1526,7 +1509,6 @@ uint32_t TALISE_getRxHd2Config(taliseDevice_t *device, taliseRxHd2Config_t *hd2C #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getRxHd2Config()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1686,7 +1668,7 @@ uint32_t TALISE_setDigDcOffsetEn(taliseDevice_t *device, uint8_t enableMask) { dataToWrite |= (enableMask & ((uint8_t)TAL_DC_OFFSET_RX1 |(uint8_t) TAL_DC_OFFSET_RX2)); } - + halError = talSpiWriteField(device->devHalInfo, REG_ADDRESS, dataToWrite, 0x06, 1); /* Write RX enable bits to the register */ retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); @@ -1697,7 +1679,7 @@ uint32_t TALISE_setDigDcOffsetEn(taliseDevice_t *device, uint8_t enableMask) { dataToWrite |= ((enableMask & ((uint8_t)TAL_DC_OFFSET_ORX1 | (uint8_t)TAL_DC_OFFSET_ORX2)) >> 2); } - + halError = talSpiWriteField(device->devHalInfo, REG_ADDRESS, dataToWrite, 0x03, 0); /* Write Loopback, ORx1 and ORx2 enable bits to the register */ retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); @@ -1744,6 +1726,171 @@ uint32_t TALISE_getDigDcOffsetEn(taliseDevice_t *device,uint8_t *enableMask) return (uint32_t)retVal; } +uint32_t TALISE_getTrackingCalsBatchSize(taliseDevice_t *device, taliseTrackingCalBatchSize_t* batchsize_us) +{ + talRecoveryActions_t retVal = TALACT_NO_ACTION; + talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + + uint8_t armFieldValue[16] = { 0 }; + uint32_t radioStatus = 0; + uint8_t byteOffset = 0x3C; + uint32_t batchsizetime; + + static const uint32_t CODECHECK_PARAM_GETTCALBATCHSIZE_ERR1 = 2; + +#if TALISE_VERBOSE + adiHalErr_t halError = ADIHAL_OK; + + halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getTrackingCalsBatchSize()\n"); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); +#endif + + retValWarn = retVal; + + if (batchsize_us == NULL) + { + return (uint32_t)talApiErrHandler(device, + TAL_ERRHDL_INVALID_PARAM, + TAL_ERR_GETTCAL_BATCHSIZE_NULL_PARAM, + retVal, + TALACT_ERR_CHECK_PARAM); + } + + /* read radio state to make sure ARM is in radioOff/IDLE state or ready state */ + retVal = (talRecoveryActions_t)TALISE_getRadioState(device, &radioStatus); + IF_ERR_RETURN_U32(retVal); + + /* SW Test */ + if (device->devStateInfo.swTest == CODECHECK_PARAM_GETTCALBATCHSIZE_ERR1) + { + radioStatus = 0; + } + /* throw error if not in radioOff/IDLE state or ready state */ + if (((radioStatus & 0x07) != TALISE_ARM_RADIO_STATUS_IDLE) && + ((radioStatus & 0x07) != TALISE_ARM_RADIO_STATUS_READY)) + { + return (uint32_t)talApiErrHandler(device, + TAL_ERRHDL_API_FAIL, + TAL_ERR_GETTCAL_BATCH_SIZE_ARMSTATE_ERROR, + retVal, + TALACT_ERR_RESET_ARM); + } + + retVal = (talRecoveryActions_t)TALISE_readArmConfig(device, + TALISE_ARM_OBJECTID_CAL_SCHEDULER, + byteOffset, + &armFieldValue[0], + 16); + IF_ERR_RETURN_U32(retVal); + batchsizetime = (taliseTrackingCalBatchSize_t)((armFieldValue[1] << 2) + (armFieldValue[0])); + switch (batchsizetime) + { + case 500: *batchsize_us = TAL_TRACK_BATCH_SIZE_500_US; break; + case 200: *batchsize_us = TAL_TRACK_BATCH_SIZE_200_US; break; + return (uint32_t)talApiErrHandler(device, + TAL_ERRHDL_INVALID_PARAM, + TAL_ERR_GETTCAL_BATCHSIZE_INV_VALUE, + retVal, + TALACT_ERR_CHECK_PARAM); + } + + /* If no other higher priority errors, return possible log warning */ + if (retVal == TALACT_NO_ACTION) + { + retVal = retValWarn; + } + + return (uint32_t)retVal; +} + +uint32_t TALISE_setTrackingCalsBatchSize(taliseDevice_t *device, taliseTrackingCalBatchSize_t batchsize_us) +{ + talRecoveryActions_t retVal = TALACT_NO_ACTION; + talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + + uint8_t armFieldValue[16] = { 0 }; + uint32_t radioStatus = 0; + uint8_t byteOffset = 0x3C; + + static const uint32_t CODECHECK_PARAM_SETTCALBATCHSIZE_ERR1 = 2; + +#if TALISE_VERBOSE + adiHalErr_t halError = ADIHAL_OK; + + halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_setTrackingCalsBatchSize()\n"); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); +#endif + + retValWarn = retVal; + + /* check bactch size and set the address */ + switch (batchsize_us) + { + case TAL_TRACK_BATCH_SIZE_500_US: + armFieldValue[0] = (uint8_t)0xF4; + armFieldValue[4] = (uint8_t)0xF4; + armFieldValue[8] = (uint8_t)0xF4; + armFieldValue[12] = (uint8_t)0xF4; + armFieldValue[1] = (uint8_t)0x01; + armFieldValue[5] = (uint8_t)0x01; + armFieldValue[9] = (uint8_t)0x01; + armFieldValue[13] = (uint8_t)0x01; + break; + + case TAL_TRACK_BATCH_SIZE_200_US: + armFieldValue[0] = (uint8_t)0xC8; + armFieldValue[4] = (uint8_t)0xC8; + armFieldValue[8] = (uint8_t)0xC8; + armFieldValue[12] = (uint8_t)0xC8; + break; + + default: + return (uint32_t)talApiErrHandler(device, + TAL_ERRHDL_INVALID_PARAM, + TAL_ERR_SETTCAL_BATCH_SIZE_PARAM, + retVal, + TALACT_ERR_CHECK_PARAM); + } + + /* read radio state to make sure ARM is in radioOff/IDLE state or ready state */ + retVal = (talRecoveryActions_t)TALISE_getRadioState(device, &radioStatus); + IF_ERR_RETURN_U32(retVal); + + /* SW Test */ + if (device->devStateInfo.swTest == CODECHECK_PARAM_SETTCALBATCHSIZE_ERR1) + { + radioStatus = 0; + } + + /* throw error if not in radioOff/IDLE state or ready state */ + if (((radioStatus & 0x07) != TALISE_ARM_RADIO_STATUS_IDLE) && + ((radioStatus & 0x07) != TALISE_ARM_RADIO_STATUS_READY)) + { + return (uint32_t)talApiErrHandler(device, + TAL_ERRHDL_API_FAIL, + TAL_ERR_SETTCAL_BATCH_SIZE_ARMSTATE_ERROR, + retVal, + TALACT_ERR_RESET_ARM); + } + + /* other armFieldValues remain zero */ + + retVal = (talRecoveryActions_t)TALISE_writeArmConfig(device, + TALISE_ARM_OBJECTID_CAL_SCHEDULER, + byteOffset, + &armFieldValue[0], + 16); + IF_ERR_RETURN_U32(retVal); + + /* If no other higher priority errors, return possible log warning */ + if (retVal == TALACT_NO_ACTION) + { + retVal = retValWarn; + } + + return (uint32_t)retVal; +} + const char* talGetCalErrorMessage(uint32_t errSrc, uint32_t errCode) { #ifndef TALISE_VERBOSE @@ -1953,4 +2100,3 @@ const char* talGetCalErrorMessage(uint32_t errSrc, uint32_t errCode) #endif } - diff --git a/drivers/iio/adc/talise/talise_cals.h b/drivers/iio/adc/talise/talise_cals.h index 47bf5bc2da7351..502fbd2c19e505 100644 --- a/drivers/iio/adc/talise/talise_cals.h +++ b/drivers/iio/adc/talise/talise_cals.h @@ -4,7 +4,7 @@ * \brief Contains Talise calibration related function prototypes for * talise_cals.c * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -804,6 +804,49 @@ uint32_t TALISE_setDigDcOffsetEn(taliseDevice_t *device, uint8_t enableMask); * \retval TALISE_ERR_OK Function completed successfully */ uint32_t TALISE_getDigDcOffsetEn(taliseDevice_t *device, uint8_t *enableMask); + + /** + * \brief Allows reading Talise tracking calibration batch size configuration option + * from Talise ARM memory + * + * Config value is read from the Talise ARM memory and returned at the address of + * the batchsize_us enum function parameter. + * + * \pre This function can only be called when the Talise ARM is in the RadioOff/IDLE state or ready state. + * + * \dep_begin + * \dep{device->devHalInfo} + * \dep_end + * + * \param device Pointer to the Talise device data structure containing settings + * \param batchsize_us Pointer to Tracking calibration batch size enum to return read settings + * + * \retval TALACT_WARN_RESET_LOG Recovery action for log reset + * \retval TALACT_ERR_RESET_ARM Recovery action if ARM is detected to be in wrong state + * \retval TALACT_ERR_CHECK_PARAM Recovery action for bad parameter check + * \retval TALACT_NO_ACTION Function completed successfully, no action required + */ +uint32_t TALISE_getTrackingCalsBatchSize(taliseDevice_t *device, taliseTrackingCalBatchSize_t* batchsize_us); + +/** + * \brief Modifies the tracking calibrations batch capture size from 500us to 200us and vice versa. + * Defualt value for batch size(Minimum internal Calibration, Rx Caibration, Tx Calibration and + * Orx Calibration period) is 500us. + * + * \pre This function can only be called when the Talise ARM is in the RadioOff/IDLE state or ready state. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Talise device data structure containing settings + * \param batchsize_us variable to store Tracking Cal batch size. + * + * \retval TALACT_WARN_RESET_LOG Recovery action for log reset + * \retval TALACT_ERR_CHECK_PARAM Recovery action for bad parameter check + * \retval TALACT_ERR_RESET_ARM Recovery action for user ARM reset required + * \retval TALACT_NO_ACTION Function completed successfully, no action required + */ +uint32_t TALISE_setTrackingCalsBatchSize(taliseDevice_t *device, taliseTrackingCalBatchSize_t batchsize_us); /**************************************************************************** * Debug functions **************************************************************************** diff --git a/drivers/iio/adc/talise/talise_cals_types.h b/drivers/iio/adc/talise/talise_cals_types.h index 444971fed7e164..a2859c5a7299a8 100644 --- a/drivers/iio/adc/talise/talise_cals_types.h +++ b/drivers/iio/adc/talise/talise_cals_types.h @@ -3,7 +3,7 @@ * \file talise_cals_types.h * \brief Contains Talise API Calibration data types * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -93,6 +93,15 @@ typedef enum TAL_DC_OFFSET_ALL_ON = 0x0F /*!< Enables all the channels */ }taliseRxDcOffsettEn_t; + /** + * \brief Enum of Tracking Calibration Batch Size in Micro Seconds + */ + typedef enum + { + TAL_TRACK_BATCH_SIZE_500_US = 0, + TAL_TRACK_BATCH_SIZE_200_US = 1 + } taliseTrackingCalBatchSize_t; + /** * \brief Data structure to hold Tx LOL Status */ diff --git a/drivers/iio/adc/talise/talise_error.c b/drivers/iio/adc/talise/talise_error.c index ca612c3a675d55..23866e346858bb 100644 --- a/drivers/iio/adc/talise/talise_error.c +++ b/drivers/iio/adc/talise/talise_error.c @@ -5,7 +5,7 @@ * These functions are public to the customer for getting more details on * errors and debugging. * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -611,7 +611,17 @@ const char* TALISE_getErrorMessage(uint32_t errSrc, uint32_t errCode) case TAL_ERR_GETEXTLOOUT_NULL_PARAM: return "TALISE_getExtLoOutCfg(): Null function parameter\n"; case TAL_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK: return "TALISE_setDigDcOffsetEn(): Invalid enable mask parameter\n"; case TAL_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK: return "TALISE_getDigDcOffsetEn(): NULL enable mask parameter\n"; + case TAL_ERR_SETTCAL_BATCH_SIZE_PARAM: return "TALISE_setTrackingCalsBatchSize(): Invalid batch size parameter\n"; + case TAL_ERR_SETTCAL_BATCH_SIZE_ARMSTATE_ERROR: return "TALISE_setTrackingCalsBatchSize: Talise ARM can not be in radioOn state when the function is called.\n"; + case TAL_ERR_GETTCAL_BATCH_SIZE_ARMSTATE_ERROR: return "TALISE_getTrackingCalsBatchSize: Talise ARM can not be in radioOn state when the function is called.\n"; + case TAL_ERR_GETTCAL_BATCHSIZE_NULL_PARAM: return "TALISE_getTrackingCalsBatchSize(): NULL pointer passed to function\n"; + case TAL_ERR_GETTCAL_BATCHSIZE_INV_VALUE: return "TALISE_getTrackingCalsBatchSize(): Invalid batch size stored in ARM \n"; + case TAL_ERR_TXNCOSHIFTER_INV_PROFILE: return "TALISE_txNcoShifterSet(): Invalid Tx profile"; + case TAL_ERR_TXNCOSHIFTER_NULL_PARM: return "TALISE_txNcoShifterSet(): Error txNcoShiftCfg is NULL"; + case TAL_ERR_TXNCOSHIFTER_INV_TX1_FREQ: return "TALISE_txNcoShifterSet(): tx1 tone frequency > divider rate KHZ or < negative divider rate KHZ"; + case TAL_ERR_TXNCOSHIFTER_INV_TX2_FREQ: return "TALISE_txNcoShifterSet(): tx2 tone frequency > divider rate KHZ or < negative divider rate KHZ"; case TAL_ERR_NUMBER_OF_ERRORS: return "Invalid API error passed, last in error list\n"; /*Use for TestApiErrorStrings */ + default: return "Invalid API error passed, not in error list\n"; } } @@ -744,4 +754,3 @@ talRecoveryActions_t talApiErrHandler(taliseDevice_t *device, taliseErrHdls_t er return retVal; } } - diff --git a/drivers/iio/adc/talise/talise_error.h b/drivers/iio/adc/talise/talise_error.h index 418124ab2a2d1d..9677e352b15548 100644 --- a/drivers/iio/adc/talise/talise_error.h +++ b/drivers/iio/adc/talise/talise_error.h @@ -5,7 +5,7 @@ * These functions are public to the customer for getting more details on * errors and debugging. * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_error_types.h b/drivers/iio/adc/talise/talise_error_types.h index 4f86e0c06b6d57..9cfc435ee45aac 100644 --- a/drivers/iio/adc/talise/talise_error_types.h +++ b/drivers/iio/adc/talise/talise_error_types.h @@ -3,7 +3,7 @@ * \file talise_error_types.h * \brief Contains Talise data types for API Error messaging * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -522,6 +522,15 @@ typedef enum TAL_ERR_GETEXTLOOUT_NULL_PARAM, TAL_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK, TAL_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK, + TAL_ERR_SETTCAL_BATCH_SIZE_PARAM, + TAL_ERR_SETTCAL_BATCH_SIZE_ARMSTATE_ERROR, + TAL_ERR_GETTCAL_BATCH_SIZE_ARMSTATE_ERROR, + TAL_ERR_GETTCAL_BATCHSIZE_NULL_PARAM, + TAL_ERR_GETTCAL_BATCHSIZE_INV_VALUE, + TAL_ERR_TXNCOSHIFTER_INV_PROFILE, + TAL_ERR_TXNCOSHIFTER_NULL_PARM, + TAL_ERR_TXNCOSHIFTER_INV_TX1_FREQ, + TAL_ERR_TXNCOSHIFTER_INV_TX2_FREQ, TAL_ERR_NUMBER_OF_ERRORS /* Keep this ENUM last as a reference to the total number of error enum values */ } taliseErr_t; diff --git a/drivers/iio/adc/talise/talise_gpio.c b/drivers/iio/adc/talise/talise_gpio.c index 10c325f49ee117..470fbdb3c1cf9f 100644 --- a/drivers/iio/adc/talise/talise_gpio.c +++ b/drivers/iio/adc/talise/talise_gpio.c @@ -3,7 +3,7 @@ * \file talise_gpio.c * \brief Talise GPIO functions * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -378,7 +378,7 @@ uint32_t TALISE_getGpIntMask(taliseDevice_t *device, uint16_t *gpIntMask) halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getGpIntMask()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif - + /* checking for null pointer */ if (gpIntMask == NULL) { @@ -390,11 +390,11 @@ uint32_t TALISE_getGpIntMask(taliseDevice_t *device, uint16_t *gpIntMask) halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_GP_INTERRUPT_MASK_1, &gpIntLsb); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); - + halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_GP_INTERRUPT_MASK_0, &gpIntMsb); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); - + *gpIntMask = ((((uint16_t)gpIntMsb) << 8) & TAL_GPMASK_MSB) | ((uint16_t)gpIntLsb & TAL_GPMASK_LSB); } @@ -437,6 +437,7 @@ uint32_t TALISE_getGpIntStatus(taliseDevice_t *device, uint16_t *gpIntStatus) uint32_t TALISE_getTemperature(taliseDevice_t *device, int16_t *temperatureDegC) { talRecoveryActions_t retVal = TALACT_NO_ACTION; + uint8_t armExtData[1] = {TALISE_ARM_OBJECTID_TEMP_SENSOR}; uint8_t cmdStatusByte = 0; uint8_t armReadBack[2] = {0}; @@ -446,7 +447,6 @@ uint32_t TALISE_getTemperature(taliseDevice_t *device, int16_t *temperatureDegC) #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getTemperature()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1639,7 +1639,7 @@ uint32_t TALISE_gpIntHandler(taliseDevice_t *device, uint32_t *gpIntStatus, tali { /* Deframer A */ if (((gpIntDeframerSources & DEFRAMER_A_BD_ERROR) > 0) || - ((gpIntDeframerSources & DEFRAMER_A_NIT_ERROR) > 0) || + ((gpIntDeframerSources & DEFRAMER_A_NIT_ERROR) > 0) || ((gpIntDeframerSources & DEFRAMER_A_UEK_ERROR) > 0)) { if (gpIntDiag != NULL) @@ -2402,5 +2402,3 @@ const char* talGetGpioErrorMessage(uint32_t errSrc, uint32_t errCode) #endif } - - diff --git a/drivers/iio/adc/talise/talise_gpio.h b/drivers/iio/adc/talise/talise_gpio.h index 4d8599cb29b1a2..20e6a592203fda 100644 --- a/drivers/iio/adc/talise/talise_gpio.h +++ b/drivers/iio/adc/talise/talise_gpio.h @@ -3,7 +3,7 @@ * \file talise_gpio.h * \brief Talise GPIO header file * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -254,7 +254,7 @@ uint32_t TALISE_getGpioMonitorOut(taliseDevice_t *device, uint8_t *monitorIndex, /** * \brief Sets the General Purpose (GP) interrupt register bit mask (1 = disable IRQ from asserting GP interrupt pin) - * + * * To enable just the JESD deframer IRQ signal: * TALISE_setGpIntMask(device, ~TAL_GP_MASK_JESD_DEFRMER_IRQ); * @@ -265,10 +265,10 @@ uint32_t TALISE_getGpioMonitorOut(taliseDevice_t *device, uint8_t *monitorIndex, * \dep_end * * \param device Pointer to the Talise data structure - * \param gpIntMask The bit-mask which masks (1=disable) the signals that may assert the GP interrupt pin. + * \param gpIntMask The bit-mask which masks (1=disable) the signals that may assert the GP interrupt pin. * taliseGpIntMask_t enumerated types are or'd together to form the GP interrupt mask word. * A bit value of 1 prevents the corresponding signal from asserting the GP interrupt - * + * * gpIntMask[bit] | Bit description * -----------------|----------------------- * [15] | Reserved @@ -287,12 +287,12 @@ uint32_t TALISE_getGpioMonitorOut(taliseDevice_t *device, uint8_t *monitorIndex, * [2] | TAL_GP_MASK_AUX_SYNTH_NONLOCK_ERROR * [1] | TAL_GP_MASK_RF_SYNTH_NONLOCK_ERROR * [0] | Reserved - * + * * \note The AUXPLL Interrupt is masked in TALISE_Initialize() since the ARM routinely * re-locks the AUXPLL. If this interrupt is enabled, the user will observe spurious * GP_INT signal assertions approximately every 2 seconds. It is recommended for the user * to NOT enable the AUXPLL interrupt. - * + * * \retval TALACT_WARN_RESET_LOG Recovery action for log reset * \retval TALACT_ERR_CHECK_PARAM Recovery action for bad parameter check * \retval TALACT_ERR_RESET_SPI Recovery action for SPI reset required @@ -311,7 +311,7 @@ uint32_t TALISE_setGpIntMask(taliseDevice_t *device, uint16_t gpIntMask); * * \param device Pointer to the Talise data structure * \param gpIntMask Bit-mask specifying which IRQ sources are masked from asserting the GP interrupt (1=disable IRQ). - * + * * enableMask[bit] | Bit description * -----------------|----------------------- * [15] | Reserved @@ -330,7 +330,7 @@ uint32_t TALISE_setGpIntMask(taliseDevice_t *device, uint16_t gpIntMask); * [2] | TAL_GP_MASK_AUX_SYNTH_NONLOCK_ERROR (1 = IRQ output masked (disabled); 0 = IRQ output unmasked (enabled)) * [1] | TAL_GP_MASK_RF_SYNTH_NONLOCK_ERROR (1 = IRQ output masked (disabled); 0 = IRQ output unmasked (enabled)) * [0] | Reserved - * + * * \retval TALACT_WARN_RESET_LOG Recovery action for log reset * \retval TALACT_ERR_CHECK_PARAM Recovery action for bad parameter check * \retval TALACT_ERR_RESET_SPI Recovery action for SPI reset required @@ -664,7 +664,7 @@ uint32_t TALISE_getGpio3v3SourceCtrl(taliseDevice_t *device, uint16_t *gpio3v3Sr * \retval TALACT_NO_ACTION Function completed successfully, no action required */ uint32_t TALISE_setGpio3v3PinLevel(taliseDevice_t *device, uint16_t gpio3v3PinLevel); - + /** * \brief Reads the Talise 3.3V GPIO pin levels * @@ -688,7 +688,7 @@ uint32_t TALISE_setGpio3v3PinLevel(taliseDevice_t *device, uint16_t gpio3v3PinLe * \retval TALACT_NO_ACTION Function completed successfully, no action required */ uint32_t TALISE_getGpio3v3PinLevel(taliseDevice_t *device, uint16_t *gpio3v3PinLevel); - + /** * \brief Reads the Talise GPIO pin output levels for BITBANG mode * diff --git a/drivers/iio/adc/talise/talise_gpio_types.h b/drivers/iio/adc/talise/talise_gpio_types.h index 640d7d529b0dc5..e8ed4215d54087 100644 --- a/drivers/iio/adc/talise/talise_gpio_types.h +++ b/drivers/iio/adc/talise/talise_gpio_types.h @@ -3,7 +3,7 @@ * \file talise_gpio_types.h * \brief Contains functions to allow control of the General Purpose IO functions on the Talise device * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -26,7 +26,7 @@ typedef enum TAL_GPIO_ARM_OUT_MODE = 9, /*!< Allows internal ARM processor to output on GPIO pins */ TAL_GPIO_SLICER_OUT_MODE = 10 /*!< Allows Slicer active configuration to the GPIO output pins */ } taliseGpioMode_t; - + /** * \brief Enum to set the GPIO3v3 mode */ diff --git a/drivers/iio/adc/talise/talise_hal.c b/drivers/iio/adc/talise/talise_hal.c index 61705245ac9fc4..127189e6decfd1 100644 --- a/drivers/iio/adc/talise/talise_hal.c +++ b/drivers/iio/adc/talise/talise_hal.c @@ -3,7 +3,7 @@ * \file talise_hal.c * \brief Contains TALISE API Hardware Abstraction Layer (HAL) functions * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_hal.h b/drivers/iio/adc/talise/talise_hal.h index 0e5b8a4be9593a..ada41f73f64f96 100644 --- a/drivers/iio/adc/talise/talise_hal.h +++ b/drivers/iio/adc/talise/talise_hal.h @@ -4,7 +4,7 @@ * \brief Contains prototypes and macro definitions for Private ADI HAL wrapper * functions implemented in talise_hal.c * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_jesd204.c b/drivers/iio/adc/talise/talise_jesd204.c index 461db0d72ad51e..910c2b6a7764bb 100644 --- a/drivers/iio/adc/talise/talise_jesd204.c +++ b/drivers/iio/adc/talise/talise_jesd204.c @@ -3,7 +3,7 @@ * \file talise_jesd204.c * \brief Contains functions to support Talise JESD204b data interface * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -1376,12 +1376,18 @@ uint32_t TALISE_enableDeframerLink(taliseDevice_t *device, taliseDeframerSel_t d talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; uint16_t deframerOffset = 0; + static const uint16_t CDR_RESET_ADDR = 0x187e; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_enableDeframerLink()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif + /* Add reset for CDR to prevent lockup issue */ + halError = talSpiWriteField(device->devHalInfo, CDR_RESET_ADDR, 1, 0x01, 7); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + if (deframerSel == TAL_DEFRAMER_A) { deframerOffset = 0; @@ -2019,8 +2025,8 @@ uint32_t TALISE_getDfrmIlasMismatch(taliseDevice_t *device, taliseDeframerSel_t uint8_t syncRegister = 0; /* Local holds contents of syncB register */ uint16_t cfgAddrArray[15] = {0}; /* Local holds cfg addresses for spiReadBytes to fetch Cfg values */ uint16_t ilasAddrArray[15] = {0}; /* Local holds ilas addresses for spiReadBytes to fetch ILAS values */ - taliseJesd204bLane0Config_t dfrmCfgLocal = {0}; /* Local deframer configuration settings */ - taliseJesd204bLane0Config_t dfrmIlasLocal = {0}; /* Local deframer Ilas settings */ + taliseJesd204bLane0Config_t dfrmCfgLocal = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* Local deframer configuration settings */ + taliseJesd204bLane0Config_t dfrmIlasLocal = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* Local deframer Ilas settings */ #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getDfrmIlasMismatch()\n"); @@ -2030,7 +2036,7 @@ uint32_t TALISE_getDfrmIlasMismatch(taliseDevice_t *device, taliseDeframerSel_t if (mismatch == NULL) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, - TAL_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM, retVal, TALACT_ERR_CHECK_PARAM); + TAL_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM, retVal, TALACT_ERR_CHECK_PARAM); } *mismatch = 0; @@ -2773,4 +2779,3 @@ uint32_t TALISE_framerSyncbToggle(taliseDevice_t *device, taliseFramerSel_t fram return (uint32_t)retVal; } - diff --git a/drivers/iio/adc/talise/talise_jesd204.h b/drivers/iio/adc/talise/talise_jesd204.h index 20aa68dc89d442..fa77de1fdb1643 100644 --- a/drivers/iio/adc/talise/talise_jesd204.h +++ b/drivers/iio/adc/talise/talise_jesd204.h @@ -4,7 +4,7 @@ * \brief Contains Talise JESD204b data path related function prototypes for * talise_jesd204.c * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_jesd204_types.h b/drivers/iio/adc/talise/talise_jesd204_types.h index 352437249f3d99..3267df4566a95c 100644 --- a/drivers/iio/adc/talise/talise_jesd204_types.h +++ b/drivers/iio/adc/talise/talise_jesd204_types.h @@ -3,7 +3,7 @@ * \file talise_jesd204_types.h * \brief Contains Talise API JESD data types * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_radioctrl.c b/drivers/iio/adc/talise/talise_radioctrl.c index c25b238f0a1056..be4538a6ad5860 100644 --- a/drivers/iio/adc/talise/talise_radioctrl.c +++ b/drivers/iio/adc/talise/talise_radioctrl.c @@ -4,7 +4,7 @@ * \brief Contains functions to support Talise radio control and pin control * functions * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -137,7 +137,6 @@ uint32_t TALISE_setArmGpioPins(taliseDevice_t *device, taliseArmGpioConfig_t *ar #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_setArmGpioPins()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -733,20 +732,20 @@ uint32_t TALISE_setTxToOrxMapping(taliseDevice_t *device, uint8_t txCalEnable, t { talRecoveryActions_t retVal = TALACT_NO_ACTION; talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + uint8_t extData[2] = {0}; uint8_t cmdStatusByte = 0x0; static const uint8_t ENABLE_TXCALS = 0x10; + extData[0] = TALISE_ARM_OBJECTID_ORX_TXCAL_CTRL; + #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_setTxToOrxMapping()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif - extData[0] = TALISE_ARM_OBJECTID_ORX_TXCAL_CTRL; - retValWarn = retVal; /* cmdByte assignment from oRx1Map */ @@ -1209,7 +1208,6 @@ uint32_t TALISE_setRfPllLoopFilter(taliseDevice_t *device, uint16_t loopBandwidt #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_setRfPllLoopFilter()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1233,9 +1231,9 @@ uint32_t TALISE_getRfPllLoopFilter(taliseDevice_t *device, uint16_t *loopBandwid talRecoveryActions_t retVal = TALACT_NO_ACTION; talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getRfPllLoopFilter()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1262,11 +1260,11 @@ uint32_t TALISE_setPllLoopFilter(taliseDevice_t *device, taliseRfPllName_t pllNa uint8_t cmdStatusByte = 0; talRecoveryActions_t retVal = TALACT_NO_ACTION; talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + uint8_t auxPllSel = 0; #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_setPllLoopFilter()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1340,11 +1338,11 @@ uint32_t TALISE_getPllLoopFilter(taliseDevice_t *device, taliseRfPllName_t pllNa uint8_t armData[3] = {0}; uint8_t cmdStatusByte = 0; talRecoveryActions_t retVal = TALACT_NO_ACTION; + uint8_t auxPllSel = 0; #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getPllLoopFilter()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1654,13 +1652,13 @@ uint32_t TALISE_setFhmConfig(taliseDevice_t *device, taliseFhmConfig_t *fhmConfi static const uint8_t ARM_CFG_BUF_SIZE = 8; talRecoveryActions_t retVal = TALACT_NO_ACTION; talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + int64_t freqValid = 0; uint8_t byteOffset = 0; uint8_t armConfigBuf[8] = {0}; #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_setFhmConfig()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1750,12 +1748,12 @@ uint32_t TALISE_getFhmConfig(taliseDevice_t *device, taliseFhmConfig_t *fhmConfi static const uint8_t ARM_CFG_BUF_SIZE = 8; talRecoveryActions_t retVal = TALACT_NO_ACTION; talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + uint8_t armCfgBuf[8] = {0}; uint8_t byteOffset = 0; #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getFhmConfig()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1845,12 +1843,12 @@ uint32_t TALISE_setFhmMode(taliseDevice_t *device, taliseFhmMode_t *fhmMode) talRecoveryActions_t retVal = TALACT_NO_ACTION; talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + uint8_t cmdStatusByte = 0; uint8_t armFhmModeCfgCmd[3] = { 0 }; #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_setFhmMode()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -1969,13 +1967,13 @@ uint32_t TALISE_getFhmMode(taliseDevice_t *device, taliseFhmMode_t *fhmMode) talRecoveryActions_t retVal = TALACT_NO_ACTION; talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + uint8_t cmdStatusByte = 0; uint8_t fhmExitMode = 0; uint8_t armGetFhmModeCmdArr[ARM_FHM_MODE_READ_CMD_NUM_BYTES]; #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getFhmMode()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -2035,12 +2033,12 @@ uint32_t TALISE_setFhmHop(taliseDevice_t *device, uint64_t nextRfPllFrequency_Hz talRecoveryActions_t retVal = TALACT_NO_ACTION; talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + uint8_t cmdStatusByte = 0; uint8_t armSetFhmHopCmdArr[ARM_FHM_HOP_SET_CMD_BYTES]; #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_setFhmHop()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -2104,13 +2102,13 @@ uint32_t TALISE_getFhmRfPllFrequency(taliseDevice_t *device, uint64_t *fhmRfPllF talRecoveryActions_t retVal = TALACT_NO_ACTION; talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + uint8_t cmdStatusByte = 0; uint8_t armGetFhmModeCmdArr[1] = { 0 }; uint8_t armGetFhmRfPllFreqArr[8] = { 0 }; #if TALISE_VERBOSE adiHalErr_t halError = ADIHAL_OK; - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getFhmRfPllFrequency()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif @@ -2187,17 +2185,11 @@ uint32_t TALISE_getFhmStatus(taliseDevice_t *device, taliseFhmStatus_t *fhmStatu talRecoveryActions_t retVal = TALACT_NO_ACTION; talRecoveryActions_t retValWarn = TALACT_NO_ACTION; + uint8_t cmdStatusByte = 0; uint8_t armGetFhmModeCmdArr[ARM_FHM_STS_READ_CMD_NUM_BYTES]; uint8_t armFhmStsData[8] = { 0 }; -#if TALISE_VERBOSE - adiHalErr_t halError = ADIHAL_OK; - - halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getFhmStatus()\n"); - retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); -#endif - /*Check for NULL*/ if(fhmStatus == NULL) { @@ -2205,6 +2197,12 @@ uint32_t TALISE_getFhmStatus(taliseDevice_t *device, taliseFhmStatus_t *fhmStatu TAL_ERR_GETFHMSTS_NULL_PARAM, retVal, TALACT_ERR_CHECK_PARAM); } +#if TALISE_VERBOSE + adiHalErr_t halError = ADIHAL_OK; + halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getFhmStatus()\n"); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); +#endif + retValWarn = retVal; /*Send ARM command to read FHM mode*/ diff --git a/drivers/iio/adc/talise/talise_radioctrl.h b/drivers/iio/adc/talise/talise_radioctrl.h index 4113abc867eb5b..149dca08fff49c 100644 --- a/drivers/iio/adc/talise/talise_radioctrl.h +++ b/drivers/iio/adc/talise/talise_radioctrl.h @@ -3,7 +3,7 @@ * \file talise_radioctrl.h * \brief Contains Talise related function prototypes for talise_radioctrl.c * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -649,7 +649,7 @@ uint32_t TALISE_setOrxLoSource(taliseDevice_t *device, taliseObsRxLoSource_t orx * \pre This function can be used after the device has been fully initialized * and the init cals have already run. This can be called in the * radio On or Off state. - * + * * \note In radio Off, this function will read back RF PLL * * \dep_begin diff --git a/drivers/iio/adc/talise/talise_radioctrl_types.h b/drivers/iio/adc/talise/talise_radioctrl_types.h index e77112fd23f083..5691aaeff0a90e 100644 --- a/drivers/iio/adc/talise/talise_radioctrl_types.h +++ b/drivers/iio/adc/talise/talise_radioctrl_types.h @@ -3,7 +3,7 @@ * \file talise_radioctrl_types.h * \brief Contains Talise API Radio Control data types * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -120,7 +120,7 @@ typedef enum TAL_RX1RX2_EN = 0x03, /*!< Rx1 + Rx2 channels enabled */ TAL_ORX1_EN = 0x04, /*!< ORx1 channel enabled */ TAL_ORX2_EN = 0x08, /*!< ORx2 channel enabled */ - TAL_ORX1ORX2_EN = 0x0C /*!< ORx1 and ORx2 channels enabled - only allowed if ADC stitching is not enabled */ + TAL_ORX1ORX2_EN = 0x0C /*!< ORx1 and ORx2 channels enabled - only allowed if ADC stitching is not enabled */ } taliseRxORxChannels_t; diff --git a/drivers/iio/adc/talise/talise_reg_addr_macros.h b/drivers/iio/adc/talise/talise_reg_addr_macros.h index b5b6c0a9a20e97..ed12bd5620ac77 100644 --- a/drivers/iio/adc/talise/talise_reg_addr_macros.h +++ b/drivers/iio/adc/talise/talise_reg_addr_macros.h @@ -3,7 +3,7 @@ * \file talise_reg_addr_macros.h * \brief Contains Talise API address macro definitions * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -277,6 +277,21 @@ extern "C" { #define TALISE_ADDR_TX_ABBF_FREQCAL_NCO_Q_UPPER_NIBBLE 0x0F1E #define TALISE_ADDR_TX_ABBF_FREQCAL_NCO_Q_MSBS 0x0F1F #define TALISE_ADDR_TX_ABBF_FREQCAL_NCO_Q_LSBS 0x0F20 +#define TALISE_ADDR_TX_NCO_CH1_CTRL 0x1020 +#define TALISE_ADDR_TX_NCO_CH1_FREQ_TUNE_BYTE_4 0x1021 +#define TALISE_ADDR_TX_NCO_CH1_FREQ_TUNE_BYTE_3 0x1022 +#define TALISE_ADDR_TX_NCO_CH1_FREQ_TUNE_BYTE_2 0x1023 +#define TALISE_ADDR_TX_NCO_CH1_FREQ_TUNE_BYTE_1 0x1024 +#define TALISE_ADDR_TX_NCO_CH1_PHASE_OFFSET_BYTE_2 0x1025 +#define TALISE_ADDR_TX_NCO_CH1_PHASE_OFFSET_BYTE_1 0x1026 +#define TALISE_ADDR_TX_NCO_CH2_CTRL 0x1027 +#define TALISE_ADDR_TX_NCO_CH2_FREQ_TUNE_BYTE_4 0x1028 +#define TALISE_ADDR_TX_NCO_CH2_FREQ_TUNE_BYTE_3 0x1029 +#define TALISE_ADDR_TX_NCO_CH2_FREQ_TUNE_BYTE_2 0x102A +#define TALISE_ADDR_TX_NCO_CH2_FREQ_TUNE_BYTE_1 0x102B +#define TALISE_ADDR_TX_NCO_CH2_PHASE_OFFSET_BYTE_2 0x102C +#define TALISE_ADDR_TX_NCO_CH2_PHASE_OFFSET_BYTE_1 0x102D +#define TALISE_ADDR_TX_NCO_FREQ_UPDATE 0x102E #define TALISE_ADDR_GPIO_3P3V_DIRECTION_CONTROL_0 0x1080 #define TALISE_ADDR_GPIO_3P3V_DIRECTION_CONTROL_1 0x1081 #define TALISE_ADDR_GPIO_3P3V_SPI_SOURCE_0 0x1082 diff --git a/drivers/iio/adc/talise/talise_rx.c b/drivers/iio/adc/talise/talise_rx.c index 96edf338c2d9c7..119c6757d218ff 100644 --- a/drivers/iio/adc/talise/talise_rx.c +++ b/drivers/iio/adc/talise/talise_rx.c @@ -4,7 +4,7 @@ * \brief Contains functions to support Talise Rx and Observation Rx data path * control * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -1003,7 +1003,7 @@ uint32_t TALISE_setRxDataFormat (taliseDevice_t *device, taliseRxDataFormat_t *r intConfig |= SIGNED_MAGNITUDE_BITM; /* signed */ npCheck = 24; } - + if (rxDataFormat->formatSelect == TAL_GAIN_COMPENSATION_DISABLED) { intConfig &= ~SLICER_NUMBERBITS_BITM; /* 2 bit on I, 2 bit on Q */ @@ -2519,7 +2519,7 @@ uint32_t TALISE_getRxDecPower(taliseDevice_t *device, taliseRxChannels_t rxChann return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INV_RX_DEC_POWER_PARAM, retVal, TALACT_ERR_CHECK_PARAM); } - + if (rxChannel == TAL_RX1) { decPowerAddr = TALISE_ADDR_DEC_POWER_CH1; @@ -2533,7 +2533,7 @@ uint32_t TALISE_getRxDecPower(taliseDevice_t *device, taliseRxChannels_t rxChann return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_GETRXDECPOWER_INV_CHANNEL, retVal, TALACT_ERR_CHECK_PARAM); } - + /* Check that rx profile is valid in current config */ if (((device->devStateInfo.profilesValid & RX_PROFILE_VALID) == 0) || (device->devStateInfo.initializedChannels & (uint32_t)rxChannel) == 0) @@ -2541,18 +2541,18 @@ uint32_t TALISE_getRxDecPower(taliseDevice_t *device, taliseRxChannels_t rxChann return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_GETRXDECPOWER_INV_PROFILE, retVal, TALACT_ERR_CHECK_PARAM); } - + /* Write some value to generate a strobe to latch the value */ halError = talSpiWriteByte(device->devHalInfo, decPowerAddr, 0x01); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); - + /* Read Rx1 Dec Power register */ halError = talSpiReadByte(device->devHalInfo, decPowerAddr, &rxDecPower_dBFS); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); - + *rxDecPower_mdBFS = ((uint16_t)rxDecPower_dBFS) * 250; /* 250 = 1000 * 0.25dB */ - + return (uint32_t)retVal; } \ No newline at end of file diff --git a/drivers/iio/adc/talise/talise_rx.h b/drivers/iio/adc/talise/talise_rx.h index 2aef05791c7e6f..05f6c2eae7fdde 100644 --- a/drivers/iio/adc/talise/talise_rx.h +++ b/drivers/iio/adc/talise/talise_rx.h @@ -4,7 +4,7 @@ * \brief Contains Talise receive related function prototypes for * talise_rx.c * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -514,7 +514,7 @@ uint32_t TALISE_setGainTableExtCtrlPins(taliseDevice_t *device, taliseRxChannels * If the receiver is disabled during the power measurement, this function returns a 0 value for rx1DecPower_mdBFS * * The resolution of this function is 0.25dB. - * When the measurement location is HB2 (i.e., powerUseRfirOut == powerUseBBDC2 == 0) the dynamic range of this function is 40dB. + * When the measurement location is HB2 (i.e., powerUseRfirOut == powerUseBBDC2 == 0) the dynamic range of this function is 40dB. * Signals lower than -40dBFS may not be measured accurately. When measuring from RfirOut or BBDC2, the dynamic range of this * function is 60dB. Signals lower than -60 dBFS may not be measured accurately. * diff --git a/drivers/iio/adc/talise/talise_rx_types.h b/drivers/iio/adc/talise/talise_rx_types.h index ac3c987426e416..6a8633c882d35c 100644 --- a/drivers/iio/adc/talise/talise_rx_types.h +++ b/drivers/iio/adc/talise/talise_rx_types.h @@ -3,7 +3,7 @@ * \file talise_rx_types.h * \brief Contains Talise API Rx datapath data types * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_tx.c b/drivers/iio/adc/talise/talise_tx.c index 9dd06f8dd23118..c9a05a75d48733 100644 --- a/drivers/iio/adc/talise/talise_tx.c +++ b/drivers/iio/adc/talise/talise_tx.c @@ -3,7 +3,7 @@ * \file talise_tx.c * \brief Contains functions to support Talise Tx data path control * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -211,6 +211,219 @@ uint32_t TALISE_setDacFullScale(taliseDevice_t *device, taliseDacFullScale_t dac return (uint32_t)retVal; } +uint32_t TALISE_txNcoShifterSet(taliseDevice_t *device, taliseTxNcoShifterCfg_t *txNcoShiftCfg) +{ + long long exponent32bit = 2147483648UL; + int32_t exponent16bit = 65535; + + talRecoveryActions_t retVal = TALACT_NO_ACTION; + adiHalErr_t halError = ADIHAL_OK; + uint32_t txInputRateDiv2_kHz = 0; + uint16_t tx1PhaseWord = 0; + uint16_t tx2PhaseWord = 0; + uint16_t tx1NcoTuneWord = 0; + uint16_t tx2NcoTuneWord = 0; + int32_t ch1TuneFrequency = 0; + int32_t ch2TuneFrequency = 0; + int32_t absValTx1Freq = 0; + int32_t absValTx2Freq = 0; + uint8_t ncoEnableMask = (uint8_t )txNcoShiftCfg->enableNCO; + + +#if TALISE_VERBOSE + halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_txNcoShifterSet()\n"); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); +#endif + + /* Check valid Tx profile */ + if ((device->devStateInfo.profilesValid & TX_PROFILE_VALID) == 0) + { + return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_ENABLETXNCO_INV_PROFILE, retVal, TALACT_ERR_CHECK_PARAM); + } + + /* Check for NULL pointer */ + if (txNcoShiftCfg == NULL) + { + return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_TXNCOSHIFTER_NULL_PARM, retVal, TALACT_ERR_CHECK_PARAM); + } + + txInputRateDiv2_kHz = device->devStateInfo.txInputRate_kHz >> 1; + if ((txNcoShiftCfg->tx1ToneFreq_kHz > (int32_t)txInputRateDiv2_kHz) || + (txNcoShiftCfg->tx1ToneFreq_kHz < -((int32_t)txInputRateDiv2_kHz))) + { + return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_TXNCOSHIFTER_INV_TX1_FREQ, retVal, TALACT_ERR_CHECK_PARAM); + } + + /* Check Tx2 NCO freq range between Fs/2 and -Fs/2 */ + if ((txNcoShiftCfg->tx2ToneFreq_kHz > (int32_t)txInputRateDiv2_kHz) || + (txNcoShiftCfg->tx2ToneFreq_kHz < -((int32_t)txInputRateDiv2_kHz))) + { + return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_TXNCOSHIFTER_INV_TX2_FREQ, retVal, TALACT_ERR_CHECK_PARAM); + } + + /* Force Tx output power to max analog output power, but 6dB digital + * back off to prevent the NCO from clipping the Tx PFIR filter */ + /* Tx1 */ + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX1_GAIN_0, 0x78 ); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX1_GAIN_1, 0x00 ); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX1_GAIN_2, 0x00 ); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + /* Tx2 */ + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX2_GAIN_0, 0x78 ); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX2_GAIN_1, 0x00 ); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX2_GAIN_2, 0x00 ); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + /* Enable TPC for Tx1 and Tx2 to Direct mode */ + halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_TX_TPC_CONFIG, 0x0A, 0x0F, 0); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + /* Calculate Tx NCO tuning words. Round the result */ + tx1NcoTuneWord = (int32_t)((DIV_S64(((int64_t)txNcoShiftCfg->tx1ToneFreq_kHz << 20), txInputRateDiv2_kHz) + 1) >> 1); + tx2NcoTuneWord = (int32_t)((DIV_S64(((int64_t)txNcoShiftCfg->tx2ToneFreq_kHz << 20), txInputRateDiv2_kHz) + 1) >> 1); + + /* Write NCO tuning words - Tx1 */ + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_ABBF_FREQCAL_NCO_I_UPPER_NIBBLE, (uint8_t)((tx1NcoTuneWord >> 16) & 0x0F)); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_ABBF_FREQCAL_NCO_I_MSBS, (uint8_t)((tx1NcoTuneWord >> 8) & 0xFF)); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_ABBF_FREQCAL_NCO_I_LSBS, (uint8_t)(tx1NcoTuneWord & 0xFF)); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + /* Write NCO tuning words - Tx2 */ + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_ABBF_FREQCAL_NCO_Q_UPPER_NIBBLE, (uint8_t)((tx2NcoTuneWord >> 16) & 0x0F)); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_ABBF_FREQCAL_NCO_Q_MSBS, (uint8_t)((tx2NcoTuneWord >> 8) & 0xFF)); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_ABBF_FREQCAL_NCO_Q_LSBS, (uint8_t)(tx2NcoTuneWord & 0xFF)); + retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + /* Calculate the phase values to be wrote to registers based on formula */ + /* value = round(desiredPhaseShift*(2^16-1)/360) */ + tx1PhaseWord = (u16) DIV_ROUND_CLOSEST(txNcoShiftCfg->tx1TonePhaseDeg * ((exponent16bit) - 1), 360); + tx2PhaseWord = (u16) DIV_ROUND_CLOSEST(txNcoShiftCfg->tx2TonePhaseDeg * ((exponent16bit) - 1), 360); + + /* write nco phase words */ + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH1_PHASE_OFFSET_BYTE_1, ((uint8_t)((tx1PhaseWord) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH1_PHASE_OFFSET_BYTE_2, ((uint8_t)((tx1PhaseWord >> 8) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH2_PHASE_OFFSET_BYTE_1, ((uint8_t)((tx2PhaseWord) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH2_PHASE_OFFSET_BYTE_2, ((uint8_t)((tx2PhaseWord >> 8) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + /* Calculate absolute value of frequencies manually */ + absValTx1Freq = txNcoShiftCfg->tx1ToneFreq_kHz * ((txNcoShiftCfg->tx1ToneFreq_kHz > 0) - (txNcoShiftCfg->tx1ToneFreq_kHz < 0)); + absValTx2Freq = txNcoShiftCfg->tx2ToneFreq_kHz * ((txNcoShiftCfg->tx2ToneFreq_kHz > 0) - (txNcoShiftCfg->tx2ToneFreq_kHz < 0)); + + /* Calculate the frequency tuning values to be wrote to registers based on formula */ + /* value = round(2^31*(abs(desiredNCOFreq / 2)/(TxSampleRate/2))); if (desiredNCOFreq<0) then add 2^31 */ + ch1TuneFrequency = (uint32_t)DIV_ROUND_CLOSEST_ULL(exponent32bit * absValTx1Freq, txInputRateDiv2_kHz / 2); + ch2TuneFrequency = (uint32_t)DIV_ROUND_CLOSEST_ULL(exponent32bit * absValTx2Freq, txInputRateDiv2_kHz / 2); + + /* 2's complement to handle negative frequencies */ + if (txNcoShiftCfg->tx1ToneFreq_kHz > 0) + { + ch1TuneFrequency = ~ch1TuneFrequency + 1; + } + + if (txNcoShiftCfg->tx2ToneFreq_kHz > 0) + { + ch2TuneFrequency = ~ch2TuneFrequency + 1; + } + + /* check for enabled/disabled and if so zero'ing out data so it resets to default signal */ + if (txNcoShiftCfg->enableNCO == TAL_TXNCO_DISABLE) + { + ch1TuneFrequency = 0x0; + ch2TuneFrequency = 0x0; + /* set the mask to update all channels back to 0 value */ + ncoEnableMask = (uint8_t)TAL_TXNCO_ENABLE_ALL; + } + + /* write nco frequency tuning values */ + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH1_FREQ_TUNE_BYTE_1, ((uint8_t)((ch1TuneFrequency) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH1_FREQ_TUNE_BYTE_2, ((uint8_t)((ch1TuneFrequency >> 8) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH1_FREQ_TUNE_BYTE_3, ((uint8_t)((ch1TuneFrequency >> 16) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH1_FREQ_TUNE_BYTE_4, ((uint8_t)((ch1TuneFrequency >> 24) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH2_FREQ_TUNE_BYTE_1, ((uint8_t)((ch2TuneFrequency) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH2_FREQ_TUNE_BYTE_2, ((uint8_t)((ch2TuneFrequency >> 8) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH2_FREQ_TUNE_BYTE_3, ((uint8_t)((ch2TuneFrequency >> 16) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_CH2_FREQ_TUNE_BYTE_4, ((uint8_t)((ch2TuneFrequency >> 24) & 0xFF))); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + /* Set nco frequency update ch2 */ + halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_NCO_FREQ_UPDATE, ncoEnableMask); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_TX_NCO_CH1_CTRL, 0x1, 0x01, 0); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_TX_NCO_CH2_CTRL, 0x1, 0x01, 0); + retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); + IF_ERR_RETURN_U32(retVal); + + return (uint32_t)retVal; +} + uint32_t TALISE_enableTxNco(taliseDevice_t *device, taliseTxNcoTestToneCfg_t *txNcoTestToneCfg) { talRecoveryActions_t retVal = TALACT_NO_ACTION; diff --git a/drivers/iio/adc/talise/talise_tx.h b/drivers/iio/adc/talise/talise_tx.h index 7f9ecf45871b14..8797573f1af86b 100644 --- a/drivers/iio/adc/talise/talise_tx.h +++ b/drivers/iio/adc/talise/talise_tx.h @@ -4,7 +4,7 @@ * \brief Contains Talise transmit related function prototypes for * talise_tx.c * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -130,6 +130,35 @@ uint32_t TALISE_setDacFullScale(taliseDevice_t *device, taliseDacFullScale_t dac */ uint32_t TALISE_enableTxNco(taliseDevice_t *device, taliseTxNcoTestToneCfg_t *txNcoTestToneCfg); +/** + * \brief Enables/Disables the Tx NCO + * + * This function enables/disables a digital numerically controlled oscillator + * in the Talise Digital to create a test CW tone on Tx1 and Tx2 RF outputs. + * + * The TxAttenuation is forced in this function to max analog output power, + * but the digital attenuation is backed off 6dB to make sure the digital + * filter does not clip and cause spurs in the tx spectrum. Ensure no other + * API's are called that change the Tx attenuation mode when using this + * function + * + * This api is similar in functionality to TALISE_enableTxNco but it has a few + * additional uses, in addition to configuring the NCO it can also configure + * Each nco independantly and it can also modify the signal of each by altering + * the phase of each. + * + * \param device Pointer to the Talise device's data structure + * \param txNcoTestToneCfg Pointer to taliseTxNcoShifterCfg_t structure that + * contains the configuration for the Tx NCO test tone and additional parameters + * related to phase of the signals for each tx. + * + * \retval TALACT_WARN_RESET_LOG Recovery action for log reset + * \retval TALACT_ERR_CHECK_PARAM Recovery action for bad parameter check + * \retval TALACT_ERR_RESET_SPI Recovery action for SPI reset required + * \retval TALACT_NO_ACTION Function completed successfully, no action required + */ +uint32_t TALISE_txNcoShifterSet(taliseDevice_t *device, taliseTxNcoShifterCfg_t *txNcoTestToneCfg); + /** * \brief Configures Gain steps and the GPIO inputs for Tx attenuation control * diff --git a/drivers/iio/adc/talise/talise_tx_types.h b/drivers/iio/adc/talise/talise_tx_types.h index d7cea52788f7f1..d0cdc8dc61484a 100644 --- a/drivers/iio/adc/talise/talise_tx_types.h +++ b/drivers/iio/adc/talise/talise_tx_types.h @@ -3,7 +3,7 @@ * \file talise_tx_types.h * \brief Contains Talise API Tx datapath data types * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -32,7 +32,7 @@ typedef enum */ typedef enum { - TAL_DACFS_0DB = 0x0, /*!< No Full Scale Boost */ + TAL_DACFS_0DB = 0x0, /*!< No Full Scale Boost */ TAL_DACFS_3DB = 0x1F /*!< Full scale boost = 3dB */ } taliseDacFullScale_t; @@ -52,11 +52,35 @@ typedef enum */ typedef struct { - uint8_t enable; /*!< 0 = Disable Tx NCO, 1 = Enable Tx NCO on both transmitters */ - int32_t tx1ToneFreq_kHz; /*!< Signed frequency in kHz of the desired Tx1 tone */ - int32_t tx2ToneFreq_kHz; /*!< Signed frequency in kHz of the desired Tx2 tone */ + uint8_t enable; /*!< 0 = Disable Tx NCO, 1 = Enable Tx NCO on both transmitters */ + int32_t tx1ToneFreq_kHz; /*!< Signed frequency in kHz of the desired Tx1 tone */ + int32_t tx2ToneFreq_kHz; /*!< Signed frequency in kHz of the desired Tx2 tone */ } taliseTxNcoTestToneCfg_t; +/** + * \brief Enum to set the Tx Atenuation step size + */ +typedef enum +{ + TAL_TXNCO_DISABLE = 0, /*!< TX NCO Disable */ + TAL_TXNCO_TX1_ENABLE = 1, /*!< TX NCO Tx1 Enable */ + TAL_TXNCO_TX2_ENABLE = 2, /*!< TX NCO Tx2 Enable */ + TAL_TXNCO_ENABLE_ALL = 3 /*!< TX NCO Tx1 & Tx2 Enable */ +} taliseTxNCOSelect_t; + +/** + * \brief Data structure to hold Talise Tx NCO Configuration (tone configuration, enable/disable and tone phase configuration) + */ +typedef struct +{ + taliseTxNCOSelect_t enableNCO; /* < 0 = Disable NCO, 1 = Enable Tx1 NCO, 2 = Enable Tx2 NCO, */ + int32_t tx1ToneFreq_kHz; /*!< Signed frequency in kHz of the desired Tx1 tone */ + int32_t tx2ToneFreq_kHz; /*!< Signed frequency in kHz of the desired Tx2 tone */ + int32_t tx1TonePhaseDeg; /*!< Tx1 Tone Phase degree */ + int32_t tx2TonePhaseDeg; /*!< Tx2 Tone Phase degree */ +} taliseTxNcoShifterCfg_t; + + /** * \brief Data structure to hold Talise Tx Attenuation Control Pin Configuration */ diff --git a/drivers/iio/adc/talise/talise_types.h b/drivers/iio/adc/talise/talise_types.h index 3fde89bf16cd9f..28a33fe3b5e859 100644 --- a/drivers/iio/adc/talise/talise_types.h +++ b/drivers/iio/adc/talise/talise_types.h @@ -3,7 +3,7 @@ * \file talise_types.h * \brief Contains Talise API configuration and run-time type definitions * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. @@ -404,15 +404,15 @@ typedef struct */ typedef struct { - taliseStates_t devState; /*!< Current device state of the part, i.e., radio on, radio off, arm loaded, etc., defined by deviceState enum */ + taliseStates_t devState; /*!< Current device state of the part, i.e., radio on, radio off, arm loaded, etc., defined by deviceState enum */ uint8_t initializedChannels; /*!< Holds Rx/ORx/Tx channels that were initialized and calibrated for the current device */ - uint8_t profilesValid; /*!< Current device profilesValid bit field for use notification, i.e., Tx = 0x01, Rx = 0x02, Orx = 0x04 */ - uint32_t errSource; /*!< Current source of error returned */ - uint32_t errCode; /*!< Current error code returned */ - taliseClocks_t clocks; /*!< Currently calculated Talise digital clocks for the selected init profiles */ - taliseGainMode_t gainMode; /*!< Current device gain mode, which can be MGC, AGCFAST, AGCSLOW, or HYBRID */ - taliseGainIndex_t gainIndexes; /*!< Current device gain index values */ - taliseTxAttenStepSize_t txAttenStepSize; /*!< Current tx Atten step size */ + uint8_t profilesValid; /*!< Current device profilesValid bit field for use notification, i.e., Tx = 0x01, Rx = 0x02, Orx = 0x04 */ + uint32_t errSource; /*!< Current source of error returned */ + uint32_t errCode; /*!< Current error code returned */ + taliseClocks_t clocks; /*!< Currently calculated Talise digital clocks for the selected init profiles */ + taliseGainMode_t gainMode; /*!< Current device gain mode, which can be MGC, AGCFAST, AGCSLOW, or HYBRID */ + taliseGainIndex_t gainIndexes; /*!< Current device gain index values */ + taliseTxAttenStepSize_t txAttenStepSize; /*!< Current tx Atten step size */ uint8_t orxAdcStitchingEnabled; /*!< TALISE_initialize sets to 1 if ORx ADC stitching enabled, 0 if not required */ uint32_t usedGpiopins; /*!< Each bit position 'N' indicates whether the GPIO 'N' is assigned to some function (if 1) or not (if 0) */ uint16_t usedGpio3p3pins; /*!< Each bit position 'N' indicates whether the GPIO3.3 'N' is assigned to some function (if 1) or not (if 0) */ diff --git a/drivers/iio/adc/talise/talise_user.c b/drivers/iio/adc/talise/talise_user.c index 75e2be3611ba14..082af0d64cd3ba 100644 --- a/drivers/iio/adc/talise/talise_user.c +++ b/drivers/iio/adc/talise/talise_user.c @@ -3,7 +3,7 @@ * \file talise_user.c * \brief Contains Talise API default gain table values for Rx and ObsRx channels. This file contains information which can be modified by the user. * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_user.h b/drivers/iio/adc/talise/talise_user.h index 6ef3d5cb2e3b0b..5fcf0b7bd3f19c 100644 --- a/drivers/iio/adc/talise/talise_user.h +++ b/drivers/iio/adc/talise/talise_user.h @@ -3,7 +3,7 @@ * \file talise_user.h * \brief Contains Talise API macro definitions and global structure declarations for talise_user.c * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. diff --git a/drivers/iio/adc/talise/talise_version.h b/drivers/iio/adc/talise/talise_version.h index 31875b8c150ba9..3accefa16e3d94 100644 --- a/drivers/iio/adc/talise/talise_version.h +++ b/drivers/iio/adc/talise/talise_version.h @@ -3,7 +3,7 @@ * \file talise_version.h * \brief Contains the version number for the Talise API * - * Talise API version: 3.6.0.5 + * Talise API version: 3.6.2.1 */ #ifndef _TALISEVERSION_H_ @@ -15,8 +15,8 @@ extern "C" { #define TAL_CURRENT_SI_VERSION 3 #define TAL_CURRENT_MAJOR_VERSION 6 -#define TAL_CURRENT_MINOR_VERSION 0 -#define TAL_CURRENT_BUILD_VERSION 5 +#define TAL_CURRENT_MINOR_VERSION 2 +#define TAL_CURRENT_BUILD_VERSION 1 #ifdef __cplusplus } From 9c3b12b730ca93069f1064b392064b850d0fafd0 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Tue, 3 May 2022 11:56:16 +0300 Subject: [PATCH 325/407] clk: ad9545: fix zero delay property Rename the DT property that specifies the rate of the hitless feedback path to a less confusing name. Fixes: 64af96d2ea6f ("clk: ad9545: add zero delay support") Signed-off-by: Alexandru Tachici --- drivers/clk/adi/clk-ad9545.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c index 1e8b0631fe63de..9c94775c5cba70 100644 --- a/drivers/clk/adi/clk-ad9545.c +++ b/drivers/clk/adi/clk-ad9545.c @@ -838,7 +838,8 @@ static int ad9545_parse_dt_plls(struct ad9545_state *st) st->pll_clks[addr].internal_zero_delay_source = val; } - ret = fwnode_property_read_u32(child, "adi,pll-internal-zero-delay", &val); + ret = fwnode_property_read_u32(child, "adi,pll-internal-zero-delay-feedback-hz", + &val); if (prop_found && !ret) { if (val >= AD9545_MAX_ZERO_DELAY_RATE) { dev_err(st->dev, "Invalid zero-delay output rate: %u.", val); From 20f84b2eb513919b9e5a0f5bb9558276adc9f005 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Tue, 3 May 2022 12:00:26 +0300 Subject: [PATCH 326/407] bindings: clock: ad9545: fix zero delay property Rename the DT property that specifies the rate of the hitless feedback path to a less confusing name. Fixes: b613d58ee08a ("bindings: clock: ad9545: document use of zero delay") Signed-off-by: Alexandru Tachici --- Documentation/devicetree/bindings/clock/clk-ad9545.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/clk-ad9545.yaml b/Documentation/devicetree/bindings/clock/clk-ad9545.yaml index 822e12c48097e3..2ca637bb2e10fa 100644 --- a/Documentation/devicetree/bindings/clock/clk-ad9545.yaml +++ b/Documentation/devicetree/bindings/clock/clk-ad9545.yaml @@ -267,7 +267,7 @@ patternProperties: '#size-cells': const: 0 - adi,pll-internal-zero-delay: + adi,pll-internal-zero-delay-feedback-hz: description: | Rate of the output that will be used as a feedback path for this PLL bloc. $ref: /schemas/types.yaml#/definitions/uint32 From 2357ab1d021143ace12a88e482bbb92790cb14b0 Mon Sep 17 00:00:00 2001 From: Liviu Adace Date: Wed, 4 May 2022 15:24:52 +0300 Subject: [PATCH 327/407] arch: arm: sockit_arradio: Remove vip-frame-reader The IP core is not supported anymore in recent versions of Quartus, so, it was removed from the HDL project. Signed-off-by: Liviu Adace --- .../arm/boot/dts/socfpga_cyclone5_sockit_arradio.dts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit_arradio.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit_arradio.dts index 516ba994f8cbc0..5a01c2195ef0fd 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_sockit_arradio.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit_arradio.dts @@ -121,20 +121,8 @@ #address-cells = <2>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0xc0000000 0x00010000>, - <0x00000001 0x00009000 0xff209000 0x00000080>, <0x00000001 0x00100000 0xff300000 0x00100000>; - alt_vip_vfr_vga: vip@100009000 { - compatible = "ALTR,vip-frame-reader-9.1"; - reg = <0x00000001 0x00009000 0x00000080>; - max-width = <1360>; - max-height = <768>; - bits-per-color = <8>; - colors-per-beat = <4>; - beats-per-pixel = <1>; - mem-word-width = <128>; - }; - c5soc_sys_cpu_interconnect: bridge@100100000 { compatible = "simple-bus"; reg = <0x00000001 0x00100000 0x00100000>; From ac4b28db42434672b84a48a40dd133349026eee0 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Wed, 27 Apr 2022 23:14:50 +0300 Subject: [PATCH 328/407] iio: beamformer: adar1000: Make gain write/read consistent Read value of IIO_CHAN_INFO_HARDWAREGAIN was returned as IIO_VAL_INT_PLUS_MICRO. Change the type to IIO_VAL_INT to become consistent with the IIO_CHAN_INFO_HARDWAREGAIN writing. Signed-off-by: Dragos Bogdan --- drivers/iio/beamformer/adar1000.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/iio/beamformer/adar1000.c b/drivers/iio/beamformer/adar1000.c index dca311b636b95c..1eb99711a42b92 100644 --- a/drivers/iio/beamformer/adar1000.c +++ b/drivers/iio/beamformer/adar1000.c @@ -603,13 +603,9 @@ static int adar1000_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - *val = -1 * (ret / 1000); - *val2 = (ret % 1000) * 1000; + *val = ret; - if (!*val) - *val2 *= -1; - - return IIO_VAL_INT_PLUS_MICRO; + return IIO_VAL_INT; case IIO_CHAN_INFO_PHASE: return adar1000_get_phase(st, chan->channel, chan->output, val, val2); From c1cd6d04b1205ffc814af07838e7662f17e9fc2d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 6 May 2022 10:13:01 +0200 Subject: [PATCH 329/407] microblaze: configs: adi_mb_defconfig: Add IPv6 support and sync options This enables IPv6 support and syncs some networking options with our ARM configs. Signed-off-by: Michael Hennerich --- arch/microblaze/configs/adi_mb_defconfig | 42 ++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/arch/microblaze/configs/adi_mb_defconfig b/arch/microblaze/configs/adi_mb_defconfig index ab70c2722f1d65..b9cfd4aa7623e0 100644 --- a/arch/microblaze/configs/adi_mb_defconfig +++ b/arch/microblaze/configs/adi_mb_defconfig @@ -42,9 +42,45 @@ CONFIG_CMA=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y CONFIG_INET=y -# CONFIG_IPV6 is not set -CONFIG_BRIDGE=m +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_SYN_COOKIES=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_T_FILTER=y +CONFIG_BRIDGE_EBT_T_NAT=y +CONFIG_BRIDGE_EBT_MARK_T=y +CONFIG_BRIDGE=y +CONFIG_NET_DSA=y +CONFIG_DNS_RESOLVER=y CONFIG_PCI=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y @@ -187,6 +223,8 @@ CONFIG_NFS_FS=y CONFIG_CIFS=y CONFIG_CIFS_STATS2=y CONFIG_ENCRYPTED_KEYS=y +CONFIG_CRYPTO_AUTHENC=y +CONFIG_CRC_CCITT=y CONFIG_DMA_CMA=y CONFIG_CMA_SIZE_PERCENTAGE=25 CONFIG_CMA_SIZE_SEL_PERCENTAGE=y From e16055abfeca1255229cbf5aa6eb5e9787ef39bb Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Thu, 5 May 2022 17:28:46 +0300 Subject: [PATCH 330/407] net: ethernet: adi: adin1110: Fix TX space read TX FIFO space is stored in the register as number of half-words (2 bytes). Fixes: 757a6117f7ff (net: adi: adin1110: Add initial support) Signed-off-by: Alexandru Tachici --- drivers/net/ethernet/adi/adin1110.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index 9ba74bd08d950c..b140228fe92ca2 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -494,7 +494,8 @@ static irqreturn_t adin1110_irq(int irq, void *p) return IRQ_HANDLED; } - priv->tx_space = val; + /* TX FIFO space is expressed in half-words */ + priv->tx_space = 2 * val; if (status1 & ADIN1110_RX_RDY) adin1110_read_frames(priv); @@ -685,7 +686,7 @@ static int adin1110_net_open(struct net_device *net_dev) return ret; } - priv->tx_space = val; + priv->tx_space = 2 * val; ret = adin1110_init_mac(priv); if (ret < 0) From 52b153b2018ac349224f6e62bccb206e98c991f4 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Mon, 9 May 2022 17:00:16 +0300 Subject: [PATCH 331/407] net: phy: adin1100: Add ADIN2111 PHY_ID The two PHYs encapsulated in the ADIN2111 2-port switch is identical with the stand-alone version. Add the ADIN2111 PHY to the match device ID list in order to be discovered by the PAL after ADIN2111 registers its own MDIO bus. Signed-off-by: Alexandru Tachici --- drivers/net/phy/adin1100.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/adin1100.c b/drivers/net/phy/adin1100.c index a165c737b51415..48c17bf581fd69 100644 --- a/drivers/net/phy/adin1100.c +++ b/drivers/net/phy/adin1100.c @@ -16,6 +16,7 @@ #define PHY_ID_ADIN1100 0x0283bc81 #define PHY_ID_ADIN1110 0x0283bc91 +#define PHY_ID_ADIN2111 0x0283bca1 static const int phy_10_features_array[] = { ETHTOOL_LINK_MODE_10baseT_Full_BIT, @@ -131,6 +132,8 @@ static int adin_match_phy_device(struct phy_device *phydev) return 1; case PHY_ID_ADIN1110: return 1; + case PHY_ID_ADIN2111: + return 1; default: return 0; } @@ -482,7 +485,8 @@ static int adin_probe(struct phy_device *phydev) static struct phy_driver adin_driver[] = { { - PHY_ID_MATCH_MODEL(PHY_ID_ADIN1100), + .phy_id = PHY_ID_ADIN1100, + .phy_id_mask = GENMASK(31, 8), .name = "ADIN1100", .get_features = adin_get_features, .match_phy_device = adin_match_phy_device, @@ -506,6 +510,7 @@ module_phy_driver(adin_driver); static struct mdio_device_id __maybe_unused adin_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1100) }, { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1110) }, + { PHY_ID_MATCH_MODEL(PHY_ID_ADIN2111) }, { } }; From 8922e5b14b6237e0a421f840e8fcb2b8f8d84c25 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Mon, 9 May 2022 17:25:27 +0300 Subject: [PATCH 332/407] net: ethernet: adi: adin1110: Fix mutex unlock path On adin1110_init_mac() error patch add unlock_mutex(). Fixes: 757a6117f7ff (net: adi: adin1110: Add initial support) Signed-off-by: Alexandru Tachici --- drivers/net/ethernet/adi/adin1110.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index b140228fe92ca2..ed77be8cd43c37 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -689,8 +689,10 @@ static int adin1110_net_open(struct net_device *net_dev) priv->tx_space = 2 * val; ret = adin1110_init_mac(priv); - if (ret < 0) + if (ret < 0) { + mutex_unlock(&priv->lock); return ret; + } mutex_unlock(&priv->lock); From b5c34085eb4dbe415028ac0d5fe226aba38c4a2d Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Mon, 9 May 2022 17:14:48 +0300 Subject: [PATCH 333/407] net: ethernet: adi: adin1110: Add adin2111 support The ADIN2111 is a low power, low complexity, two-Ethernet ports switch with integrated 10BASE-T1L PHYs and one serial peripheral interface (SPI) port. The device is designed for industrial Ethernet applications using low power constrained nodes and is compliant with the IEEE 802.3cg-2019 Ethernet standard for long reach 10 Mbps single pair Ethernet (SPE). The switch supports various routing configurations between the two Ethernet ports and the SPI host port providing a flexible solution for line, daisy-chain, or ring network topologies. The ADIN2111 supports cable reach of up to 1700 meters with ultra low power consumption of 77 mW. The two PHY cores support the 1.0 V p-p operating mode and the 2.4 V p-p operating mode defined in the IEEE 802.3cg standard. The device integrates the switch, two Ethernet physical layer (PHY) cores with a media access control (MAC) interface and all the associated analog circuitry, and input and output clock buffering. The device also includes internal buffer queues, the SPI and subsystem registers, as well as the control logic to manage the reset and clock control and hardware pin configuration. Access to the PHYs is exposed via an internal MDIO bus. Writes/reads can be performed by reading/writing to the ADIN2111 MDIO registers via SPI. On probe, for each port, a struct net_device is allocated and registered, called port netdev. Default behaviour of the MAC is to forward any unknown host to the other port and accept only broadcast address and host address. Signed-off-by: Alexandru Tachici --- drivers/net/ethernet/adi/adin1110.c | 528 +++++++++++++++++++--------- 1 file changed, 362 insertions(+), 166 deletions(-) diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index ed77be8cd43c37..f38e1c09c182cd 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -26,22 +26,28 @@ #define ADIN1110_PHY_ID 0x1 +#define ADIN1110_CONFIG1 0x04 +#define ADIN1110_CONFIG1_SYNC BIT(15) + #define ADIN1110_CONFIG2 0x06 +#define ADIN211_FWD_UNK2PORT GENMASK(14, 13) +#define ADIN2111_P2_FWD_UNK2HOST BIT(12) #define ADIN1110_CRC_APPEND BIT(5) #define ADIN1110_FWD_UNK2HOST BIT(2) #define ADIN1110_STATUS0 0x08 #define ADIN1110_STATUS1 0x09 +#define ADIN2111_P2_RX_RDY BIT(17) #define ADIN1110_SPI_ERR BIT(10) #define ADIN1110_RX_RDY BIT(4) #define ADIN1110_TX_RDY BIT(3) #define ADIN1110_IMASK1 0x0D +#define ADIN2111_RX_RDY_IRQ BIT(17) #define ADIN1110_SPI_ERR_IRQ BIT(10) #define ADIN1110_RX_RDY_IRQ BIT(4) #define ADIN1110_TX_RDY_IRQ BIT(3) -#define ADIN1110_LINK_CHANGE_IRQ BIT(1) #define ADIN1110_MDIOACC 0x20 #define ADIN1110_MDIO_TRDONE BIT(31) @@ -63,6 +69,7 @@ #define ADIN1110_TFC 0x3F #define ADIN1110_MAC_ADDR_FILTER_UPR 0x50 +#define ADIN2111_MAC_ADDR_APPLY2PORT2 BIT(31) #define ADIN1110_MAC_ADDR_APPLY2PORT BIT(30) #define ADIN1110_MAC_ADDR_HOST_PRI BIT(19) #define ADIN1110_MAC_ADDR_TO_HOST BIT(16) @@ -76,19 +83,22 @@ #define ADIN1110_RX_FSIZE 0x90 #define ADIN1110_RX 0x91 -#define ADIN1110_RX_FRM_CNT 0xA0 -#define ADIN1110_RX_MCAST_CNT 0xA2 -#define ADIN1110_RX_CRC_ERR_CNT 0xA4 -#define ADIN1110_RX_ALGN_ERR_CNT 0xA5 -#define ADIN1110_RX_LS_ERR_CNT 0xA6 -#define ADIN1110_RX_PHY_ERR_CNT 0xA7 -#define ADIN1110_RX_DROP_FULL_CNT 0xAC +#define ADIN1110_RX_FRM_CNT(x) (0xA0 + ((x) * 0x30)) +#define ADIN1110_RX_MCAST_CNT(x) (0xA2 + ((x) * 0x30)) +#define ADIN1110_RX_CRC_ERR_CNT(x) (0xA4 + ((x) * 0x30)) +#define ADIN1110_RX_ALGN_ERR_CNT(x) (0xA5 + ((x) * 0x30)) +#define ADIN1110_RX_LS_ERR_CNT(x) (0xA6 + ((x) * 0x30)) +#define ADIN1110_RX_PHY_ERR_CNT(x) (0xA7 + ((x) * 0x30)) +#define ADIN1110_RX_DROP_FULL_CNT(x) (0xAC + ((x) * 0x30)) + +#define ADIN1110_TX_FRM_CNT(x) (0xA8 + ((x) * 0x30)) +#define ADIN1110_TX_MCAST_CNT(x) (0xAA + ((x) * 0x30)) -#define ADIN1110_TX_FRM_CNT 0xA8 -#define ADIN1110_TX_MCAST_CNT 0xAA +#define ADIN2111_RX_P2_FSIZE 0xC0 +#define ADIN2111_RX_P2 0xC1 -#define ADIN1110_CLEAR_STATUS0 0x1F7F -#define ADIN1110_CLEAR_STATUS1 0x1F01D0A +#define ADIN1110_CLEAR_STATUS0 0xFFF +#define ADIN1110_CLEAR_STATUS1 U32_MAX /* MDIO_OP codes */ #define ADIN1110_MDIO_OP_WR 0x1 @@ -106,28 +116,75 @@ #define ADIN1110_FEC_LEN 4 #define ADIN1110_PHY_ID_VAL 0x0283BC91 +#define ADIN2111_PHY_ID_VAL 0x0283BCA1 #define ADIN1110_TX_SPACE_MAX 0x0FFF +#define ADIN_MAC_MAX_PORTS 2 + +#define ADIN_MAC_ADDR_SLOT 0 +#define ADIN_MAC_BROADCAST_ADDR_SLOT 1 +#define ADIN_MAC_MULTICAST_ADDR_SLOT 2 + DECLARE_CRC8_TABLE(adin1110_crc_table); +enum adin1110_chips_id { + ADIN1110_MAC = 0, + ADIN2111_MAC, +}; + +struct adin1110_cfg { + enum adin1110_chips_id id; + char name[MDIO_NAME_SIZE]; + u32 phy_ids[PHY_MAX_ADDR]; + u32 ports_nr; + u32 phy_id_val; +}; + +struct adin1110_port_priv { + struct adin1110_priv *priv; + struct net_device *netdev; + struct phy_device *phydev; + struct work_struct tx_work; + u64 rx_bytes; + u64 tx_bytes; + struct work_struct rx_mode_work; + u32 flags; + struct sk_buff_head txq; + u32 nr; + struct adin1110_cfg *cfg; +}; + struct adin1110_priv { - struct mutex lock; /* protect spi */ - spinlock_t state_lock; /* protect RX mode */ - struct work_struct tx_work; - u32 tx_space; - u64 rx_bytes; - u64 tx_bytes; - struct work_struct rx_mode_work; - u32 flags; - struct sk_buff_head txq; - struct mii_bus *mii_bus; - struct phy_device *phydev; - struct net_device *netdev; - struct spi_device *spidev; - bool append_crc; - int irq; - u8 data[ADIN1110_MAX_BUFF] ____cacheline_aligned; + struct mutex lock; /* protect spi */ + spinlock_t state_lock; /* protect RX mode */ + struct mii_bus *mii_bus; + struct spi_device *spidev; + bool append_crc; + struct adin1110_cfg *cfg; + u32 tx_space; + u32 irq_mask; + int irq; + struct adin1110_port_priv *ports[ADIN_MAC_MAX_PORTS]; + char mii_bus_name[MII_BUS_ID_SIZE]; + u8 data[ADIN1110_MAX_BUFF] ____cacheline_aligned; +}; + +struct adin1110_cfg adin1110_cfgs[] = { + { + .id = ADIN1110_MAC, + .name = "adin1110", + .phy_ids = {1}, + .ports_nr = 1, + .phy_id_val = ADIN1110_PHY_ID_VAL, + }, + { + .id = ADIN2111_MAC, + .name = "adin2111", + .phy_ids = {1, 2}, + .ports_nr = 2, + .phy_id_val = ADIN2111_PHY_ID_VAL, + }, }; static u8 adin1110_crc_data(u8 *data, u32 len) @@ -175,7 +232,7 @@ static int adin1110_read_reg(struct adin1110_priv *priv, u16 reg, u32 *val) recv_crc = priv->data[header_len + ADIN1110_REG_LEN]; if (crc != recv_crc) { - netdev_err(priv->netdev, "CRC error."); + dev_err(&priv->spidev->dev, "CRC error."); return -EBADMSG; } } @@ -236,18 +293,26 @@ static int adin1110_round_len(int len) return len; } -static int adin1110_read_fifo(struct adin1110_priv *priv) +static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) { + struct adin1110_priv *priv = port_priv->priv; u32 header_len = ADIN1110_RD_HEADER_LEN; - __le16 __reg = cpu_to_le16(ADIN1110_RX); struct spi_transfer t[2] = {0}; + u32 frame_size_no_fcs; struct sk_buff *rxb; u32 frame_size; - u32 frame_size_no_fcs; int round_len; + __le16 __reg; int ret; - ret = adin1110_read_reg(priv, ADIN1110_RX_FSIZE, &frame_size); + if (!port_priv->nr) { + __reg = cpu_to_le16(ADIN1110_RX); + ret = adin1110_read_reg(priv, ADIN1110_RX_FSIZE, &frame_size); + } else { + __reg = cpu_to_le16(ADIN2111_RX_P2); + ret = adin1110_read_reg(priv, ADIN2111_RX_P2_FSIZE, &frame_size); + } + if (ret < 0) return ret; @@ -261,7 +326,7 @@ static int adin1110_read_fifo(struct adin1110_priv *priv) frame_size_no_fcs = frame_size - ADIN1110_FRAME_HEADER_LEN - ADIN1110_FEC_LEN; - rxb = netdev_alloc_skb(priv->netdev, frame_size_no_fcs); + rxb = netdev_alloc_skb(port_priv->netdev, frame_size_no_fcs); if (!rxb) return -ENOMEM; @@ -293,19 +358,21 @@ static int adin1110_read_fifo(struct adin1110_priv *priv) skb_copy_to_linear_data(rxb, &priv->data[header_len + ADIN1110_FRAME_HEADER_LEN], frame_size_no_fcs); - rxb->protocol = eth_type_trans(rxb, priv->netdev); + rxb->protocol = eth_type_trans(rxb, port_priv->netdev); netif_rx_ni(rxb); - priv->rx_bytes += frame_size - ADIN1110_FRAME_HEADER_LEN; + port_priv->rx_bytes += frame_size - ADIN1110_FRAME_HEADER_LEN; return 0; } -static int adin1110_write_fifo(struct adin1110_priv *priv, struct sk_buff *txb) +static int adin1110_write_fifo(struct adin1110_port_priv *port_priv, struct sk_buff *txb) { + struct adin1110_priv *priv = port_priv->priv; __le16 __reg = cpu_to_le16(ADIN1110_TX); u32 header_len = ADIN1110_WR_HEADER_LEN; + __be16 frame_header; int padding = 0; int round_len; int padded_len; @@ -338,13 +405,17 @@ static int adin1110_write_fifo(struct adin1110_priv *priv, struct sk_buff *txb) header_len++; } + /* mention the port on which to send the frame in the frame header */ + frame_header = cpu_to_be16(port_priv->nr); + memcpy(&priv->data[header_len], &frame_header, ADIN1110_FRAME_HEADER_LEN); + memcpy(&priv->data[header_len + ADIN1110_FRAME_HEADER_LEN], txb->data, txb->len); ret = spi_write(priv->spidev, &priv->data[0], round_len + header_len); if (ret < 0) return ret; - priv->tx_bytes += txb->len; + port_priv->tx_bytes += txb->len; return 0; } @@ -371,7 +442,7 @@ static int adin1110_mdio_read(struct mii_bus *bus, int phy_id, int reg) val |= FIELD_PREP(ADIN1110_MDIO_OP, ADIN1110_MDIO_OP_RD); val |= FIELD_PREP(ADIN1110_MDIO_ST, 0x1); - val |= FIELD_PREP(ADIN1110_MDIO_PRTAD, 0x1); + val |= FIELD_PREP(ADIN1110_MDIO_PRTAD, phy_id); val |= FIELD_PREP(ADIN1110_MDIO_DEVAD, reg); /* write the clause 22 read command to the chip */ @@ -407,7 +478,7 @@ static int adin1110_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 reg val |= FIELD_PREP(ADIN1110_MDIO_OP, ADIN1110_MDIO_OP_WR); val |= FIELD_PREP(ADIN1110_MDIO_ST, 0x1); - val |= FIELD_PREP(ADIN1110_MDIO_PRTAD, 0x1); + val |= FIELD_PREP(ADIN1110_MDIO_PRTAD, phy_id); val |= FIELD_PREP(ADIN1110_MDIO_DEVAD, reg); val |= FIELD_PREP(ADIN1110_MDIO_DATA, reg_val); @@ -426,6 +497,7 @@ static int adin1110_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 reg } /* ADIN1110 MAC-PHY contains an ADIN1100 PHY. + * ADIN2111 MAC-PHY contains two ADIN1100 PHYs. * By registering a new MDIO bus we allow the PAL to discover * the encapsulated PHY and probe the ADIN1100 driver. */ @@ -438,12 +510,15 @@ static int adin1110_register_mdiobus(struct adin1110_priv *priv, struct device * if (!mii_bus) return -ENOMEM; - mii_bus->name = "adin1110_eth_mii"; + snprintf(priv->mii_bus_name, MII_BUS_ID_SIZE, "%s-%u", + priv->cfg->name, priv->spidev->chip_select); + + mii_bus->name = priv->mii_bus_name; mii_bus->read = adin1110_mdio_read; mii_bus->write = adin1110_mdio_write; mii_bus->priv = priv; mii_bus->parent = dev; - mii_bus->phy_mask = ~((u32)BIT(0)); + mii_bus->phy_mask = ~((u32)GENMASK(2, 0)); snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); ret = devm_mdiobus_register(dev, mii_bus); @@ -455,8 +530,17 @@ static int adin1110_register_mdiobus(struct adin1110_priv *priv, struct device * return 0; } -static void adin1110_read_frames(struct adin1110_priv *priv) +static bool adin1110_port_rx_ready(struct adin1110_port_priv *port_priv, u32 status) +{ + if (!port_priv->nr) + return !!(status & ADIN1110_RX_RDY); + else + return !!(status & ADIN2111_P2_RX_RDY); +} + +static void adin1110_read_frames(struct adin1110_port_priv *port_priv) { + struct adin1110_priv *priv = port_priv->priv; u32 status1; int ret; @@ -465,28 +549,37 @@ static void adin1110_read_frames(struct adin1110_priv *priv) if (ret < 0) return; - if (!(status1 & ADIN1110_RX_RDY)) + if (!adin1110_port_rx_ready(port_priv, status1)) break; - ret = adin1110_read_fifo(priv); + ret = adin1110_read_fifo(port_priv); if (ret < 0) return; } } +static void adin1110_wake_queues(struct adin1110_priv *priv) +{ + int i; + + for (i = 0; i < priv->cfg->ports_nr; i++) + netif_wake_queue(priv->ports[i]->netdev); +} + static irqreturn_t adin1110_irq(int irq, void *p) { struct adin1110_priv *priv = p; u32 status1; u32 val; int ret; + int i; mutex_lock(&priv->lock); adin1110_read_reg(priv, ADIN1110_STATUS1, &status1); if (priv->append_crc && (status1 & ADIN1110_SPI_ERR)) - netdev_warn(priv->netdev, "SPI CRC error on write.\n"); + dev_warn(&priv->spidev->dev, "SPI CRC error on write.\n"); ret = adin1110_read_reg(priv, ADIN1110_TX_SPACE, &val); if (ret < 0) { @@ -497,30 +590,39 @@ static irqreturn_t adin1110_irq(int irq, void *p) /* TX FIFO space is expressed in half-words */ priv->tx_space = 2 * val; - if (status1 & ADIN1110_RX_RDY) - adin1110_read_frames(priv); + for (i = 0; i < priv->cfg->ports_nr; i++) { + if (adin1110_port_rx_ready(priv->ports[i], status1)) + adin1110_read_frames(priv->ports[i]); + } /* clear IRQ sources */ - adin1110_write_reg(priv, ADIN1110_STATUS0, ADIN1110_CLEAR_STATUS0); - adin1110_write_reg(priv, ADIN1110_STATUS1, ADIN1110_CLEAR_STATUS1); + ret = adin1110_write_reg(priv, ADIN1110_STATUS0, ADIN1110_CLEAR_STATUS0); + ret = adin1110_write_reg(priv, ADIN1110_STATUS1, priv->irq_mask); mutex_unlock(&priv->lock); if (priv->tx_space > 0) - netif_wake_queue(priv->netdev); + adin1110_wake_queues(priv); return IRQ_HANDLED; } /* ADIN1110 can filter up to 16 MAC addresses, mac_nr here is the slot used */ -static int adin1110_write_mac_address(struct adin1110_priv *priv, int mac_nr, u8 *addr, u8 *mask) +static int adin1110_write_mac_address(struct adin1110_port_priv *port_priv, int mac_nr, u8 *addr, + u8 *mask) { + struct adin1110_priv *priv = port_priv->priv; u32 offset = mac_nr * 2; + u32 port_rules; int ret; u32 val; + port_rules = ADIN1110_MAC_ADDR_APPLY2PORT; + if (priv->cfg->id == ADIN2111_MAC) + port_rules |= ADIN2111_MAC_ADDR_APPLY2PORT2; + /* tell MAC to forward this DA to host */ - val = ADIN1110_MAC_ADDR_APPLY2PORT | ADIN1110_MAC_ADDR_TO_HOST; + val = port_rules | ADIN1110_MAC_ADDR_TO_HOST; val |= get_unaligned_be16(&addr[0]); ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_FILTER_UPR + offset, val); if (ret < 0) @@ -531,8 +633,7 @@ static int adin1110_write_mac_address(struct adin1110_priv *priv, int mac_nr, u8 if (ret < 0) return ret; - val = ADIN1110_MAC_ADDR_APPLY2PORT | ADIN1110_MAC_ADDR_TO_HOST; - val |= get_unaligned_be16(&mask[0]); + val = get_unaligned_be16(&mask[0]); ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_UPR + offset, val); if (ret < 0) return ret; @@ -541,8 +642,9 @@ static int adin1110_write_mac_address(struct adin1110_priv *priv, int mac_nr, u8 return adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_LWR + offset, val); } -static int adin1110_clear_mac_address(struct adin1110_priv *priv, int mac_nr) +static int adin1110_clear_mac_address(struct adin1110_port_priv *port_priv, int mac_nr) { + struct adin1110_priv *priv = port_priv->priv; u32 offset = mac_nr * 2; int ret; @@ -561,7 +663,8 @@ static int adin1110_clear_mac_address(struct adin1110_priv *priv, int mac_nr) return adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_LWR + offset, 0); } -static int adin1110_multicast_filter(struct adin1110_priv *priv, int mac_nr, bool accept_multicast) +static int adin1110_multicast_filter(struct adin1110_port_priv *port_priv, int mac_nr, + bool accept_multicast) { u8 mask[ETH_ALEN] = {0}; u8 mac[ETH_ALEN] = {0}; @@ -570,15 +673,15 @@ static int adin1110_multicast_filter(struct adin1110_priv *priv, int mac_nr, boo mask[0] = BIT(1); mac[0] = BIT(1); - return adin1110_write_mac_address(priv, mac_nr, mac, mask); + return adin1110_write_mac_address(port_priv, mac_nr, mac, mask); } - return adin1110_clear_mac_address(priv, mac_nr); + return adin1110_clear_mac_address(port_priv, mac_nr); } static int adin1110_set_mac_address(struct net_device *netdev, void *addr) { - struct adin1110_priv *priv = netdev_priv(netdev); + struct adin1110_port_priv *port_priv = netdev_priv(netdev); struct sockaddr *sa = addr; u8 mask[ETH_ALEN]; @@ -591,7 +694,7 @@ static int adin1110_set_mac_address(struct net_device *netdev, void *addr) ether_addr_copy(netdev->dev_addr, sa->sa_data); memset(mask, 0xFF, ETH_ALEN); - return adin1110_write_mac_address(priv, 0, netdev->dev_addr, mask); + return adin1110_write_mac_address(port_priv, ADIN_MAC_ADDR_SLOT, netdev->dev_addr, mask); } static int adin1110_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -607,46 +710,55 @@ static int adin1110_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) static void adin1110_rx_mode_work(struct work_struct *work) { - struct adin1110_priv *priv = container_of(work, struct adin1110_priv, rx_mode_work); + struct adin1110_port_priv *port_priv = container_of(work, struct adin1110_port_priv, rx_mode_work); + struct adin1110_priv *priv = port_priv->priv; + u32 mask; + + if (!port_priv->nr) + mask = ADIN1110_FWD_UNK2HOST; + else + mask = ADIN2111_P2_FWD_UNK2HOST; mutex_lock(&priv->lock); - adin1110_set_bits(priv, ADIN1110_CONFIG2, ADIN1110_FWD_UNK2HOST, - (priv->flags & IFF_PROMISC) ? ADIN1110_FWD_UNK2HOST : 0); + adin1110_set_bits(priv, ADIN1110_CONFIG2, mask, + (port_priv->flags & IFF_PROMISC) ? mask : 0); - adin1110_multicast_filter(priv, 2, !!(priv->flags & IFF_ALLMULTI)); + adin1110_multicast_filter(port_priv, ADIN_MAC_MULTICAST_ADDR_SLOT, + !!(port_priv->flags & IFF_ALLMULTI)); mutex_unlock(&priv->lock); } static void adin1110_set_rx_mode(struct net_device *dev) { - struct adin1110_priv *priv = netdev_priv(dev); + struct adin1110_port_priv *port_priv = netdev_priv(dev); + struct adin1110_priv *priv = port_priv->priv; spin_lock(&priv->state_lock); - priv->flags = dev->flags; - schedule_work(&priv->rx_mode_work); + port_priv->flags = dev->flags; + schedule_work(&port_priv->rx_mode_work); spin_unlock(&priv->state_lock); } -static int adin1110_init_mac(struct adin1110_priv *priv) +static int adin1110_init_mac(struct adin1110_port_priv *port_priv) { - struct net_device *netdev = priv->netdev; + struct net_device *netdev = port_priv->netdev; u8 mask[ETH_ALEN]; u8 mac[ETH_ALEN]; int ret; memset(mask, 0xFF, ETH_ALEN); - ret = adin1110_write_mac_address(priv, 0, netdev->dev_addr, mask); + ret = adin1110_write_mac_address(port_priv, ADIN_MAC_ADDR_SLOT, netdev->dev_addr, mask); if (ret < 0) { netdev_err(netdev, "Could not set MAC address: %pM, %d\n", mac, ret); return ret; } memset(mac, 0xFF, ETH_ALEN); - ret = adin1110_write_mac_address(priv, 1, mac, mask); + ret = adin1110_write_mac_address(port_priv, ADIN_MAC_BROADCAST_ADDR_SLOT, mac, mask); if (ret < 0) { netdev_err(netdev, "Could not set Broadcast MAC address: %d\n", ret); return ret; @@ -657,22 +769,32 @@ static int adin1110_init_mac(struct adin1110_priv *priv) static int adin1110_net_open(struct net_device *net_dev) { - struct adin1110_priv *priv = netdev_priv(net_dev); + struct adin1110_port_priv *port_priv = netdev_priv(net_dev); + struct adin1110_priv *priv = port_priv->priv; u32 val; int ret; mutex_lock(&priv->lock); + /* Configure MAC to compute and append the FCS itself. + * If ADIN2111 configure MAC to forward unknown host to other port. + */ val = ADIN1110_CRC_APPEND; + if (priv->cfg->id == ADIN2111_MAC) + val |= ADIN211_FWD_UNK2PORT; + ret = adin1110_set_bits(priv, ADIN1110_CONFIG2, val, val); if (ret < 0) { mutex_unlock(&priv->lock); return ret; } - val = ADIN1110_TX_RDY_IRQ | ADIN1110_RX_RDY_IRQ | ADIN1110_LINK_CHANGE_IRQ | - ADIN1110_SPI_ERR_IRQ; - ret = adin1110_set_bits(priv, ADIN1110_IMASK1, val, 0); + val = ADIN1110_TX_RDY_IRQ | ADIN1110_RX_RDY_IRQ | ADIN1110_SPI_ERR_IRQ; + if (priv->cfg->id == ADIN2111_MAC) + val |= ADIN2111_RX_RDY_IRQ; + + priv->irq_mask = val; + ret = adin1110_write_reg(priv, ADIN1110_IMASK1, ~val); if (ret < 0) { netdev_err(net_dev, "Failed to enable chip IRQs: %d\n", ret); mutex_unlock(&priv->lock); @@ -688,62 +810,59 @@ static int adin1110_net_open(struct net_device *net_dev) priv->tx_space = 2 * val; - ret = adin1110_init_mac(priv); + ret = adin1110_init_mac(port_priv); if (ret < 0) { mutex_unlock(&priv->lock); return ret; } - mutex_unlock(&priv->lock); - - phy_start(priv->phydev); - - /* ADIN1110 INT_N pin will be used to signal the host */ - ret = request_threaded_irq(net_dev->irq, NULL, adin1110_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - net_dev->name, priv); - + ret = adin1110_set_bits(priv, ADIN1110_CONFIG1, ADIN1110_CONFIG1_SYNC, + ADIN1110_CONFIG1_SYNC); if (ret < 0) { - netdev_err(net_dev, "Failed to get IRQ: %d\n", ret); + mutex_unlock(&priv->lock); return ret; } - netif_start_queue(priv->netdev); + mutex_unlock(&priv->lock); + + phy_start(port_priv->phydev); + + netif_start_queue(net_dev); return ret; } static int adin1110_net_stop(struct net_device *net_dev) { - struct adin1110_priv *priv = netdev_priv(net_dev); + struct adin1110_port_priv *port_priv = netdev_priv(net_dev); - netif_stop_queue(priv->netdev); - flush_work(&priv->tx_work); - phy_stop(priv->phydev); - free_irq(net_dev->irq, priv); + netif_stop_queue(port_priv->netdev); + flush_work(&port_priv->tx_work); + phy_stop(port_priv->phydev); return 0; } static void adin1110_tx_work(struct work_struct *work) { - struct adin1110_priv *priv = container_of(work, struct adin1110_priv, tx_work); + struct adin1110_port_priv *port_priv = container_of(work, struct adin1110_port_priv, tx_work); + struct adin1110_priv *priv = port_priv->priv; struct sk_buff *txb; bool last; int ret; mutex_lock(&priv->lock); - last = skb_queue_empty(&priv->txq); + last = skb_queue_empty(&port_priv->txq); while (!last) { - txb = skb_dequeue(&priv->txq); - last = skb_queue_empty(&priv->txq); + txb = skb_dequeue(&port_priv->txq); + last = skb_queue_empty(&port_priv->txq); if (txb) { - ret = adin1110_write_fifo(priv, txb); + ret = adin1110_write_fifo(port_priv, txb); if (ret < 0) - netdev_err(priv->netdev, "Frame write error: %d\n", ret); + netdev_err(port_priv->netdev, "Frame write error: %d\n", ret); dev_kfree_skb(txb); } @@ -754,7 +873,8 @@ static void adin1110_tx_work(struct work_struct *work) static netdev_tx_t adin1110_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct adin1110_priv *priv = netdev_priv(dev); + struct adin1110_port_priv *port_priv = netdev_priv(dev); + struct adin1110_priv *priv = port_priv->priv; netdev_tx_t netdev_ret = NETDEV_TX_OK; u32 tx_space_needed; @@ -766,53 +886,78 @@ static netdev_tx_t adin1110_start_xmit(struct sk_buff *skb, struct net_device *d netdev_ret = NETDEV_TX_BUSY; } else { priv->tx_space -= tx_space_needed; - skb_queue_tail(&priv->txq, skb); + skb_queue_tail(&port_priv->txq, skb); } spin_unlock(&priv->state_lock); - schedule_work(&priv->tx_work); + schedule_work(&port_priv->tx_work); return netdev_ret; } void adin1110_ndo_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage) { - struct adin1110_priv *priv = netdev_priv(dev); + struct adin1110_port_priv *port_priv = netdev_priv(dev); + struct adin1110_priv *priv = port_priv->priv; u32 val; mutex_lock(&priv->lock); - adin1110_read_reg(priv, ADIN1110_RX_FRM_CNT, &val); + adin1110_read_reg(priv, ADIN1110_RX_FRM_CNT(port_priv->nr), &val); storage->rx_packets = val; - adin1110_read_reg(priv, ADIN1110_TX_FRM_CNT, &val); + adin1110_read_reg(priv, ADIN1110_TX_FRM_CNT(port_priv->nr), &val); storage->tx_packets = val; - storage->rx_bytes = priv->rx_bytes; - storage->tx_bytes = priv->tx_bytes; + storage->rx_bytes = port_priv->rx_bytes; + storage->tx_bytes = port_priv->tx_bytes; - adin1110_read_reg(priv, ADIN1110_RX_CRC_ERR_CNT, &val); + adin1110_read_reg(priv, ADIN1110_RX_CRC_ERR_CNT(port_priv->nr), &val); storage->rx_errors += val; - adin1110_read_reg(priv, ADIN1110_RX_ALGN_ERR_CNT, &val); + adin1110_read_reg(priv, ADIN1110_RX_ALGN_ERR_CNT(port_priv->nr), &val); storage->rx_errors += val; - adin1110_read_reg(priv, ADIN1110_RX_LS_ERR_CNT, &val); + adin1110_read_reg(priv, ADIN1110_RX_LS_ERR_CNT(port_priv->nr), &val); storage->rx_errors += val; - adin1110_read_reg(priv, ADIN1110_RX_PHY_ERR_CNT, &val); + adin1110_read_reg(priv, ADIN1110_RX_PHY_ERR_CNT(port_priv->nr), &val); storage->rx_errors += val; - adin1110_read_reg(priv, ADIN1110_RX_DROP_FULL_CNT, &val); + adin1110_read_reg(priv, ADIN1110_RX_DROP_FULL_CNT(port_priv->nr), &val); storage->rx_dropped = val; - adin1110_read_reg(priv, ADIN1110_RX_MCAST_CNT, &val); + adin1110_read_reg(priv, ADIN1110_RX_MCAST_CNT(port_priv->nr), &val); storage->multicast = val; mutex_unlock(&priv->lock); } +static int adin1110_port_get_port_parent_id(struct net_device *dev, + struct netdev_phys_item_id *ppid) +{ + struct adin1110_port_priv *port_priv = netdev_priv(dev); + struct adin1110_priv *priv = port_priv->priv; + + ppid->id_len = strnlen(priv->mii_bus_name, MII_BUS_ID_SIZE); + memcpy(ppid->id, priv->mii_bus_name, ppid->id_len); + + return 0; +} + +static int adin1110_ndo_get_phys_port_name(struct net_device *dev, char *name, size_t len) +{ + struct adin1110_port_priv *port_priv = netdev_priv(dev); + int err; + + err = snprintf(name, len, "p%d", port_priv->nr); + if (err >= len) + return -EINVAL; + + return 0; +} + static const struct net_device_ops adin1110_netdev_ops = { .ndo_open = adin1110_net_open, .ndo_stop = adin1110_net_stop, @@ -822,6 +967,8 @@ static const struct net_device_ops adin1110_netdev_ops = { .ndo_set_rx_mode = adin1110_set_rx_mode, .ndo_validate_addr = eth_validate_addr, .ndo_get_stats64 = adin1110_ndo_get_stats64, + .ndo_get_port_parent_id = adin1110_port_get_port_parent_id, + .ndo_get_phys_port_name = adin1110_ndo_get_phys_port_name, }; static void adin1110_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *di) @@ -856,13 +1003,11 @@ static int adin1110_check_spi(struct adin1110_priv *priv) if (ret < 0) return ret; - if (val != ADIN1110_PHY_ID_VAL) { - netdev_err(priv->netdev, "PHY ID read: %x\n", val); + if (val != priv->cfg->phy_id_val) { + dev_err(&priv->spidev->dev, "PHY ID read: %x\n", val); return -EIO; } - snprintf(priv->netdev->name, IFNAMSIZ, "adin1110-%u", priv->spidev->chip_select); - return 0; } @@ -871,98 +1016,149 @@ static void adin1110_disconnect_phy(void *data) phy_disconnect(data); } -static int adin1110_probe(struct spi_device *spi) +static int adin1110_probe_netdevs(struct adin1110_priv *priv) { - struct device *dev = &spi->dev; - struct adin1110_priv *priv; + struct device *dev = &priv->spidev->dev; + struct adin1110_port_priv *port_priv; struct net_device *netdev; const u8 *mac_addr; u8 mac[ETH_ALEN]; int ret; + int i; + + for (i = 0; i < priv->cfg->ports_nr; i++) { + netdev = devm_alloc_etherdev(dev, sizeof(*port_priv)); + if (!netdev) + return -ENOMEM; + + port_priv = netdev_priv(netdev); + port_priv->netdev = netdev; + port_priv->priv = priv; + port_priv->cfg = priv->cfg; + port_priv->nr = i; + priv->ports[i] = port_priv; + SET_NETDEV_DEV(netdev, dev); + + mac_addr = device_get_mac_address(dev, mac, ETH_ALEN); + if (!mac_addr) { + netdev_err(netdev, "MAC address invalid: %pM\n", mac); + return -EINVAL; + } + + ether_addr_copy(netdev->dev_addr, mac); + + netdev->irq = priv->spidev->irq; + INIT_WORK(&port_priv->tx_work, adin1110_tx_work); + INIT_WORK(&port_priv->rx_mode_work, adin1110_rx_mode_work); + skb_queue_head_init(&port_priv->txq); + + netif_carrier_off(netdev); - netdev = devm_alloc_etherdev(dev, sizeof(struct adin1110_priv)); - if (!netdev) + /* FIXME: This should be changed to 10BASET1L when introduced to PAL */ + netdev->if_port = IF_PORT_10BASET; + netdev->netdev_ops = &adin1110_netdev_ops; + netdev->ethtool_ops = &adin1110_ethtool_ops; + + switch (priv->cfg->id) { + case ADIN1110_MAC: + snprintf(port_priv->netdev->name, IFNAMSIZ, "%s-%u", priv->cfg->name, + priv->spidev->chip_select); + break; + case ADIN2111_MAC: + snprintf(port_priv->netdev->name, IFNAMSIZ, "%s-%u-p%d", priv->cfg->name, + priv->spidev->chip_select, i); + break; + default: + return -EINVAL; + } + + ret = devm_register_netdev(dev, netdev); + if (ret < 0) { + dev_err(dev, "failed to register network device\n"); + return ret; + } + + port_priv->phydev = get_phy_device(priv->mii_bus, i + 1, false); + if (!port_priv->phydev) { + netdev_err(netdev, "Could not find PHY with device address: %d.\n", i); + return -ENODEV; + } + + port_priv->phydev = phy_connect(netdev, phydev_name(port_priv->phydev), + adin1110_adjust_link, PHY_INTERFACE_MODE_MII); + if (IS_ERR(port_priv->phydev)) { + netdev_err(netdev, "Could not connect PHY with device address: %d.\n", i); + return PTR_ERR(port_priv->phydev); + } + + ret = devm_add_action_or_reset(dev, adin1110_disconnect_phy, port_priv->phydev); + if (ret < 0) + return ret; + } + + /* ADIN1110 INT_N pin will be used to signal the host */ + return devm_request_threaded_irq(dev, priv->spidev->irq, NULL, adin1110_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, dev_name(dev), priv); +} + +static int adin1110_probe(struct spi_device *spi) +{ + const struct spi_device_id *dev_id = spi_get_device_id(spi); + struct device *dev = &spi->dev; + struct adin1110_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(struct adin1110_priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - priv = netdev_priv(netdev); priv->spidev = spi; - priv->netdev = netdev; + priv->cfg = &adin1110_cfgs[dev_id->driver_data]; spi->bits_per_word = 8; - SET_NETDEV_DEV(netdev, dev); mutex_init(&priv->lock); spin_lock_init(&priv->state_lock); - INIT_WORK(&priv->tx_work, adin1110_tx_work); - INIT_WORK(&priv->rx_mode_work, adin1110_rx_mode_work); - /* use of CRC on control and data transactions is pin dependent */ priv->append_crc = device_property_read_bool(dev, "adi,spi-crc"); if (priv->append_crc) crc8_populate_msb(adin1110_crc_table, 0x7); - mac_addr = device_get_mac_address(dev, mac, ETH_ALEN); - if (!mac_addr) { - netdev_err(netdev, "MAC address invalid: %pM, %d\n", mac, ret); - return -EINVAL; - } - - ether_addr_copy(netdev->dev_addr, mac); - ret = adin1110_check_spi(priv); if (ret < 0) { - netdev_err(netdev, "SPI read failed: %d\n", ret); + dev_err(dev, "SPI read failed: %d\n", ret); return ret; } ret = adin1110_register_mdiobus(priv, dev); if (ret < 0) { - netdev_err(netdev, "Could not register MDIO bus %d\n", ret); - return ret; - } - - skb_queue_head_init(&priv->txq); - - netdev->irq = spi->irq; - - netif_carrier_off(priv->netdev); - - /* FIXME: This should be changed to 10BASET1L when introduced to PAL */ - netdev->if_port = IF_PORT_10BASET; - netdev->netdev_ops = &adin1110_netdev_ops; - netdev->ethtool_ops = &adin1110_ethtool_ops; - - ret = devm_register_netdev(dev, netdev); - if (ret) { - dev_err(dev, "failed to register network device\n"); + dev_err(dev, "Could not register MDIO bus %d\n", ret); return ret; } - /* there is only one PHY connected to our registered MDIO bus */ - priv->phydev = phy_find_first(priv->mii_bus); - if (!priv->phydev) - return -ENODEV; - - priv->phydev = phy_connect(netdev, phydev_name(priv->phydev), - adin1110_adjust_link, PHY_INTERFACE_MODE_MII); - if (IS_ERR(priv->phydev)) - return PTR_ERR(priv->phydev); - - return devm_add_action_or_reset(dev, adin1110_disconnect_phy, priv->phydev); + return adin1110_probe_netdevs(priv); } static const struct of_device_id adin1110_match_table[] = { { .compatible = "adi,adin1110" }, + { .compatible = "adi,adin2111" }, { } }; MODULE_DEVICE_TABLE(of, adin1110_match_table); +static const struct spi_device_id adin1110_spi_id[] = { + { .name = "adin1110", .driver_data = ADIN1110_MAC }, + { .name = "adin2111", .driver_data = ADIN2111_MAC }, + { } +}; + static struct spi_driver adin1110_driver = { .driver = { .name = "adin1110", .of_match_table = adin1110_match_table, }, .probe = adin1110_probe, + .id_table = adin1110_spi_id, }; module_spi_driver(adin1110_driver); From 2c81a28cce4f6f6d315783eed88b304b962154b9 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Thu, 28 Apr 2022 20:22:18 +0300 Subject: [PATCH 334/407] dt-bindings: net: adin2111: Add docs Add bindings for the ADIN2111 MAC-PHY. Signed-off-by: Alexandru Tachici --- .../devicetree/bindings/net/adi,adin1110.yaml | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/net/adi,adin1110.yaml b/Documentation/devicetree/bindings/net/adi,adin1110.yaml index 24c53e1dacef7e..0a31e2c8e8fb50 100644 --- a/Documentation/devicetree/bindings/net/adi,adin1110.yaml +++ b/Documentation/devicetree/bindings/net/adi,adin1110.yaml @@ -18,12 +18,21 @@ description: | an Ethernet PHY core with a MAC and all the associated analog circuitry, input and output clock buffering. + The ADIN2111 is a low power, low complexity, two-Ethernet ports + switch with integrated 10BASE-T1L PHYs and one serial peripheral + interface (SPI) port. The device is designed for industrial Ethernet + applications using low power constrained nodes and is compliant + with the IEEE 802.3cg-2019 Ethernet standard for long reach + 10 Mbps single pair Ethernet (SPE). + The device has a 4-wire SPI interface for communication between the MAC and host processor. properties: compatible: - const: adi,adin1110 + enum: + - adi,adin1110 + - adi,adin2111 '#address-cells': const: 1 @@ -42,17 +51,31 @@ properties: interrupts: maxItems: 1 - phy@0: +patternProperties: + "^phy@[0-1]$": description: | ADIN1100 PHY that is present on the same chip as the MAC. type: object properties: reg: - const: 0 - - compatible: - const: ethernet-phy-id0283.bc91 + items: + maximum: 1 + + allOf: + - if: + properties: + compatible: + contains: + const: adi,adin1110 + then: + properties: + compatible: + const: ethernet-phy-id0283.bc91 + else: + properties: + compatible: + const: ethernet-phy-id0283.bca1 required: - compatible From 4d60f7949ddbc621792ed81f582be82bb6ac7709 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 12 May 2022 11:21:12 +0200 Subject: [PATCH 335/407] iio: frequency: ad9528: jesd204-fsm ignore SYSREF rate issues in SC0 Ignore SYSREF rate errors in JESD204 SUBCLASS_0 since SYSREF is not needed. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/ad9528.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iio/frequency/ad9528.c b/drivers/iio/frequency/ad9528.c index cbe80e1b1ab9ca..5696cf191e354e 100644 --- a/drivers/iio/frequency/ad9528.c +++ b/drivers/iio/frequency/ad9528.c @@ -1316,7 +1316,8 @@ static int ad9528_jesd204_link_supported(struct jesd204_dev *jdev, dev_dbg(dev, "%s:%d link_num %u LMFC/LEMC %u/%lu gcd %u\n", __func__, __LINE__, lnk->link_id, st->jdev_lmfc_lemc_rate, rate, st->jdev_lmfc_lemc_gcd); - if (ret) + + if (ret && lnk->subclass != JESD204_SUBCLASS_0) return ret; return JESD204_STATE_CHANGE_DONE; From df88660ee30f638bbf3c2b3f043aad35925f6f52 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 12 May 2022 11:49:20 +0200 Subject: [PATCH 336/407] iio: frequency: adf4371: Support for RFAUX8 VCO output mux The RFAUX8 can behave like the RF8 output or directly provide the fundamental VCO frequency. This patch adds support for controlling this mux, using the out_altvoltage1_vco_output_enable attribute. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/adf4371.c | 77 ++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/drivers/iio/frequency/adf4371.c b/drivers/iio/frequency/adf4371.c index 7541ae68d16f10..b3051c95dbac9b 100644 --- a/drivers/iio/frequency/adf4371.c +++ b/drivers/iio/frequency/adf4371.c @@ -2,7 +2,7 @@ /* * Analog Devices ADF4371 SPI Wideband Synthesizer driver * - * Copyright 2019 Analog Devices Inc. + * Copyright 2019-2022 Analog Devices Inc. */ #include #include @@ -99,6 +99,10 @@ #define ADF4371_VCO_ALC_TOUT_MSK GENMASK(4, 0) #define ADF4371_VCO_ALC_TOUT(x) FIELD_PREP(ADF4371_VCO_ALC_TOUT_MSK, x) +/* ADF4371_REG72 */ +#define ADF4371_AUX_FREQ_SEL_MSK BIT(6) +#define ADF4371_AUX_FREQ_SEL(x) FIELD_PREP(ADF4371_AUX_FREQ_SEL_MSK, x) + /* ADF4371_REG73 */ #define ADF4371_ADC_CLK_DISABLE_MSK BIT(2) #define ADF4371_ADC_CLK_DISABLE(x) FIELD_PREP(ADF4371_ADC_CLK_DISABLE_MSK, x) @@ -129,6 +133,7 @@ enum { ADF4371_POWER_DOWN, ADF4371_CHANNEL_NAME, ADF4371_MUXOUT_ENABLE, + ADF4371_AUX_FREQ_VCO_ENABLE, }; enum { @@ -287,6 +292,7 @@ struct adf4371_state { bool muxout_1v8_en; bool spi_3wire_en; bool differential_ref_clk; + bool rf8aux_vco_en; u8 buf[10] ____cacheline_aligned; }; @@ -304,7 +310,8 @@ static unsigned long long adf4371_pll_fract_n_get_rate(struct adf4371_state *st, do_div(tmp, st->mod2); val += tmp + ADF4371_MODULUS1 / 2; - if (channel == ADF4371_CH_RF8 || channel == ADF4371_CH_RFAUX8) + if (channel == ADF4371_CH_RF8 || + (channel == ADF4371_CH_RFAUX8 && !st->rf8aux_vco_en)) ref_div_sel = st->rf_div_sel; else ref_div_sel = 0; @@ -356,8 +363,15 @@ static int adf4371_set_freq(struct adf4371_state *st, unsigned long long freq, int ret; switch (channel) { - case ADF4371_CH_RF8: case ADF4371_CH_RFAUX8: + if (st->rf8aux_vco_en) { + if (ADF4371_CHECK_RANGE(freq, VCO_FREQ)) + return -EINVAL; + + break; + } + fallthrough; + case ADF4371_CH_RF8: if (ADF4371_CHECK_RANGE(freq, OUT_RF8_FREQ)) return -EINVAL; @@ -623,6 +637,13 @@ static ssize_t adf4371_read(struct iio_dev *indio_dev, val = !(readval & BIT(bit)); break; + case ADF4371_AUX_FREQ_VCO_ENABLE: + ret = regmap_read(st->regmap, ADF4371_REG(0x72), &readval); + if (ret < 0) + break; + + val = !!(readval & ADF4371_AUX_FREQ_SEL_MSK); + break; case ADF4371_CHANNEL_NAME: return sprintf(buf, "%s\n", adf4371_ch_names[chan->channel]); case ADF4371_MUXOUT_ENABLE: @@ -643,7 +664,7 @@ static ssize_t adf4371_write(struct iio_dev *indio_dev, { struct adf4371_state *st = iio_priv(indio_dev); unsigned long long freq; - bool power_down, muxout_en; + bool power_down, muxout_en, enable; int ret; mutex_lock(&st->lock); @@ -668,13 +689,26 @@ static ssize_t adf4371_write(struct iio_dev *indio_dev, break; ret = regmap_update_bits(st->regmap, ADF4371_REG(0x20), - ADF4371_MUXOUT_EN_MSK, + ADF4371_AUX_FREQ_SEL_MSK, ADF4371_MUXOUT_EN(muxout_en)); if (ret < 0) break; st->muxout_en = muxout_en; break; + case ADF4371_AUX_FREQ_VCO_ENABLE: + ret = kstrtobool(buf, &enable); + if (ret) + break; + + ret = regmap_update_bits(st->regmap, ADF4371_REG(0x72), + ADF4371_AUX_FREQ_SEL_MSK, + ADF4371_AUX_FREQ_SEL(enable)); + if (ret < 0) + break; + + st->rf8aux_vco_en = enable; + break; default: ret = -EINVAL; break; @@ -756,6 +790,37 @@ static const struct iio_chan_spec_ext_info adf4371_ext_info[] = { .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PHASE), \ } +static const struct iio_chan_spec_ext_info adf4371_ext_info_aux[] = { + /* + * Ideally we use IIO_CHAN_INFO_FREQUENCY, but there are + * values > 2^32 in order to support the entire frequency range + * in Hz. Using scale is a bit ugly. + */ + _ADF4371_EXT_INFO("frequency", ADF4371_FREQ), + _ADF4371_EXT_INFO("powerdown", ADF4371_POWER_DOWN), + _ADF4371_EXT_INFO("vco_output_enable", ADF4371_AUX_FREQ_VCO_ENABLE), + _ADF4371_EXT_INFO("name", ADF4371_CHANNEL_NAME), + { + .name = "muxout_enable", + .read = adf4371_read, + .write = adf4371_write, + .private = ADF4371_MUXOUT_ENABLE, + .shared = IIO_SHARED_BY_ALL, + }, + IIO_ENUM("muxout_mode", IIO_SHARED_BY_ALL, &adf4371_muxout_mode_enum), + IIO_ENUM_AVAILABLE("muxout_mode", &adf4371_muxout_mode_enum), + { }, +}; + +#define ADF4371_AUX_CHANNEL(index) { \ + .type = IIO_ALTVOLTAGE, \ + .output = 1, \ + .channel = index, \ + .ext_info = adf4371_ext_info_aux, \ + .indexed = 1, \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PHASE), \ + } + static const struct iio_chan_spec adf4371_chan[] = { { .type = IIO_TEMP, @@ -764,7 +829,7 @@ static const struct iio_chan_spec adf4371_chan[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }, ADF4371_CHANNEL(ADF4371_CH_RF8), - ADF4371_CHANNEL(ADF4371_CH_RFAUX8), + ADF4371_AUX_CHANNEL(ADF4371_CH_RFAUX8), ADF4371_CHANNEL(ADF4371_CH_RF16), ADF4371_CHANNEL(ADF4371_CH_RF32), }; From feaf2a148ceeec2c0efd746c00fb3d9fed0dfcfe Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 12 May 2022 11:59:34 +0200 Subject: [PATCH 337/407] dts: xilinx/adi-ad9083-vna: Updates for board Rev.B This adds some changes found on the latest Rev.B board. Signed-off-by: Michael Hennerich --- .../arm64/boot/dts/xilinx/adi-ad9083-vna.dtsi | 91 +++++++++---------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/adi-ad9083-vna.dtsi b/arch/arm64/boot/dts/xilinx/adi-ad9083-vna.dtsi index fcdb4a082257e9..8e64679ff998b5 100644 --- a/arch/arm64/boot/dts/xilinx/adi-ad9083-vna.dtsi +++ b/arch/arm64/boot/dts/xilinx/adi-ad9083-vna.dtsi @@ -2,6 +2,8 @@ /* * dts file for AD9083-ADL5960 on Xilinx ZynqMP ZCU102 Rev 1.0 * + * board_revision: + * * Copyright (C) 2021 Analog Devices Inc. */ #include @@ -20,15 +22,6 @@ #define AD9083_NCO_FREQ (ADF9528_DIST_CLK / ADL5960_FOF) / { - clk_doubler: hmc561 { - #clock-cells = <0>; - compatible = "fixed-factor-clock"; - clock-div = <1>; - clock-mult = <2>; - clocks = <&adf5610>; - clock-output-names = "doubler"; - }; - fixed_clk: fixed-clock { #clock-cells = <0>; compatible = "fixed-clock"; @@ -59,16 +52,16 @@ label = "mux-rfin"; }; - clk_mux0: mux-doubler { + clk_mux0: mux-adf4371 { compatible = "adi,gen_mux"; - clocks = <&adf5610>, <&fixed_clk>, <&fixed_clk>, <&clk_doubler>; + clocks = <&adf4371 3>, <&adf4371 0>, <&adf4371 2>, <&fixed_clk>; #clock-cells = <0>; - clock-names = "bypass", "iso1", "iso2", "doubler"; + clock-names = "pll0-clk-rf32", "pll0-clk-rf8", "pll0-clk-rf16", "disabled"; clock-output-names = "clk-mux-out"; mux-controls = <&mux1>; - mux-state-names = "bypass", "iso1", "iso2", "doubler"; - label = "mux-doubler"; + mux-state-names = "rf32", "rf8", "rf16", "disabled"; + label = "mux-adf4371"; }; adl5960-sync@0 { @@ -83,8 +76,6 @@ label = "ADL5960x_SYNC"; }; }; - - }; &spi0 { @@ -124,7 +115,7 @@ adi,sysref-k-div = <256>; adi,sysref-nshot-mode = ; adi,sysref-request-trigger-mode = ; - adi,jesd204-max-sysref-frequency-hz = <400000>; + //adi,jesd204-max-sysref-frequency-hz = <400000>; /* PLL1 config */ adi,pll1-feedback-src-vcxo; @@ -319,17 +310,6 @@ &spi1 { status = "okay"; - admv8818-1@0{ - compatible = "adi,admv8818"; - reg = <0>; - spi-max-frequency = <1000000>; - clocks = <&adf5610>; /* Fixme */ - clock-names = "rf_in"; - clock-scales = <1 10>; - label = "admv8818-lo"; - adi,tolerance-percent = <3>; - }; - admv8818-2@1{ compatible = "adi,admv8818"; reg = <1>; @@ -341,20 +321,39 @@ adi,tolerance-percent = <3>; }; - adf5610: adf5610@2 { - compatible = "adi,adf5610"; + adf4371: adf4371@2 { + compatible = "adi,adf4371"; reg = <2>; spi-max-frequency = <1000000>; - #clock-cells = <0>; + #address-cells = <1>; + #clock-cells = <1>; + #size-cells = <0>; clocks = <&ad9528 2>; - clock-names = "xref"; + clock-names = "clkin"; clock-scales = <1 10>; - adi,power-up-div-out-frequency-hz = /bits/ 64 <3000000000>; - adi,charge-pump-down-gain-ua = /bits/ 16 <2540>; - adi,charge-pump-up-gain-ua = /bits/ 16 <2540>; - adi,charge-pump-offset-ua = /bits/ 16 <520>; - adi,charge-pump-offset-down-enable; - label = "adf5610"; + label = "adf4371"; + clock-output-names = "pll0-clk-rf8", "pll0-clk-rfaux8", + "pll0-clk-rf16", "pll0-clk-rf32"; + channel@0 { + reg = <0>; + adi,power-up-frequency = /bits/ 64 <1000000000>; + adi,output-enable; + }; + channel@1 { + reg = <1>; + adi,power-up-frequency = /bits/ 64 <1000000000>; + adi,output-enable; + }; + channel@2 { + reg = <2>; + adi,power-up-frequency = /bits/ 64 <8000000000>; + adi,output-enable; + }; + channel@3 { + reg = <3>; + adi,power-up-frequency = /bits/ 64 <16000000000>; + adi,output-enable; + }; }; }; @@ -364,7 +363,7 @@ reg = <0>; spi-max-frequency = <12500000>; /* Clocks */ - clocks = <&adf5610>, <&ad9528 4>; + clocks = <&adf4371 1>, <&ad9528 4>; clock-names = "lo_in", "offs_in"; lo_in-clock-scales = <1 10>; label = "adl5960-1"; @@ -375,7 +374,7 @@ reg = <1>; spi-max-frequency = <12500000>; /* Clocks */ - clocks = <&adf5610>, <&ad9528 5>; + clocks = <&adf4371 1>, <&ad9528 5>; clock-names = "lo_in", "offs_in"; lo_in-clock-scales = <1 10>; label = "adl5960-2"; @@ -386,7 +385,7 @@ reg = <2>; spi-max-frequency = <12500000>; /* Clocks */ - clocks = <&adf5610>, <&ad9528 6>; + clocks = <&adf4371 1>, <&ad9528 6>; clock-names = "lo_in", "offs_in"; lo_in-clock-scales = <1 10>; label = "adl5960-3"; @@ -397,7 +396,7 @@ reg = <3>; spi-max-frequency = <12500000>; /* Clocks */ - clocks = <&adf5610>, <&ad9528 7>; + clocks = <&adf4371 1>, <&ad9528 7>; clock-names = "lo_in", "offs_in"; lo_in-clock-scales = <1 10>; label = "adl5960-4"; @@ -410,7 +409,7 @@ reg = <0>; spi-max-frequency = <12500000>; /* Clocks */ - clocks = <&adf5610>, <&ad9528 8>; + clocks = <&adf4371 1>, <&ad9528 8>; clock-names = "lo_in", "offs_in"; lo_in-clock-scales = <1 10>; label = "adl5960-5"; @@ -421,7 +420,7 @@ reg = <1>; spi-max-frequency = <12500000>; /* Clocks */ - clocks = <&adf5610>, <&ad9528 9>; + clocks = <&adf4371 1>, <&ad9528 9>; clock-names = "lo_in", "offs_in"; lo_in-clock-scales = <1 10>; label = "adl5960-6"; @@ -431,7 +430,7 @@ reg = <2>; spi-max-frequency = <12500000>; /* Clocks */ - clocks = <&adf5610>, <&ad9528 10>; + clocks = <&adf4371 1>, <&ad9528 10>; clock-names = "lo_in", "offs_in"; lo_in-clock-scales = <1 10>; label = "adl5960-7"; @@ -442,7 +441,7 @@ reg = <3>; spi-max-frequency = <12500000>; /* Clocks */ - clocks = <&adf5610>, <&ad9528 11>; + clocks = <&adf4371 1>, <&ad9528 11>; clock-names = "lo_in", "offs_in"; lo_in-clock-scales = <1 10>; label = "adl5960-8"; From 828b7ea6a85d6ac91a7b8e399f4b3e0021161699 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Thu, 12 May 2022 17:16:22 +0300 Subject: [PATCH 338/407] net: ethernet: adi: adin1110: Fix MAC address masking The ADIN1110/2111 chips can filter up to 16 MAC addresses at once, but only the first two MAC address slots can be masked. For this reason the multicast address has been moved to the first slot. Fixes: b5c34085eb4d ("net: ethernet: adi: adin1110: Add adin2111 support") Signed-off-by: Alexandru Tachici --- drivers/net/ethernet/adi/adin1110.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index f38e1c09c182cd..fd52f5dceb269f 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -122,9 +122,9 @@ #define ADIN_MAC_MAX_PORTS 2 -#define ADIN_MAC_ADDR_SLOT 0 -#define ADIN_MAC_BROADCAST_ADDR_SLOT 1 -#define ADIN_MAC_MULTICAST_ADDR_SLOT 2 +#define ADIN_MAC_MULTICAST_ADDR_SLOT 0 +#define ADIN_MAC_ADDR_SLOT 1 +#define ADIN_MAC_BROADCAST_ADDR_SLOT 2 DECLARE_CRC8_TABLE(adin1110_crc_table); @@ -633,13 +633,18 @@ static int adin1110_write_mac_address(struct adin1110_port_priv *port_priv, int if (ret < 0) return ret; - val = get_unaligned_be16(&mask[0]); - ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_UPR + offset, val); - if (ret < 0) - return ret; + /* only the first two MAC address slots support masking */ + if (mac_nr < ADIN_MAC_BROADCAST_ADDR_SLOT) { + val = get_unaligned_be16(&mask[0]); + ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_UPR + offset, val); + if (ret < 0) + return ret; - val = get_unaligned_be32(&mask[2]); - return adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_LWR + offset, val); + val = get_unaligned_be32(&mask[2]); + return adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_LWR + offset, val); + } + + return 0; } static int adin1110_clear_mac_address(struct adin1110_port_priv *port_priv, int mac_nr) From af49aacfcabcc0700873ffc7c2f4e2c75e6ae8b9 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Thu, 12 May 2022 17:18:39 +0300 Subject: [PATCH 339/407] net: ethernet: adi: adin1110: Fix forwarding Multicast and broadcast MAC addresses need to be forwarded by the MAC to both the SPI host and the other port. Fixes: b5c34085eb4d ("net: ethernet: adi: adin1110: Add adin2111 support") Signed-off-by: Alexandru Tachici --- drivers/net/ethernet/adi/adin1110.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index fd52f5dceb269f..890a0a9a2d3e9c 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -72,6 +72,7 @@ #define ADIN2111_MAC_ADDR_APPLY2PORT2 BIT(31) #define ADIN1110_MAC_ADDR_APPLY2PORT BIT(30) #define ADIN1110_MAC_ADDR_HOST_PRI BIT(19) +#define ADIN2111_MAC_ADDR_TO_OTHER_PORT BIT(17) #define ADIN1110_MAC_ADDR_TO_HOST BIT(16) #define ADIN1110_MAC_ADDR GENMASK(15, 0) @@ -618,9 +619,14 @@ static int adin1110_write_mac_address(struct adin1110_port_priv *port_priv, int u32 val; port_rules = ADIN1110_MAC_ADDR_APPLY2PORT; - if (priv->cfg->id == ADIN2111_MAC) + if (priv->cfg->id == ADIN2111_MAC) { port_rules |= ADIN2111_MAC_ADDR_APPLY2PORT2; + /* Broadcast and multicast should also be forwarded to the other port */ + if (mac_nr != ADIN_MAC_ADDR_SLOT) + port_rules |= ADIN2111_MAC_ADDR_TO_OTHER_PORT; + } + /* tell MAC to forward this DA to host */ val = port_rules | ADIN1110_MAC_ADDR_TO_HOST; val |= get_unaligned_be16(&addr[0]); From 24651e0a6cf822b4e4277c98b3cf2f242f6a9ba3 Mon Sep 17 00:00:00 2001 From: Sergiu Arpadi Date: Mon, 16 May 2022 16:25:56 +0300 Subject: [PATCH 340/407] arch: arm64: dts: zcu102-cn0506: add sysid support Device trees for zcu102-cn0506-mii/rmii/rgmii projects were missing sysid node. Signed-off-by: Sergiu Arpadi --- .../dts/xilinx/zynqmp-zcu102-rev10-cn0506-mii.dts | 15 +++++++++++++++ .../xilinx/zynqmp-zcu102-rev10-cn0506-rgmii.dts | 15 +++++++++++++++ .../xilinx/zynqmp-zcu102-rev10-cn0506-rmii.dts | 15 +++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-mii.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-mii.dts index 5f2aefbfdf439c..17200673b42d3b 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-mii.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-mii.dts @@ -10,3 +10,18 @@ */ #include "zynqmp-zcu102-rev1.0.dts" #include "adi-cn0506-mii.dtsi" + +/ { + fpga_axi: fpga-axi@0 { + interrupt-parent = <&gic>; + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges = <0 0 0 0xffffffff>; + + axi_sysid_0: axi-sysid-0@85000000 { + compatible = "adi,axi-sysid-1.00.a"; + reg = <0x85000000 0x2000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-rgmii.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-rgmii.dts index 16241439f2fc7a..9b0b4abf7d9a60 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-rgmii.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-rgmii.dts @@ -10,3 +10,18 @@ */ #include "zynqmp-zcu102-rev1.0.dts" #include "adi-cn0506-rgmii.dtsi" + +/ { + fpga_axi: fpga-axi@0 { + interrupt-parent = <&gic>; + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges = <0 0 0 0xffffffff>; + + axi_sysid_0: axi-sysid-0@85000000 { + compatible = "adi,axi-sysid-1.00.a"; + reg = <0x85000000 0x2000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-rmii.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-rmii.dts index af247ba4b86e9f..102ab6a122bee4 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-rmii.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-cn0506-rmii.dts @@ -10,3 +10,18 @@ */ #include "zynqmp-zcu102-rev1.0.dts" #include "adi-cn0506-rmii.dtsi" + +/ { + fpga_axi: fpga-axi@0 { + interrupt-parent = <&gic>; + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges = <0 0 0 0xffffffff>; + + axi_sysid_0: axi-sysid-0@85000000 { + compatible = "adi,axi-sysid-1.00.a"; + reg = <0x85000000 0x2000>; + }; + }; +}; From 45bc996dfec151a50dbfced53b4b0491017c052b Mon Sep 17 00:00:00 2001 From: Sean Smith Date: Wed, 18 May 2022 13:59:54 -0700 Subject: [PATCH 341/407] arch: arm: dts: zynq-zed-otg.dts Add fpga-axi dt node This change adds an fpga-axi node to the root device tree for product evaluation. This will allow for multiple small overlays to be applied to the device tree at run-time. Signed-off-by: Sean Smith --- arch/arm/boot/dts/zynq-zed-otg.dts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/zynq-zed-otg.dts b/arch/arm/boot/dts/zynq-zed-otg.dts index edc6cf7f67939b..8b443070826393 100644 --- a/arch/arm/boot/dts/zynq-zed-otg.dts +++ b/arch/arm/boot/dts/zynq-zed-otg.dts @@ -14,6 +14,15 @@ #include "zynq-zed.dtsi" +/{ + fpga_axi: fpga-axi@0 { + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + }; +}; + &usb0 { dr_mode = "otg"; }; From c7f46515d8ce22979506d443a14f034ef08ea723 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Wed, 18 May 2022 19:43:54 +0300 Subject: [PATCH 342/407] net: ethernet: adi: adin1110: Add unicast ability flag ndo_set_rx_mode() is implemented, we can have this flag set in netdev->priv_flags. Signed-off-by: Alexandru Tachici --- drivers/net/ethernet/adi/adin1110.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index 890a0a9a2d3e9c..7578aa6b2e81c7 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -1069,6 +1069,7 @@ static int adin1110_probe_netdevs(struct adin1110_priv *priv) netdev->if_port = IF_PORT_10BASET; netdev->netdev_ops = &adin1110_netdev_ops; netdev->ethtool_ops = &adin1110_ethtool_ops; + netdev->priv_flags |= IFF_UNICAST_FLT; switch (priv->cfg->id) { case ADIN1110_MAC: From a2bee61a48506c92c60e0e80552cfa7ec8ed2c0f Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Tue, 24 May 2022 14:11:25 +0300 Subject: [PATCH 343/407] net: adi: adin1110: Set frames as forwarded At probe, we program ADIN2111 to forward all frames received on a port, that do not match the host address to the other port. Multicast and broadcast frames are sent both on the SPI and the other port. Those frames need to be marked as forwarded in order to avoid duplicate frames that can be created by a user defined bridge. Fixes: b5c34085eb4d ("net: ethernet: adi: adin1110: Add adin2111 support") Signed-off-by: Alexandru Tachici --- drivers/net/ethernet/adi/adin1110.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index 7578aa6b2e81c7..dfe2fbca9047f3 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -355,6 +355,10 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) return ret; } + /* Already forwarded to the other port if it did not match any MAC Addresses. */ + if (priv->cfg->id == ADIN2111_MAC) + rxb->offload_fwd_mark = 1; + skb_put(rxb, frame_size_no_fcs); skb_copy_to_linear_data(rxb, &priv->data[header_len + ADIN1110_FRAME_HEADER_LEN], frame_size_no_fcs); From 27b6af8ef481cf606abb9d6a06223908f6ca1867 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Mon, 23 May 2022 10:47:31 +0300 Subject: [PATCH 344/407] net: adi: adin1110: Fix multicast filter Ethernet frames with a value of 1 in the least-significant bit of the first octet of the destination MAC address are treated as multicast frames. Fixes: 757a6117f7ff ("net: adi: adin1110: Add initial support") Signed-off-by: Alexandru Tachici --- drivers/net/ethernet/adi/adin1110.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index dfe2fbca9047f3..64c75aad369f1b 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -685,8 +685,8 @@ static int adin1110_multicast_filter(struct adin1110_port_priv *port_priv, int m u8 mac[ETH_ALEN] = {0}; if (accept_multicast) { - mask[0] = BIT(1); - mac[0] = BIT(1); + mask[0] = BIT(0); + mac[0] = BIT(0); return adin1110_write_mac_address(port_priv, mac_nr, mac, mask); } From eb61f82bcc8bb814b114ef5f23ed4c8bb37107b0 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 24 May 2022 10:38:31 +0300 Subject: [PATCH 345/407] arch: arm64: xmicrowave.dts: add labels Add labels for up/down converters to ease the interaction/distinguish of the devices having the same compatible type when using them with libiio/iio-osc. Signed-off-by: Antoniu Miclaus --- ...9-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-xmicrowave.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-xmicrowave.dts b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-xmicrowave.dts index 0a78716c4180f6..3a37fb91df58de 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-xmicrowave.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-xmicrowave.dts @@ -51,6 +51,7 @@ &axi_spi_1 { admv1013_a@0 { compatible = "adi,admv1013"; + label = "admv1013_a"; reg = <0>; spi-max-frequency = <5000000>; clocks = <&lo_adf5356>; @@ -65,6 +66,7 @@ admv1013_b@1 { compatible = "adi,admv1013"; + label = "admv1013_b"; reg = <1>; spi-max-frequency = <5000000>; clocks = <&lo_adf5356>; @@ -79,6 +81,7 @@ admv1014_a@2 { compatible = "adi,admv1014"; + label = "admv1014_a"; reg = <2>; spi-max-frequency = <5000000>; clocks = <&lo_adf5356>; @@ -94,6 +97,7 @@ admv1014_b@3 { compatible = "adi,admv1014"; + label = "admv1014_b"; reg = <3>; spi-max-frequency = <5000000>; clocks = <&lo_adf5356>; From 2195c1fbbd4b6afc7dddaa2a873fda7ce0f1a0cf Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 24 May 2022 10:43:26 +0300 Subject: [PATCH 346/407] arch: arm64: xmicrowave.dts: enable detector Similar to admv1013, enable by default the detector for admv1014 devices. Signed-off-by: Antoniu Miclaus --- ...009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-xmicrowave.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-xmicrowave.dts b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-xmicrowave.dts index 3a37fb91df58de..c43892c387bafa 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-xmicrowave.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-revb-adrv2crr-fmc-revb-jesd204-fsm-xmicrowave.dts @@ -93,6 +93,7 @@ adi,det-prog = <4>; adi,parity-en; adi,bb-amp-gain-ctrl = <0>; + adi,det-en; }; admv1014_b@3 { @@ -109,6 +110,7 @@ adi,det-prog = <4>; adi,parity-en; adi,bb-amp-gain-ctrl = <0>; + adi,det-en; }; lo_adf5356: adf5356@4 { From 24b8d41d5ffaa7a643db67faa04335b18313a9fc Mon Sep 17 00:00:00 2001 From: "Liviu.Iacob" Date: Wed, 25 May 2022 13:56:43 +0100 Subject: [PATCH 347/407] arch: arm: dts: add socfpga_arria10_socdk_adrv9002 dts Add devicetree support for adrv9002 with a10soc carrier. Signed-off-by: Liviu.Iacob --- .../dts/socfpga_arria10_socdk_adrv9002.dts | 226 ++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002.dts diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002.dts new file mode 100644 index 00000000000000..31ad5892b9448a --- /dev/null +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002.dts @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices ADRV9002 + * + * hdl_project: + * board_revision: <> + * + * Copyright (C) 2022 Analog Devices Inc. + */ +/dts-v1/; +#include "socfpga_arria10_socdk.dtsi" +#include + +&mmc { + status = "okay"; + num-slots = <1>; + cap-sd-highspeed; + broken-cd; + bus-width = <4>; + altr,dw-mshc-ciu-div = <3>; + altr,dw-mshc-sdr-timing = <0 3>; +}; + +/ { + clocks { + dma_clk: dma_clk { + #clock-cells = <0x0>; + compatible = "fixed-clock"; + clock-frequency = <250000000>; + clock-output-names = "dma_clk"; + }; + }; + + soc { + sys_hps_bridges: bridge@ff200000 { + compatible = "simple-bus"; + reg = <0xff200000 0x00200000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00000000 0xff200000 0x00200000>; + + sys_spi: spi@40 { + compatible = "altr,spi-1.0"; + reg = <0x00000040 0x00000020>; + interrupt-parent = <&intc>; + interrupts = <0 26 4>; + #address-cells = <0x1>; + #size-cells = <0x0>; + }; + + adrv9001_gpio: gpio@60000 { + compatible = "altr,pio-1.0"; + reg = <0x00060000 0x00000010>; + interrupt-parent = <&intc>; + interrupts = <0 33 4>; + altr,gpio-bank-width = <19>; + altr,interrupt-type = <4>; + altr,interrupt_type = <4>; + level_trigger = <1>; + resetvalue = <0>; + #gpio-cells = <2>; + gpio-controller; + }; + + rx1_dma: dma@40000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x00040000 0x800>; + #dma-cells = <1>; + interrupt-parent = <&intc>; + interrupts = <0 21 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&dma_clk>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <64>; + adi,source-bus-type = <2>; + adi,destination-bus-width = <64>; + adi,destination-bus-type = <0>; + }; + }; + }; + + rx2_dma: dma@41000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x00041000 0x800>; + #dma-cells = <1>; + interrupt-parent = <&intc>; + interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&dma_clk>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <64>; + adi,source-bus-type = <2>; + adi,destination-bus-width = <64>; + adi,destination-bus-type = <0>; + }; + }; + }; + + tx1_dma: dma@44000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x00044000 0x00000800>; + #dma-cells = <1>; + interrupt-parent = <&intc>; + interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&dma_clk>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <64>; + adi,source-bus-type = <0>; + adi,destination-bus-width = <64>; + adi,destination-bus-type = <2>; + }; + }; + }; + + tx2_dma: dma@45000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x00045000 0x00000800>; + #dma-cells = <1>; + interrupt-parent = <&intc>; + interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&dma_clk>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <64>; + adi,source-bus-type = <0>; + adi,destination-bus-width = <64>; + adi,destination-bus-type = <2>; + }; + }; + }; + + axi_adrv9002_core_rx1: axi-adrv9002-rx1-lpc@20000 { + compatible = "adi,axi-adrv9002-rx-1.0"; + reg = <0x00020000 0x6000>; + clocks = <&adc0_adrv9002 0>; + dmas = <&rx1_dma 0>; + dma-names = "rx"; + spibus-connected = <&adc0_adrv9002>; + }; + + axi_adrv9002_core_tx1: axi-adrv9002-tx1-lpc@2A000 { + compatible = "adi,axi-adrv9002-tx-1.0"; + reg = <0x0002A000 0x2000>; + clocks = <&adc0_adrv9002 1>; + clock-names = "sampl_clk"; + dmas = <&tx1_dma 0>; + dma-names = "tx"; + adi,axi-dds-default-scale = <0x800>; + adi,axi-dds-default-frequency = <2000000>; + }; + + axi_adrv9002_core_tdd1: axi-adrv9002-core-tdd1-lpc@2C800 { + compatible = "adi,axi-tdd-1.00"; + reg = <0x0002C800 0x400>; + clocks = <&dma_clk>, <&adc0_adrv9002 2>; + clock-names = "s_axi_aclk", "intf_clk"; + label = "axi-core-tdd-1"; + }; + + axi_adrv9002_core_rx2: axi-adrv9002-rx2-lpc@29000 { + compatible = "adi,axi-adrv9002-rx2-1.0"; + reg = <0x00029000 0x1000>; + clocks = <&adc0_adrv9002 3>; + clock-names = "sampl_clk"; + dmas = <&rx2_dma 0>; + dma-names = "rx"; + }; + + axi_adrv9002_core_tx2: axi-adrv9002-tx2-lpc@2C000 { + compatible = "adi,axi-adrv9002-tx-1.0"; + reg = <0x0002C000 0x2000>; + clocks = <&adc0_adrv9002 4>; + clock-names = "sampl_clk"; + dmas = <&tx2_dma 0>; + dma-names = "tx"; + adi,axi-dds-default-scale = <0x800>; + adi,axi-dds-default-frequency = <2000000>; + }; + + axi_adrv9002_core_tdd2: axi-adrv9002-core-tdd2-lpc@2CC00 { + compatible = "adi,axi-tdd-1.00"; + reg = <0x0002CC00 0x400>; + clocks = <&dma_clk>, <&adc0_adrv9002 5>; + clock-names = "s_axi_aclk", "intf_clk"; + label = "axi-core-tdd-2"; + }; + }; + }; +}; + +#define fmc_spi sys_spi + +#include "adi-adrv9002.dtsi" + +&adc0_adrv9002 { + reset-gpios = <&adrv9001_gpio 14 GPIO_ACTIVE_LOW>; +}; + +&rx0 { + orx-gpios = <&adrv9001_gpio 0 GPIO_ACTIVE_HIGH>; /* dgpio0 */ +}; + +&rx1 { + orx-gpios = <&adrv9001_gpio 1 GPIO_ACTIVE_HIGH>; /* dgpio1 */ +}; From fa793cb71fe5bd7ab07147ea83ab9a9def9664a4 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Fri, 27 May 2022 16:43:20 +0300 Subject: [PATCH 348/407] iio: frequency: adf4371: Fix Lock Detect bit reading Lock Detect bit readback can be performed only when MUXOUT is set to "digital lock detect". Fixes: 5a088e68dcd0 ("iio: frequency: adf4371: Add support for ADF4371 PLL") Signed-off-by: Dragos Bogdan --- drivers/iio/frequency/adf4371.c | 85 +++++++++++++++++---------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/drivers/iio/frequency/adf4371.c b/drivers/iio/frequency/adf4371.c index b3051c95dbac9b..dc6b93e1bcf277 100644 --- a/drivers/iio/frequency/adf4371.c +++ b/drivers/iio/frequency/adf4371.c @@ -473,6 +473,40 @@ static int adf4371_channel_power_down(struct adf4371_state *st, return regmap_write(st->regmap, reg, readval); } +static int adf4371_get_muxout_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct adf4371_state *st = iio_priv(indio_dev); + unsigned int readval; + int ret; + + ret = regmap_read(st->regmap, ADF4371_REG(0x20), &readval); + if (ret < 0) + return ret; + + readval &= ADF4371_MUXOUT_MSK; + + return (readval >> 4); +} + +static int adf4371_set_muxout_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct adf4371_state *st = iio_priv(indio_dev); + + return regmap_update_bits(st->regmap, ADF4371_REG(0x20), + ADF4371_MUXOUT_MSK, + ADF4371_MUXOUT(mode)); +} + +static const struct iio_enum adf4371_muxout_mode_enum = { + .items = adf4371_muxout_modes, + .num_items = ARRAY_SIZE(adf4371_muxout_modes), + .get = adf4371_get_muxout_mode, + .set = adf4371_set_muxout_mode, +}; + static int adf4371_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, @@ -613,18 +647,21 @@ static ssize_t adf4371_read(struct iio_dev *indio_dev, struct adf4371_state *st = iio_priv(indio_dev); unsigned long long val = 0; unsigned int readval, reg, bit; - int ret; + int muxout_mode, ret; switch ((u32)private) { case ADF4371_FREQ: val = adf4371_pll_fract_n_get_rate(st, chan->channel); - ret = regmap_read(st->regmap, ADF4371_REG(0x7C), &readval); - if (ret < 0) - break; + muxout_mode = adf4371_get_muxout_mode(indio_dev, chan); + if (st->spi_3wire_en && (muxout_mode == ADF4371_DIG_LOCK)) { + ret = regmap_read(st->regmap, ADF4371_REG(0x7C), &readval); + if (ret < 0) + break; - if (readval == 0x00) { - dev_dbg(&st->spi->dev, "PLL un-locked\n"); - ret = -EBUSY; + if (readval == 0x00) { + dev_dbg(&st->spi->dev, "PLL un-locked\n"); + ret = -EBUSY; + } } break; case ADF4371_POWER_DOWN: @@ -718,40 +755,6 @@ static ssize_t adf4371_write(struct iio_dev *indio_dev, return ret ? ret : len; } -static int adf4371_get_muxout_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct adf4371_state *st = iio_priv(indio_dev); - unsigned int readval; - int ret; - - ret = regmap_read(st->regmap, ADF4371_REG(0x20), &readval); - if (ret < 0) - return ret; - - readval &= ADF4371_MUXOUT_MSK; - - return (readval >> 4); -} - -static int adf4371_set_muxout_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - unsigned int mode) -{ - struct adf4371_state *st = iio_priv(indio_dev); - - return regmap_update_bits(st->regmap, ADF4371_REG(0x20), - ADF4371_MUXOUT_MSK, - ADF4371_MUXOUT(mode)); -} - -static const struct iio_enum adf4371_muxout_mode_enum = { - .items = adf4371_muxout_modes, - .num_items = ARRAY_SIZE(adf4371_muxout_modes), - .get = adf4371_get_muxout_mode, - .set = adf4371_set_muxout_mode, -}; - #define _ADF4371_EXT_INFO(_name, _ident) { \ .name = _name, \ .read = adf4371_read, \ From 7526063a7c44bae60054da707754a48df1ce75f3 Mon Sep 17 00:00:00 2001 From: Raluca Chis Date: Fri, 3 Jun 2022 09:52:08 +0300 Subject: [PATCH 349/407] CI:add z option to tar archive Add z option to archives to set the compression method to gzip. Signed-off-by: Raluca Chis --- ci/travis/prepare_artifacts.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/travis/prepare_artifacts.sh b/ci/travis/prepare_artifacts.sh index 1445ca1b8fbce7..3d5f8555588fd7 100644 --- a/ci/travis/prepare_artifacts.sh +++ b/ci/travis/prepare_artifacts.sh @@ -25,7 +25,7 @@ artifacts_structure() { cd ../ cp -r ./adi_"${typeBCM[$index]}"_defconfig/* ./${timestamp} done - tar -C ${SOURCE_DIRECTORY}/${timestamp}/modules -cvf ${SOURCE_DIRECTORY}/${timestamp}/rpi_modules.tar.gz . + tar -C ${SOURCE_DIRECTORY}/${timestamp}/modules -czvf ${SOURCE_DIRECTORY}/${timestamp}/rpi_modules.tar.gz . rm -r ${SOURCE_DIRECTORY}/${timestamp}/modules } @@ -45,7 +45,7 @@ artifacts_swdownloads() { md5_modules=($(md5sum rpi_modules.tar.gz| cut -d ' ' -f 1)) rm rpi_modules.tar.gz rpi_git_properties.txt - tar -C ${PWD} -cvf rpi_latest_boot.tar.gz * + tar -C ${PWD} -czvf rpi_latest_boot.tar.gz * md5_boot=($(md5sum rpi_latest_boot.tar.gz| cut -d ' ' -f 1)) scp -2 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o HostKeyAlgorithms=+ssh-dss \ -i ${KEY_FILE} -r rpi_latest_boot.tar.gz ${DEST_SERVER} From f67948a9fa3ad818bb4690dbc5182621ec9bba64 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 6 Jun 2022 16:25:22 +0300 Subject: [PATCH 350/407] drivers: iio: ad9467: fix ad9649 scale handling For AD9649 device, the register 0x18 (VREF) is not available according to the datasheet, and the VREF can be configured hardware-wise using either internal 1.0V reference or externally applied 1.0V. This patch fixes scale handling, by skipping the register operations and computing VLSB based only on the available `scale_table`. Fixes: f132a28 ("iio/adc/ad9467.c: Add support for AD9649") Signed-off-by: Antoniu Miclaus --- drivers/iio/adc/ad9467.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index 85cd6d60cda8b6..12314a7907b94c 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -983,8 +983,6 @@ static int ad9467_get_scale(struct axiadc_converter *conv, int *val, int *val2) unsigned vref_val, vref_mask; unsigned int i; - vref_val = ad9467_spi_read(conv->spi, AN877_ADC_REG_VREF); - switch (conv->chip_info->id) { case CHIPID_AD9467: vref_mask = AD9467_REG_VREF_MASK; @@ -1003,11 +1001,16 @@ static int ad9467_get_scale(struct axiadc_converter *conv, int *val, int *val2) case CHIPID_AD9652: vref_mask = AD9652_REG_VREF_MASK; break; + case CHIPID_AD9649: + i = 0; + goto skip_reg_read; default: vref_mask = 0xFFFF; break; } + vref_val = ad9467_spi_read(conv->spi, AN877_ADC_REG_VREF); + vref_val &= vref_mask; for (i = 0; i < conv->chip_info->num_scales; i++) { @@ -1015,6 +1018,7 @@ static int ad9467_get_scale(struct axiadc_converter *conv, int *val, int *val2) break; } +skip_reg_read: ad9467_scale(conv, i, val, val2); return IIO_VAL_INT_PLUS_MICRO; @@ -1025,6 +1029,13 @@ static int ad9467_set_scale(struct axiadc_converter *conv, int val, int val2) unsigned int scale_val[2]; unsigned int i; + switch (conv->chip_info->id) { + case CHIPID_AD9649: + return -EINVAL; + default: + break; + } + if (val != 0) return -EINVAL; From 9da9d86350baddea610b07c83c6078145ce61a99 Mon Sep 17 00:00:00 2001 From: Raluca Chis Date: Wed, 8 Jun 2022 15:55:43 +0300 Subject: [PATCH 351/407] CI:set 'exit 1' if timestamp folder is not found This is necessary to avoid uploading the wrong data to SWDownloads. Signed-off-by: Raluca Chis --- ci/travis/prepare_artifacts.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/travis/prepare_artifacts.sh b/ci/travis/prepare_artifacts.sh index 3d5f8555588fd7..160718a3636214 100644 --- a/ci/travis/prepare_artifacts.sh +++ b/ci/travis/prepare_artifacts.sh @@ -38,7 +38,7 @@ artifacts_artifactory() { #archive artifacts and upload to SWDownloads artifacts_swdownloads() { - cd ${SOURCE_DIRECTORY}/${timestamp} + cd ${SOURCE_DIRECTORY}/${timestamp} || exit 1 chmod 600 ${KEY_FILE} scp -2 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o HostKeyAlgorithms=+ssh-dss \ -i ${KEY_FILE} -r *.tar.gz ${DEST_SERVER} From 19dc26be0eba98c05adc1528b60cfa21de432f42 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 9 Jun 2022 13:27:57 +0300 Subject: [PATCH 352/407] drivers: iio: ad9467: fix ad9625 scale handling For AD9625 device, the register 0x18 (VREF) is not available according to the datasheet, and the VREF is 1.0V Vp-p internal reference. This patch fixes scale handling, by skipping the register operations and computing VLSB based only on the available ad9625 `scale_table`. Fixes: 98762a6 ("cf_axi_adc_core: Add support for AD9625 and AD9434") Signed-off-by: Antoniu Miclaus --- drivers/iio/adc/ad9467.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index 12314a7907b94c..38f5be0b97a649 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -516,6 +516,10 @@ static const int ad9467_scale_table[][2] = { {2300, 8}, {2400, 9}, {2500, 10}, }; +static const int ad9625_scale_table[][2] = { + {1000, 0}, +}; + static const int ad9643_scale_table[][2] = { {2087, 0x0F}, {2065, 0x0E}, {2042, 0x0D}, {2020, 0x0C}, {1997, 0x0B}, {1975, 0x0A}, {1952, 0x09}, {1930, 0x08}, {1907, 0x07}, {1885, 0x06}, @@ -782,8 +786,8 @@ static const struct axiadc_chip_info ad9467_chip_tbl[] = { .name = "AD9625", .id = CHIPID_AD9625, .max_rate = 2500000000UL, - .scale_table = ad9643_scale_table, - .num_scales = ARRAY_SIZE(ad9643_scale_table), + .scale_table = ad9625_scale_table, + .num_scales = ARRAY_SIZE(ad9625_scale_table), .max_testmode = AN877_ADC_TESTMODE_RAMP, .num_channels = 1, .channel[0] = AIM_CHAN_NOCALIB(0, 0, 12, 'S', 0), @@ -992,8 +996,6 @@ static int ad9467_get_scale(struct axiadc_converter *conv, int *val, int *val2) break; case CHIPID_AD9250: case CHIPID_AD9683: - case CHIPID_AD9625: - vref_mask = AD9250_REG_VREF_MASK; break; case CHIPID_AD9265: vref_mask = AD9265_REG_VREF_MASK; @@ -1002,6 +1004,7 @@ static int ad9467_get_scale(struct axiadc_converter *conv, int *val, int *val2) vref_mask = AD9652_REG_VREF_MASK; break; case CHIPID_AD9649: + case CHIPID_AD9625: i = 0; goto skip_reg_read; default: @@ -1030,6 +1033,7 @@ static int ad9467_set_scale(struct axiadc_converter *conv, int val, int val2) unsigned int i; switch (conv->chip_info->id) { + case CHIPID_AD9625: case CHIPID_AD9649: return -EINVAL; default: From 63218e37c99ed75f8639dd3f92aac05903211043 Mon Sep 17 00:00:00 2001 From: "stefan.raus" Date: Fri, 10 Jun 2022 14:38:50 +0100 Subject: [PATCH 353/407] zynqmp-zcu102-rev10-ad9082: fix HDL project tag Fir HDL projects tag for all ad9082+zcu102 projects. Signed-off-by: stefan.raus --- ...cu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts | 2 +- .../zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts | 2 +- .../zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-sc1.dts | 2 +- .../zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23.dts | 2 +- arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-m4-l8.dts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts index 780f4caffd0ffe..81fd035596d7b3 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual-multi-top.dts @@ -4,7 +4,7 @@ * https://wiki.analog.com/resources/eval/user-guides/quadmxfe/quick-start * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 * - * hdl_project: + * hdl_project: * board_revision: <> * * Copyright (C) 2021 Analog Devices Inc. diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts index ce52800338ee2c..8a813bcfe2b514 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-dual.dts @@ -4,7 +4,7 @@ * https://wiki.analog.com/resources/eval/user-guides/quadmxfe/quick-start * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 * - * hdl_project: + * hdl_project: * board_revision: <> * * Copyright (C) 2021 Analog Devices Inc. diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-sc1.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-sc1.dts index f6df26372141d5..497dc09bf0d2e0 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-sc1.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23-sc1.dts @@ -4,7 +4,7 @@ * https://wiki.analog.com/resources/eval/user-guides/quadmxfe/quick-start * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 * - * hdl_project: + * hdl_project: * board_revision: <> * * Copyright (C) 2022 Analog Devices Inc. diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23.dts index b6ca0e8e9b4bcd..ebcd15e1ee5346 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-204c-txmode22-rxmode23.dts @@ -4,7 +4,7 @@ * https://wiki.analog.com/resources/eval/user-guides/quadmxfe/quick-start * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 * - * hdl_project: + * hdl_project: * board_revision: <> * * Copyright (C) 2021 Analog Devices Inc. diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-m4-l8.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-m4-l8.dts index 7e96586af9017b..f462709ef64735 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-m4-l8.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9082-m4-l8.dts @@ -4,7 +4,7 @@ * https://wiki.analog.com/resources/eval/user-guides/quadmxfe/quick-start * https://wiki.analog.com/resources/tools-software/linux-drivers/iio-mxfe/ad9081 * - * hdl_project: + * hdl_project: * board_revision: <> * * Copyright (C) 2019-2021 Analog Devices Inc. From 4147d32d288c9cb9e19d1024b4715ca02ea04fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 10 Jun 2022 14:47:02 +0200 Subject: [PATCH 354/407] iio: adrv9002: Update API to 67.1.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDK is taken as is which means that compilation will likely fail. The following patches will integrate the new SDK with linux and the existing driver code. Signed-off-by: Nuno Sá --- .../adrv9001/private/src/adrv9001_arm.c | 77 +++--- .../public/include/adi_adrv9001_cals.h | 69 +++++- .../public/include/adi_adrv9001_dpd_types.h | 2 + .../public/include/adi_adrv9001_fh_types.h | 3 + .../public/include/adi_adrv9001_gpio.h | 36 +-- .../public/include/adi_adrv9001_gpio_types.h | 23 +- .../adrv9001/public/include/adi_adrv9001_rx.h | 56 ++++- .../public/include/adi_adrv9001_rx_types.h | 9 +- .../public/include/adi_adrv9001_types.h | 14 +- .../public/include/adi_adrv9001_version.h | 2 +- .../adrv9001/public/src/adi_adrv9001_arm.c | 14 +- .../adrv9001/public/src/adi_adrv9001_auxadc.c | 109 +++++++-- .../adrv9001/public/src/adi_adrv9001_cals.c | 162 +++++++++++-- .../adrv9001/public/src/adi_adrv9001_dpd.c | 12 +- .../adrv9001/public/src/adi_adrv9001_fh.c | 152 ++++++------ .../adrv9001/public/src/adi_adrv9001_gpio.c | 18 +- .../adrv9001/public/src/adi_adrv9001_rx.c | 219 ++++++++++++++---- .../adrv9001/public/src/adi_adrv9001_tx.c | 106 ++++----- 18 files changed, 773 insertions(+), 310 deletions(-) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c b/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c index 9f162219fa0500..66aae466a504b0 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/private/src/adrv9001_arm.c @@ -40,7 +40,6 @@ #include #endif - /* Header files related to libraries */ /* System header files */ @@ -105,8 +104,8 @@ const char* const adrv9001_error_table_CmdCtrlMboxCmdError[] = "Command error" }; -const char* const adrv9001_error_table_CmdError[] = -{ +const char* const adrv9001_error_table_CmdError[] = +{ "Error occurred during an Init Calibration. Check that no signal is being applied to the Rx ports. Check that " "correct external LOs are applied, and synchronized, where appropriate", "Error occurred during a Tracking Calibration. Disable tracking calibrations, reset and program. If enabled " @@ -255,7 +254,7 @@ static __maybe_unused int32_t adrv9001_DmaMemReadByte(adi_adrv9001_Device_t *dev } regRead |= ADRV9001_DMA_CTL_LEGACY_MODE; - + /* bus size, 2'b00=byte; 2'b01=half-word; 2'b10=full-word; 2'b11=invalid */ /* core_bf.bus_size.write(bf_status, 2'b10); */ regRead |= ADRV9001_BF_ENCODE(0, ADRV9001_DMA_CTL_BUS_SIZE_MASK, ADRV9001_DMA_CTL_BUS_SIZE_SHIFT); @@ -327,7 +326,7 @@ static __maybe_unused int32_t adrv9001_DmaMemReadByte(adi_adrv9001_Device_t *dev returnData[i + 1] = dataRead0; ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_2", ADRV9001_ADDR_ARM_DMA_DATA2, &dataRead0); returnData[i + 2] = dataRead0; - + /* 'single_instruction' has to be cleared before reading DMA_DATA3 and set back after */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x0); ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_3", ADRV9001_ADDR_ARM_DMA_DATA3, &dataRead0); @@ -1044,7 +1043,7 @@ static void adrv9001_LoadSsiConfig(adi_adrv9001_Device_t *device, uint32_t *offs cfgData[tempOffset++] = (uint8_t)ssiConfig->cmosClkInversionEn; cfgData[tempOffset++] = (uint8_t)ssiConfig->ddrEn; - + cfgData[tempOffset++] = (uint8_t)ssiConfig->rxMaskStrobeEn; /* 4 bytes of padding is needed for alignment */ @@ -1565,15 +1564,15 @@ typedef struct duplexMode_e duplexMode; uint8_t fhModeOn; uint8_t reserved1[1u]; //< Reserved for future feature - uint8_t numDynamicProfile; // Number of Profile. =1 means only one profile and no switching + uint8_t numDynamicProfile; // Number of Profile. =1 means only one profile and no switching mcsMode_e mcsMode; // MCS mode selection: 0 - Disable, 1 - MCS Only, 2 - MCS + RFPLL phase sync - adcType_e adcTypeMonitor; // ADC type used in Monitor Mode - uint16_t pllLockTime_us; // Required lock time in microseconds for PLLs, based on ref_clk and loop bandwidth - pllModulus_t pllModuli; // PLL moduli - uint16_t pllPhaseSyncWait_us; // Worst case phase sync wait time in FH - mcsInf_e mcsInterfaceType; // 0-Disabled, 1-CMOS, 2-LVDS - uint8_t warmBootEnable; // Enable WarmBoot - Load initCal cefficients instead of running initCals - uint32_t reserved[1u]; // Reserved for future feature + adcType_e adcTypeMonitor; // ADC type used in Monitor Mode + uint16_t pllLockTime_us; // Required lock time in microseconds for PLLs, based on ref_clk and loop bandwidth + pllModulus_t pllModuli; // PLL moduli + uint16_t pllPhaseSyncWait_us; // Worst case phase sync wait time in FH + mcsInf_e mcsInterfaceType; // 0-Disabled, 1-CMOS, 2-LVDS + uint8_t warmBootEnable; // Enable WarmBoot - Load initCal cefficients instead of running initCals + uint32_t reserved[1u]; // Reserved for future feature } deviceSysConfig_t; */ static void adrv9001_DeviceSysConfigWrite(adi_adrv9001_Device_t *device, const adi_adrv9001_DeviceSysConfig_t *sysConfig, uint8_t cfgData[], uint32_t *offset) @@ -1611,13 +1610,13 @@ static void adrv9001_DeviceSysConfigWrite(adi_adrv9001_Device_t *device, const a { adrv9001_LoadFourBytes(&tempOffset, cfgData, sysConfig->pllModulus.dmModulus[i]); } - + /* PLL phase sync wait time in us */ adrv9001_LoadTwoBytes(&tempOffset, cfgData, sysConfig->pllPhaseSyncWait_us); cfgData[tempOffset++] = sysConfig->mcsInterfaceType; cfgData[tempOffset++] = sysConfig->warmBootEnable; - + /* 4 bytes padding; Reserved for future use */ tempOffset += 4; @@ -1994,7 +1993,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co uint8_t singleInstruction = 0; uint8_t spiMode = 0; uint8_t spiConfig_A = 0; - + ADI_ENTRY_PTR_ARRAY_EXPECT(device, data, byteCount); ADRV9001_DMAINFO("ARM_MEM_WRITE", armMemAddress, byteCount); @@ -2013,7 +2012,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co /* If Address is not on word boundary, Or ByteCount is not on Word boundary */ if (((armMemAddress & 0x00000003) > 0) || ((byteCount & 0x00000003) > 0)) { - if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || + if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || (ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4 == spiWriteMode)) { ADI_ERROR_REPORT(&device->common, @@ -2057,7 +2056,7 @@ int32_t adrv9001_DmaMemWrite(adi_adrv9001_Device_t *device, uint32_t address, co /* setting up the DMA control register for a write */ ADRV9001_SPIWRITEBYTEDMA(device, "ARM_DMA_CTL", ADRV9001_ADDR_ARM_DMA_CTL, regWrite); - + /* Enable single instruction and disable SPI streaming mode by default. * If ADRV9001 SPI streming mode is selected, then single instruction and single instruction are disbled */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x1); @@ -2187,18 +2186,18 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop uint8_t addrLsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; uint8_t dataArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; #else - static uint8_t addrMsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; - static uint8_t addrLsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; - static uint8_t dataArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; + static uint8_t addrMsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; + static uint8_t addrLsbArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; + static uint8_t dataArray[ADRV9001_FREQ_HOPPING_MAX_NUM_BYTES]; - memset(addrMsbArray, 0, sizeof(addrMsbArray)); - memset(addrLsbArray, 0, sizeof(addrLsbArray)); - memset(dataArray, 0, sizeof(dataArray)); + memset(addrMsbArray, 0, sizeof(addrMsbArray)); + memset(addrLsbArray, 0, sizeof(addrLsbArray)); + memset(dataArray, 0, sizeof(dataArray)); #endif ADI_ENTRY_PTR_ARRAY_EXPECT(device, numHopTableEntries, numHopTableEntriesByteCount); ADI_ENTRY_PTR_ARRAY_EXPECT(device, hopTableBufferData, hopTableBufferDataByteCount); - + /* Trigger appropriate SPI Interrupt upon table load */ if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) { @@ -2214,7 +2213,7 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop } ADRV9001_DMAINFO("ARM_MEM_WRITE", armMemAddress, byteCount); - + regWrite &= ~ADRV9001_DMA_CTL_RD_WRB; regWrite |= ADRV9001_DMA_CTL_SYS_CODEB; regWrite |= ADRV9001_BF_ENCODE(2, ADRV9001_DMA_CTL_BUS_SIZE_MASK, ADRV9001_DMA_CTL_BUS_SIZE_SHIFT); @@ -2262,7 +2261,7 @@ int32_t adrv9001_DmaMemWriteFH(adi_adrv9001_Device_t *device, adi_adrv9001_FhHop dataArray[addrIndex] = numHopTableEntries[dataIndex]; addrIndex++; } - + addrMsbArray[addrIndex] = (uint8_t)(((ADRV9001_SPI_WRITE_POLARITY & 0x01) << 7) | ((ADRV9001_ADDR_ARM_DMA_ADDR3 >> 8) & 0x7F)); addrLsbArray[addrIndex] = (uint8_t)ADRV9001_ADDR_ARM_DMA_ADDR3; dataArray[addrIndex] = (uint8_t)((hopTableBufferAddress) >> ADRV9001_ADDR_ARM_DMA_ADDR3_BYTE_SHIFT); @@ -2412,7 +2411,7 @@ int32_t adrv9001_DmaMemRead(adi_adrv9001_Device_t *device, uint32_t address, uin returnData[i + 2] = dataRead; ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_1", ADRV9001_ADDR_ARM_DMA_DATA1, &dataRead); returnData[i + 1] = dataRead; - + /* 'single_instruction' has to be cleared before reading DMA_DATA3 and set back after */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x0); ADRV9001_SPIREADBYTEDMA(device, "ARM_DMA_DATA_0", ADRV9001_ADDR_ARM_DMA_DATA0, &dataRead); @@ -2477,7 +2476,7 @@ int32_t adrv9001_FlexStreamProcessorMemWrite(adi_adrv9001_Device_t *device, /* If Address is not on word boundary, Or ByteCount is not on Word boundary */ if (((flexSpAddress & 0x00000003) > 0) || ((byteCount & 0x00000003) > 0)) { - if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || + if ((ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_252 == spiWriteMode) || (ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4 == spiWriteMode)) { ADI_ERROR_REPORT(&device->common, @@ -2512,7 +2511,7 @@ int32_t adrv9001_FlexStreamProcessorMemWrite(adi_adrv9001_Device_t *device, /* setting up the flex SP DMA control register for a write */ ADRV9001_SPIWRITEBYTEDMA(device, "FLEX_SP_ARM_DMA_CTL", ADRV9001_ADDR_FLEX_SP_ARM_DMA_CTL, regWrite); - + /* Enable single instruction and disable SPI streaming mode by default. * If ADRV9001 SPI streming mode is selected, then single instruction and single instruction are disbled */ ADI_EXPECT(adrv9001_NvsRegmapCore_SingleInstruction_Set, device, 0x1); @@ -2775,7 +2774,7 @@ static const char* adrv9001_CmdErrMsgGet(uint32_t errCode) { return adrv9001_error_table_CmdError[6]; } - + return NULL; } @@ -2832,7 +2831,7 @@ int32_t adrv9001_ArmCmdErrorHandler(adi_adrv9001_Device_t *device, uint32_t detE ADI_EXPECT(adrv9001_ArmMailBoxErrCodeGet, device, &mailboxErrCode); errorString = adrv9001_CmdErrMsgGet(mailboxErrCode); - + ADI_ERROR_REPORT(&device->common, ADI_ADRV9001_SRC_ARMCMD, mailboxErrCode, @@ -2934,7 +2933,7 @@ static uint32_t adrv9001_ArmProfileWrite_Validate(adi_adrv9001_Device_t *device, ADI_ERROR_RETURN(device->common.error.newAction); } } - + /* Range check parameters in adi_adrv9001_TxSettings_t */ for (i = 0; i < ADI_ADRV9001_MAX_TXCHANNELS; i++) { @@ -2950,7 +2949,7 @@ static uint32_t adrv9001_ArmProfileWrite_Validate(adi_adrv9001_Device_t *device, ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.ssiDataFormatSel, ADI_ADRV9001_SSI_FORMAT_2_BIT_SYMBOL_DATA, ADI_ADRV9001_SSI_FORMAT_22_BIT_I_Q_DATA_1_BIT_GAIN_CHANGE_8_BIT_GAIN_INDEX); ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.numLaneSel, ADI_ADRV9001_SSI_1_LANE, ADI_ADRV9001_SSI_4_LANE); ADI_RANGE_CHECK(device, init->tx.txProfile[i].txSsiConfig.strobeType, ADI_ADRV9001_SSI_SHORT_STROBE, ADI_ADRV9001_SSI_LONG_STROBE); - + if ((ADI_ADRV9001_SSI_TYPE_LVDS == init->tx.txProfile[i].txSsiConfig.ssiType) && (false == init->tx.txProfile[i].txSsiConfig.ddrEn) && (init->tx.txProfile[i].txInterfaceSampleRate_Hz > 30720000)) @@ -3127,7 +3126,7 @@ int32_t adrv9001_ArmProfileWrite(adi_adrv9001_Device_t *device, const adi_adrv90 cfgData[offset++] = (uint8_t)(init->clocks.armPowerSavingClkDiv - 1); cfgData[offset++] = (uint8_t)init->clocks.refClockOutEnable; - + cfgData[offset++] = (uint8_t)init->clocks.auxPllPower; cfgData[offset++] = (uint8_t)init->clocks.clkPllPower; @@ -3186,14 +3185,14 @@ int32_t adrv9001_ArmProfileWrite(adi_adrv9001_Device_t *device, const adi_adrv90 if (ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_TX_PROFILE_VALID)) { armChannels |= (init->tx.txInitChannelMask & (ADI_ADRV9001_TX1 | ADI_ADRV9001_TX2)); - + /* Tx channels must have a valid and enabled ILB channel unless the signaling is Direct FM/FSK */ if(ADRV9001_BF_EQUAL(init->tx.txInitChannelMask, ADI_ADRV9001_TX1) && (init->tx.txProfile[0].outputSignaling != ADI_ADRV9001_TX_DIRECT_FM_FSK)) { armChannels |= (init->rx.rxInitChannelMask & ADI_ADRV9001_ILB1); } - + if (ADRV9001_BF_EQUAL(init->tx.txInitChannelMask, ADI_ADRV9001_TX2) && (init->tx.txProfile[1].outputSignaling != ADI_ADRV9001_TX_DIRECT_FM_FSK)) { @@ -3482,7 +3481,7 @@ int32_t adrv9001_DynamicProfile_Write(adi_adrv9001_Device_t *device, int32_t recoveryAction = ADI_COMMON_ACT_NO_ACTION; uint32_t offset = 0; uint8_t cfgData[ADRV9001_DYNAMIC_PROFILE_BLOB_SIZE] = { 0 }; - + cfgData[offset++] = dynamicProfile->dynamicProfileIndex; cfgData[offset++] = 0; // padding cfgData[offset++] = 0; // padding diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals.h index 1fc87240cef599..6df79e1f384e98 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_cals.h @@ -279,7 +279,25 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate(adi_adrv9001_Device_t *adrv uint32_t length); /** - * \brief Read the InitCal coefficients needed for Warmboot + * \brief Return the unique initCals enabled for this device configuration + * + * \note Message type: \ref timing_mailbox "Mailbox command" + * + * \pre Channel state is CALIBRATED + * + * \param[in] device Context variable - Pointer to the ADRV9001 device settings data structure + * \param[out] calNumbers Number of unique initCals enabled and array containing calNumber for each for this device configuration + * \param[in] maskChannel1 Calibration bit mask for channel 1 + * \param[in] maskChannel2 Calibration bit mask for channel 2 + * + * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover + */ + int32_t adi_adrv9001_cals_InitCals_WarmBoot_UniqueEnabledCals_Get(adi_adrv9001_Device_t *device, + adi_adrv9001_Warmboot_CalNumbers_t *calNumbers, + uint32_t maskChannel1, + uint32_t maskChannel2); +/** + * \brief Read the InitCal coefficients needed for Warmboot, savedCals has size ADI_ADRV9001_WB_MAX_NUM_UNIQUE_CALS x ADI_ADRV9001_WB_MAX_NUM_COEFF * * \note Message type: \ref timing_mailbox "Mailbox command" * @@ -292,13 +310,32 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate(adi_adrv9001_Device_t *adrv * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ - int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Get(adi_adrv9001_Device_t *device, - adi_adrv9001_Warmboot_Coeff_t *savedCals, - uint32_t maskChannel1, - uint32_t maskChannel2); + int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_MaxArray_Get(adi_adrv9001_Device_t *device, + adi_adrv9001_Warmboot_Coeff_t *savedCals, + uint32_t maskChannel1, + uint32_t maskChannel2); + +/** + * \brief Read the InitCal coefficients needed for Warmboot and place in allocated memory + * + * \note Message type: \ref timing_mailbox "Mailbox command" + * + * \pre Channel state is CALIBRATED + * + * \param[in] device Context variable - Pointer to the ADRV9001 device settings data structure + * \param[in] memStartAddress Pointer to start address of memory block that has been allocated to hold warmbootMemoryNumBytes + * \param[in] maskChannel1 Calibration bit mask for channel 1 + * \param[in] maskChannel2 Calibration bit mask for channel 2 + * + * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover + */ + int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_UniqueArray_Get(adi_adrv9001_Device_t *device, + char *memStartAddress, + uint32_t maskChannel1, + uint32_t maskChannel2); /** - * \brief Store the InitCal coefficients needed for Warmboot + * \brief Write the InitCal coefficients needed for Warmboot, savedCals has size ADI_ADRV9001_WB_MAX_NUM_UNIQUE_CALS x ADI_ADRV9001_WB_MAX_NUM_COEFF * * \note Message type: \ref timing_mailbox "Mailbox command" * @@ -311,10 +348,28 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate(adi_adrv9001_Device_t *adrv * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ - int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Set(adi_adrv9001_Device_t *device, + int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_MaxArray_Set(adi_adrv9001_Device_t *device, adi_adrv9001_Warmboot_Coeff_t *savedCals, uint32_t maskChannel1, uint32_t maskChannel2); +/** +* \brief Write the InitCal coefficients needed for Warmboot from allocated memory +* +* \note Message type: \ref timing_mailbox "Mailbox command" +* +* \pre Channel state is STANDBY +* +* \param[in] device Context variable - Pointer to the ADRV9001 device settings data structure +* \param[in] memStartAddress Pointer to start address of memory block that has been allocated and contains warmbootMemoryNumBytes +* \param[in] maskChannel1 Calibration bit mask for channel 1 +* \param[in] maskChannel2 Calibration bit mask for channel 2 +* +* \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover +*/ + int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_UniqueArray_Set(adi_adrv9001_Device_t *device, + char *memStartAddress, + uint32_t maskChannel1, + uint32_t maskChannel2); #ifdef __cplusplus } #endif diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd_types.h index 7dadd74819fd81..3c98c17972642b 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_dpd_types.h @@ -137,6 +137,8 @@ typedef struct adi_adrv9001_DpdCfg uint32_t clgcFilterAlpha; /*!< filter coefficient for the filtered gain values. */ int32_t clgcLastGain_HundredthdB; /*!< last gain. Only valid during Get. */ int32_t clgcFilteredGain_HundredthdB; /*!< filtered gain. Only valid during Get. */ + + uint32_t captureDelay_us; /*!< Amount of time that capture will be delayed (beyond normal) relative to the start of the frame. This parameter applies to both DPD and CLGC. */ } adi_adrv9001_DpdCfg_t; typedef struct adi_adrv9001_DpdCoefficients diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h index 3e44ef30f67dee..639298e52be51b 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_fh_types.h @@ -194,6 +194,9 @@ typedef struct { bool gainSetupByPin; /*!< Use GPIO Pins to provide a Tx/Rx gain index for next hop frame. If false, gain information is provided in hop table*/ adi_adrv9001_FhGainSetupByPinCfg_t gainSetupByPinConfig[ADI_ADRV9001_NUM_CHANNELS]; /*!< Configuration information for gain setup by pin. This structure is ignored if gainSetupByPin is false */ + bool enableAGCGainIndexSeeding; /*!< Enable seeding of the hardware value of adi_adrv9001_GainControlCfg_t->resetOnRxonGainIndex with rxGainIndex from FHTable, + if mode is ADI_ADRV9001_RX_GAIN_CONTROL_MODE_AUTO then + gainIndex will begin tracking from this seeded gainIndex at the beginning of the frame */ } adi_adrv9001_FhCfg_t; #ifdef __cplusplus diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h index 7179df8add7404..6d2a654784b152 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio.h @@ -120,7 +120,7 @@ int32_t adi_adrv9001_gpio_GpIntStatus_Get(adi_adrv9001_Device_t *adrv9001, uint3 * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_OutputPinLevel_Set(adi_adrv9001_Device_t *adrv9001, - adi_adrv9001_GpioPin_e pin, + adi_adrv9001_GpioPin_e pin, adi_adrv9001_GpioPinLevel_e level); /** @@ -158,7 +158,7 @@ int32_t adi_adrv9001_gpio_OutputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin, adi_adrv9001_GpioPinLevel_e *gpioInPinLevels); @@ -169,64 +169,64 @@ int32_t adi_adrv9001_gpio_InputPinLevel_Get(adi_adrv9001_Device_t *adrv9001, * * \note Message type: \ref timing_direct "Direct register access" * - * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure + * \param[in] device Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] pin The pin for which to get the direction * \param[out] direction Current direction of the pin * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_PinDirection_Get(adi_adrv9001_Device_t *device, - adi_adrv9001_GpioPin_e pin, - adi_adrv9001_GpioPinDirection_e *direction); + adi_adrv9001_GpioPin_e pin, + adi_adrv9001_GpioPinDirection_e *direction); /** * \brief Configure specified pin as manual input - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] pin The GPIO pin to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_ManualInput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin); - + /** * \brief Configure specified pin crumb as manual output - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] crumb The GPIO pin crumb to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ int32_t adi_adrv9001_gpio_ManualOutput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPinCrumbSel_e crumb); /** * \brief Configure specified analog GPIO pin as manual input - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] pin The analog GPIO pin to configure - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_ManualAnalogInput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioPin_e pin); /** * \brief Configure specified analog GPIO pin nibble as manual output - * + * * \note Message type: \ref timing_direct "Direct register access" * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device settings data structure * \param[in] nibble The analog GPIO pin nibble to configure * \param[in] source The source signal to be output on the pins - * + * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ -int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioAnalogPinNibbleSel_e nibble); /** @@ -241,7 +241,7 @@ int32_t adi_adrv9001_gpio_ManualAnalogOutput_Configure(adi_adrv9001_Device_t *ad */ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioCtrlInitCfg_t *gpioCtrlInitCfg); - + /** * \brief Configure the ADRV9001 GPIO for the specified signal * @@ -258,7 +258,7 @@ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, int32_t adi_adrv9001_gpio_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_GpioSignal_e signal, adi_adrv9001_GpioCfg_t *gpioConfig); - + /** * \brief Retrieve the ADRV9001 GPIO configuration for the requested signal * diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h index c9967920c57cd5..ba3c20c09141d3 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_gpio_types.h @@ -200,8 +200,10 @@ typedef enum adi_adrv9001_GpioSignal ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2_TABLE_SELECT, /*!< Frequency hopping table select for HOP 2 */ ADI_ADRV9001_GPIO_SIGNAL_FH_HOP1_NCO_ASYNC_CHANGE, /*!< Asynchronously change NCO for Hop1 */ ADI_ADRV9001_GPIO_SIGNAL_FH_HOP2_NCO_ASYNC_CHANGE, /*!< Asynchronously change NCO for Hop2 */ + ADI_ADRV9001_GPIO_SIGNAL_RX1_INTERFACEGAIN_SEED_SAVE = 52, /*!< Seed (rising edge) or save (falling edge) the RX1 InterfaceGain */ + ADI_ADRV9001_GPIO_SIGNAL_RX2_INTERFACEGAIN_SEED_SAVE = 53, /*!< Seed (rising edge) or save (falling edge) the RX2 InterfaceGain */ - ADI_ADRV9001_GPIO_NUM_SIGNALS = 46, /*!< Total Number of signals from BBIC*/ + ADI_ADRV9001_GPIO_NUM_SIGNALS = 54, /*!< Total Number of signals from BBIC*/ } adi_adrv9001_GpioSignal_e; /** @@ -246,15 +248,16 @@ typedef struct adi_adrv9001_GpioCfg */ typedef struct adi_adrv9001_GpioCtrlInitCfg { - adi_adrv9001_GpioCfg_t tx_ext_frontend_ctrl[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) Tx FrontEnd controls */ - adi_adrv9001_GpioCfg_t rx_ext_frontend_ctrl[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) Rx FrontEnd controls */ - adi_adrv9001_GpioCfg_t ext_pll_chip_enable[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) External PLL Chip Enables */ - adi_adrv9001_GpioCfg_t vco_chip_enable[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) Rx VCO Chip Enables */ - adi_adrv9001_GpioCfg_t ext_pll_lock[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) External PLL locks */ - adi_adrv9001_GpioCfg_t channelPowerSaving[ADI_ADRV9001_NUM_CHANNELS]; /*!< (DGPIO) Channel Power Saving Enables */ - adi_adrv9001_GpioCfg_t systemPowerSavingAndMonitorEnable; /*!< (DGPIO) System Power Saving and Monitor Enable */ - adi_adrv9001_GpioCfg_t systemPowerSavingAndMonitorWakeUp; /*!< (DGPIO) Monitor WakeUp */ - adi_adrv9001_GpioCfg_t fh_update_rx_nco[ADI_ADRV9001_NUM_CHANNELS]; /*!< (DGPIO) Trigger Update of Rx NCO in Frequency Hop Frame */ + adi_adrv9001_GpioCfg_t tx_ext_frontend_ctrl[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) Tx FrontEnd controls */ + adi_adrv9001_GpioCfg_t rx_ext_frontend_ctrl[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) Rx FrontEnd controls */ + adi_adrv9001_GpioCfg_t ext_pll_chip_enable[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) External PLL Chip Enables */ + adi_adrv9001_GpioCfg_t vco_chip_enable[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) Rx VCO Chip Enables */ + adi_adrv9001_GpioCfg_t ext_pll_lock[ADI_ADRV9001_NUM_PORTS]; /*!< (AGPIO) External PLL locks */ + adi_adrv9001_GpioCfg_t channelPowerSaving[ADI_ADRV9001_NUM_CHANNELS]; /*!< (DGPIO) Channel Power Saving Enables */ + adi_adrv9001_GpioCfg_t systemPowerSavingAndMonitorEnable; /*!< (DGPIO) System Power Saving and Monitor Enable */ + adi_adrv9001_GpioCfg_t systemPowerSavingAndMonitorWakeUp; /*!< (DGPIO) Monitor WakeUp */ + adi_adrv9001_GpioCfg_t fh_update_rx_nco[ADI_ADRV9001_NUM_CHANNELS]; /*!< (DGPIO) Trigger Update of Rx NCO in Frequency Hop Frame */ + adi_adrv9001_GpioCfg_t rx_interfaceGain_seed_save[ADI_ADRV9001_NUM_CHANNELS]; /*!< (DGPIO) Trigger Seed (RisingEdge) or Save (FallingEdge) of interfaceGain */ } adi_adrv9001_GpioCtrlInitCfg_t; diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx.h index d04dfa308a6fce..439cccac7b873e 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx.h @@ -186,7 +186,7 @@ int32_t adi_adrv9001_Rx_Rssi_Read(adi_adrv9001_Device_t *adrv9001, * The location of the power measurement is given by agcCfg->power->powerInputSelect * The number of samples used by power measurement is given by 8*2^(agcCfg->power->powerMeasurementDuration) at the IQ rate, * if measured at RFIR output. This number of samples must be less than the agcCfg->gainUpdateCounter. - * If the receiver is disabled during the power measurement, this function returns a '0' for rxDecPower_mdBFS + * If the receiver is disabled (all zero samples) during the power measurement, this function returns a '200000' for rxDecPower_mdBFS * * The resolution of this function is 250mdB. * The dynamic range of this function is 60dB. Signals lower than -60dBFS may not be measured accurately. @@ -195,7 +195,7 @@ int32_t adi_adrv9001_Rx_Rssi_Read(adi_adrv9001_Device_t *adrv9001, * * \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device data structure * \param[in] channel An enum ( of type adi_common_ChannelNumber_e) to select Rx Channel. - * \param[out] rxDecPower_mdBFS Pointer to store the ADRV9001 Dec Power return. Value returned is in mdBFS. + * \param[out] rxDecPower_mdBFS Pointer to store the ADRV9001 Dec Power return. Value returned is in mdBFS. If all samples are zero, a '200000' is returned * * \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover */ @@ -276,7 +276,59 @@ int32_t adi_adrv9001_Rx_InterfaceGain_Inspect(adi_adrv9001_Device_t *adrv9001, int32_t adi_adrv9001_Rx_InterfaceGain_Get(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_RxInterfaceGain_e *gain); +/** +* \brief Set the Seed for Rx interface gain for the next frame, seedGain is applied by rising edge on associated GPIO +* +* \note Message type: \ref timing_direct "Direct register access" +* +* \pre Channel state is any of CALIBRATED, PRIMED, RF_ENABLED +* +* \pre Seeding of interfaceGain is only enabled when controlMode = ADI_ADRV9001_RX_INTERFACE_GAIN_CONTROL_AUTOMATIC +* +* \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device data structure +* \param[in] channel The Rx channel for which the interface gain has to be configured +* \param[in] seedGain The gain value to be seeded for next frame by rising edge on associated GPIO +* +* \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover +*/ +int32_t adi_adrv9001_Rx_InterfaceGain_SeedGain_Set(adi_adrv9001_Device_t *adrv9001, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxInterfaceGain_e seedGain); + +/** +* \brief Get the Seed for Rx interface gain for the next frame, seedGain is applied by rising edge on associated GPIO +* +* \note Message type: \ref timing_direct "Direct register access" +* +* \pre Channel state any of CALIBRATED, PRIMED, RF_ENABLED +* +* \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device data structure +* \param[in] channel The Rx channel from which to read the interface gain +* \param[out] seedGain The gain value to be seeded for next frame by rising edge on associated GPIO +* +* \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover +*/ +int32_t adi_adrv9001_Rx_InterfaceGain_SeedGain_Get( adi_adrv9001_Device_t *adrv9001, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxInterfaceGain_e *seedGain); +/** +* \brief Get the EndOfFrameGain for Rx interface gain, EndOfFrameGain is updated by falling edge on associated GPIO +* +* \note Message type: \ref timing_direct "Direct register access" +* +* \pre Channel state any of CALIBRATED, PRIMED, RF_ENABLED +* +* \param[in] adrv9001 Context variable - Pointer to the ADRV9001 device data structure +* \param[in] channel The Rx channel from which to read the interface gain +* \param[out] endOfFrameGain The gain value at end of previous frame, latched by falling edge on associated GPIO +* +* \returns A code indicating success (ADI_COMMON_ACT_NO_ACTION) or the required action to recover +*/ +int32_t adi_adrv9001_Rx_InterfaceGain_EndOfFrameGain_Get( adi_adrv9001_Device_t *adrv9001, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxInterfaceGain_e *endOfFrameGain); + /** * \brief Set the NCO frequency to correct for small deviations in Rx LO frequency * diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h index 9c3262f5c126a7..3302fe02f90f90 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_rx_types.h @@ -29,6 +29,10 @@ extern "C" { #define ADI_ADRV9001_RX_GAIN_INDEX_MIN 187 #define ADI_ADRV9001_RX_GAIN_INDEX_MAX 255 +#define RX1_INTERFACE_GAIN_SEED_ADDR 0x2001FFD0 +#define RX2_INTERFACE_GAIN_SEED_ADDR 0x2001FFD4 +#define RX1_INTERFACE_GAIN_END_OF_FRAME_ADDR 0x2001FFD8 +#define RX2_INTERFACE_GAIN_END_OF_FRAME_ADDR 0x2001FFDC /** * \brief Rx gain table SRAM base addresses @@ -132,8 +136,9 @@ typedef struct adi_adrv9001_RxInterfaceGainCtrl adi_adrv9001_RxInterfaceGain_e gain; uint8_t rssiDuration; /* Duration of RSSI measurement (unit = 1ms/255 ) */ uint8_t rssiMovingAverageDuration; /* Number of measurements in RSSI Moving-Average window */ - uint8_t reserved1; - uint8_t reserved2; + int8_t gainControlAutomaticThreshold_dBFS; /* Max signal level target in dBFS */ + uint8_t signalPAR; /* Peak to Average Ratio of applied signal */ + bool enableFastAttack; /* false: fastAttack and tracking use same configuration of MovingAveragefilter, true: No MovingAveragefilter in fastAttack region */ } adi_adrv9001_RxInterfaceGainCtrl_t; diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h index f258e8e701d8ea..c07c5d23901c03 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_types.h @@ -37,6 +37,9 @@ /* TODO: Determine a reasonable value */ #define ADI_ADRV9001_READY_FOR_MCS_DELAY_US 100U +#define ADI_ADRV9001_WB_MAX_NUM_UNIQUE_CALS 156 +#define ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_WORDS 624 +#define ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_BYTES 2496 #define ADI_ADRV9001_WB_MAX_NUM_ENTRY 16384 #define ADI_ADRV9001_WB_MAX_NUM_COEFF 6000 @@ -185,9 +188,18 @@ typedef struct adi_adrv9001_SiliconVersion */ typedef struct adi_adrv9001_Warmboot_Coeff { - uint8_t calValue[ADI_ADRV9001_WB_MAX_NUM_ENTRY][ADI_ADRV9001_WB_MAX_NUM_COEFF]; + uint8_t calValue[ADI_ADRV9001_WB_MAX_NUM_UNIQUE_CALS][ADI_ADRV9001_WB_MAX_NUM_COEFF]; } adi_adrv9001_Warmboot_Coeff_t; +/** + * \brief WarmBoot calNumbers Information + */ +typedef struct adi_adrv9001_Warmboot_CalNumbers { + uint8_t numberUniqueEnabledCals; /*!< The Number of unique initCals enabled for this device configuration */ + uint8_t calNumbersEnabled[ADI_ADRV9001_WB_MAX_NUM_UNIQUE_CALS]; /*!< Array indicating the calNumber of each enabled unique initCal */ + uint32_t warmbootMemoryNumBytes; /*!< Memory allocation required to store/retrieve the Warmboot coefficients */ +} adi_adrv9001_Warmboot_CalNumbers_t; + #ifndef CLIENT_IGNORE /** * \brief Data structure to hold a ADRV9001 device instance status information diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h index 613a4c78676c82..eba873aea9d5b4 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/include/adi_adrv9001_version.h @@ -19,7 +19,7 @@ extern "C" { #endif /* Auto-generated version number - DO NOT MANUALLY EDIT */ -#define ADI_ADRV9001_CURRENT_VERSION "48.49.2" +#define ADI_ADRV9001_CURRENT_VERSION "67.1.1" #ifdef __cplusplus } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c index ebb60ce9f97df3..89a2c7cbd3458d 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_arm.c @@ -373,7 +373,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_arm_Memory_ReadWrite_V "Invalid parameter value. byteCount must be a multiple of 4 when using autoIncrement"); ADI_ERROR_RETURN(device->common.error.newAction); } - + ADI_RANGE_CHECK(device, spiWriteMode, ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4, ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STREAMING_BYTES_4); ADI_API_RETURN(device); } @@ -398,7 +398,7 @@ int32_t adi_adrv9001_arm_Memory_Read32(adi_adrv9001_Device_t *device, uint8_t autoIncrement) { //uint8_t data[] = { 0 }; - + ADI_PERFORM_VALIDATION(adi_adrv9001_arm_Memory_ReadWrite_Validate, device, address, (uint8_t *)returnData, byteCount, 0, autoIncrement); ADI_EXPECT(adrv9001_DmaMemRead, device, address, (uint8_t *)returnData, byteCount, autoIncrement); @@ -1193,7 +1193,7 @@ int32_t adi_adrv9001_arm_System_Program(adi_adrv9001_Device_t *device, uint8_t c ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ILB1) >> (ilbFlgShift)) | ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ELB1) >> (elbFlgShift)) | ((device->devStateInfo.initializedChannels & ADI_ADRV9001_TX1) << (txFlgShiftUp))); - + /*Mask for Channel 2 */ device->devStateInfo.chProfEnMask[1] = (((device->devStateInfo.initializedChannels & ADI_ADRV9001_RX2) >> 1) | ((device->devStateInfo.initializedChannels & ADI_ADRV9001_ORX2) >> (orxFlgShift + 1)) | @@ -1206,7 +1206,7 @@ int32_t adi_adrv9001_arm_System_Program(adi_adrv9001_Device_t *device, uint8_t c device->devStateInfo.chProfEnMask[0] = device->devStateInfo.chProfEnMask[0] | adcPortBFlg; device->devStateInfo.chProfEnMask[1] = device->devStateInfo.chProfEnMask[1] | adcPortBFlg; } - + ADI_API_RETURN(device); } @@ -1425,12 +1425,12 @@ int32_t adi_adrv9001_arm_Start(adi_adrv9001_Device_t *device) { uint8_t armCtl1 = 0; uint8_t mailBox[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; - + ADI_ENTRY_EXPECT(device); /* Set MailBox 0xFF */ ADI_EXPECT(adi_adrv9001_arm_Memory_Write, device, ADRV9001_ADDR_ARM_MAILBOX_GET, &mailBox[0], 4, ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); - + armCtl1 = ADRV9001_AC1_ARM_DEBUG_ENABLE | ADRV9001_AC1_ARM_MEM_HRESP_MASK | ADRV9001_AC1_ARM_M3_RUN; ADRV9001_SPIWRITEBYTE(device, "ARM_CTL_1", ADRV9001_ADDR_ARM_CTL_1, armCtl1); @@ -1447,4 +1447,4 @@ int32_t adi_adrv9001_arm_Stop(adi_adrv9001_Device_t *device) ADRV9001_SPIWRITEBYTE(device, "ARM_CTL_1", ADRV9001_ADDR_ARM_CTL_1, armCtl1); ADI_API_RETURN(device); -} \ No newline at end of file +} diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c index ac0dd00d3cad13..264a3219d3fa05 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c @@ -15,7 +15,14 @@ #include "adi_adrv9001_arm.h" #include "adi_adrv9001_auxadc.h" #include "adrv9001_bf.h" - +/* System header files */ +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#endif static __maybe_unused int32_t __maybe_unused adi_adrv9001_AuxAdc_Configure_Validate(adi_adrv9001_Device_t *device, adi_adrv9001_AuxAdc_e auxAdc) { @@ -137,29 +144,87 @@ int32_t adi_adrv9001_AuxAdc_Voltage_Get(adi_adrv9001_Device_t *device, uint16_t *auxAdc_mV) { uint16_t auxAdcCode = 0; - static const uint16_t MEASURED_OFFSET = 0; - static const uint16_t MEASURED_GAIN = 4096; + uint32_t auxAdcWait, armClk_Hz, auxAdcClk_Hz; + uint8_t refClkDiv, hsClkDiv, armClkDiv, auxAdcClkSel; + static const uint16_t MEASURED_OFFSET = 0; + static const uint16_t MEASURED_GAIN = 4096; ADI_PERFORM_VALIDATION(adi_adrv9001_AuxAdc_Voltage_Get_Validate, device, auxAdc, auxAdc_mV); - - /* Get 12 bit ADC word from selected AuxADC */ - if (auxAdc == ADI_ADRV9001_AUXADC0) - { - ADI_EXPECT(adrv9001_NvsRegmapCore_AuxAdc0Read_Get, device, &auxAdcCode); - } - else if (auxAdc == ADI_ADRV9001_AUXADC1) - { - ADI_EXPECT(adrv9001_NvsRegmapCore_AuxAdc1Read_Get, device, &auxAdcCode); - } - else if (auxAdc == ADI_ADRV9001_AUXADC2) - { - ADI_EXPECT(adrv9001_NvsRegmapCore_AuxAdc2Read_Get, device, &auxAdcCode); - } - else - { - ADI_EXPECT(adrv9001_NvsRegmapCore_AuxAdc3Read_Get, device, &auxAdcCode); - } - + + //These settings are hardcoded in auxadc configure + uint32_t auxadcClkDiv = 63; //clk divider is hardcoded as x6. This is an encoded divider and x6 ==>x3F or d63 + uint32_t decimator = 2048; //decimator is hardcoded as x0. This correspons to 2048. + + ADI_EXPECT(adrv9001_NvsRegmapCore1_AuxAdcClkArmSel_Get, device, &auxAdcClkSel); + if (auxAdcClkSel == 0) + { + //Clock is ref clock + ADI_EXPECT(adrv9001_NvsRegmapCore3_RefClkIntDevclkDivideRatio_Get, device, &refClkDiv); + auxAdcClk_Hz = device->devStateInfo.deviceClock_kHz / pow(2, refClkDiv) * 1000; + } + + else + { + //Clock is arm clock + ADI_EXPECT(adrv9001_NvsRegmapCore_Clk1105ClkSel_Get, device, &hsClkDiv); + if (hsClkDiv == 0) + { + armClk_Hz = device->devStateInfo.hsDigClk_Hz / 2; + } + else + { + armClk_Hz = device->devStateInfo.hsDigClk_Hz; + } + //read arm clk divider + ADI_EXPECT(adrv9001_NvsRegmapCore_ArmClkSel_Get, device, &armClkDiv); + if (armClkDiv == 1) + { + armClk_Hz = armClk_Hz / 4; + } + else if (armClkDiv == 2) + { + armClk_Hz = armClk_Hz / 6; + } + auxAdcClk_Hz = armClk_Hz; + } + + /* Get 12 bit ADC word from selected AuxADC */ + if (auxAdc == ADI_ADRV9001_AUXADC0) + { + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc0Linearity_Set, device, 0x800); + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc0DecLinearDataCapture_Set, device, 0x1); + //Add harware configurable timer based on AUXADC clock + auxAdcWait = 2E+6 / (auxAdcClk_Hz / auxadcClkDiv / decimator); + adi_common_hal_Wait_us(&device->common, auxAdcWait); + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc0ReadData_Get, device, &auxAdcCode); + } + else if (auxAdc == ADI_ADRV9001_AUXADC1) + { + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc1Linearity_Set, device, 0x800); + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc1DecLinearDataCapture_Set, device, 0x1); + //Add harware configurable timer based on AUXADC clock + auxAdcWait = 2E+6 / (auxAdcClk_Hz / auxadcClkDiv / decimator); + adi_common_hal_Wait_us(&device->common, auxAdcWait); + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc1ReadData_Get, device, &auxAdcCode); + } + else if (auxAdc == ADI_ADRV9001_AUXADC2) + { + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc2Linearity_Set, device, 0x800); + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc2DecLinearDataCapture_Set, device, 0x1); + //Add harware configurable timer based on AUXADC clock + auxAdcWait = 2E+6 / (auxAdcClk_Hz / auxadcClkDiv / decimator); + adi_common_hal_Wait_us(&device->common, auxAdcWait); + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc2ReadData_Get, device, &auxAdcCode); + } + else + { + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc3Linearity_Set, device, 0x800); + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc3DecLinearDataCapture_Set, device, 0x1); + //Add harware configurable timer based on AUXADC clock + auxAdcWait = 2E+6 / (auxAdcClk_Hz / auxadcClkDiv / decimator); + adi_common_hal_Wait_us(&device->common, auxAdcWait); + ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc3ReadData_Get, device, &auxAdcCode); + } /*TODO: offset and gain may be read from ADRV9001 device for this calculation */ /* AUXADC_mV = (auxAdcCode - meausured_offset) / measured_gain */ *auxAdc_mV = 1000 * (auxAdcCode - MEASURED_OFFSET) / MEASURED_GAIN; diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c index c306c3487b885d..80ca6c09ab86a7 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c @@ -27,6 +27,8 @@ #include "adrv9001_reg_addr_macros.h" #include "object_ids.h" +#include + int32_t adi_adrv9001_cals_InitCals_Run(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_InitCals_t *initCals, uint32_t timeout_ms, @@ -76,7 +78,7 @@ int32_t adi_adrv9001_cals_InitCals_Run(adi_adrv9001_Device_t *adrv9001, /* Mode to select the Init calibration algorithms to run */ payload[1] = (uint8_t)(initCals->calMode); - + /* A value of true will force all enabled calibrations to re-run */ payload[2] = (uint8_t)(initCals->force); @@ -586,7 +588,7 @@ int32_t adi_adrv9001_cals_InternalPathDelay_Get_Validate(adi_adrv9001_Device_t * { static uint8_t MAX_NUM_PROFILE = 6; adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(adrv9001, port, ADI_RX, ADI_TX); ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, internalPathDelays_ns); @@ -594,7 +596,7 @@ int32_t adi_adrv9001_cals_InternalPathDelay_Get_Validate(adi_adrv9001_Device_t * ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, adrv9001, port, channel, &state); if (ADI_ADRV9001_CHANNEL_STANDBY == state) { - ADI_ERROR_REPORT(&adrv9001->common, + ADI_ERROR_REPORT(&adrv9001->common, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_INV_PARAM, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -726,7 +728,7 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate_Validate(adi_adrv9001_Devic ADI_ENTRY_PTR_EXPECT(adrv9001, initCals); ADI_NULL_PTR_RETURN(&adrv9001->common, errorFlag); - ADI_NULL_PTR_RETURN(&adrv9001->common, dynamicProfile); + ADI_NULL_PTR_RETURN(&adrv9001->common, dynamicProfile); ADI_RANGE_CHECK(adrv9001, length, 1, MAX_NUM_PROFILE); for (port = ADI_RX; port <= ADI_TX; port++) @@ -764,7 +766,7 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate(adi_adrv9001_Device_t *adrv { int8_t i = 0; ADI_EXPECT(adi_adrv9001_cals_Dynamic_profiles_calibrate_Validate, adrv9001, initCals, errorFlag, dynamicProfile, length); - + for (i = 0; i <= (length - 1); i++) { ADI_EXPECT(adi_adrv9001_arm_NextDynamicProfile_Set, adrv9001, &dynamicProfile[i]); @@ -775,24 +777,68 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate(adi_adrv9001_Device_t *adrv ADI_API_RETURN(adrv9001); } -int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Get(adi_adrv9001_Device_t *device, +int32_t adi_adrv9001_cals_InitCals_WarmBoot_UniqueEnabledCals_Get(adi_adrv9001_Device_t *device, + adi_adrv9001_Warmboot_CalNumbers_t *calNumbers, + uint32_t maskChannel1, + uint32_t maskChannel2) +{ +#ifndef __KERNEL__ + uint32_t tblSize[4]; + uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_WORDS] = { 0 }; +#else + static tblSize[4]; + static uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_WORDS]; + static uint32_t calNumbersEnabled[ADI_ADRV9001_WB_MAX_NUM_UNIQUE_CALS]; +#endif + int calNo; + int arrayIndex = 0; + calNumbers->numberUniqueEnabledCals = 0; + + ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); + ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0] * 16, 1); + + for (calNo = 0; calNo < tblSize[0]; calNo++) + { + uint32_t initMask = vecTbl[(4*calNo) + 2]; + uint32_t profMask = vecTbl[(4*calNo) + 3]; + adi_common_ChannelNumber_e channel; + for (channel = ADI_CHANNEL_1; channel <= ADI_CHANNEL_2; channel++) + { + uint32_t chInitMask = maskChannel1; + profMask = profMask >> (8 * (channel - 1)); + if (profMask == 0) + continue; + if (((initMask & chInitMask) != 0) && ((profMask & device->devStateInfo.chProfEnMask[channel - 1]) != 0)) + { + calNumbers->calNumbersEnabled[arrayIndex] = (uint8_t)calNo; + arrayIndex++; + calNumbers->numberUniqueEnabledCals++; + } + } + calNumbers->warmbootMemoryNumBytes = (uint32_t)(calNumbers->numberUniqueEnabledCals * ADI_ADRV9001_WB_MAX_NUM_COEFF); + } + ADI_API_RETURN(device); +} + +int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_MaxArray_Get(adi_adrv9001_Device_t *device, adi_adrv9001_Warmboot_Coeff_t *savedCals, uint32_t maskChannel1, uint32_t maskChannel2) { - uint32_t tblSize[4]; #ifndef __KERNEL__ - uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY] = { 0 }; + uint32_t tblSize[4]; + uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_BYTES] = { 0 }; uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; #else + static tblSize[4]; static uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY]; static uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; #endif - int calNo; + int calNo; ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); - ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0]*16, 1); - + ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0] * 16, 1); + for (calNo = 0; calNo < tblSize[0]; calNo++) { uint32_t addr = vecTbl[4*calNo]; @@ -809,7 +855,6 @@ int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Get(adi_adrv9001_Device if (((initMask & chInitMask) != 0) && ((profMask & device->devStateInfo.chProfEnMask[channel - 1]) != 0)) { int calSize; - ADI_EXPECT(adi_adrv9001_arm_Memory_Read, device, addr, calVal, size, 0); for (calSize = 0; calSize < size; calSize++) { @@ -818,24 +863,66 @@ int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Get(adi_adrv9001_Device } } } + ADI_API_RETURN(device); +} +int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_UniqueArray_Get(adi_adrv9001_Device_t *device, + char *memStartAddress, + uint32_t maskChannel1, + uint32_t maskChannel2) +{ +#ifndef __KERNEL__ + uint32_t tblSize[4]; + uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_BYTES] = { 0 }; + uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; +#else + static tblSize[4]; + static uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY]; + static uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; +#endif + int calNo; + ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); + ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0] * 16, 1); + + for (calNo = 0; calNo < tblSize[0]; calNo++) + { + uint32_t addr = vecTbl[4*calNo]; + uint32_t size = vecTbl[(4*calNo) + 1]; + uint32_t initMask = vecTbl[(4*calNo) + 2]; + uint32_t profMask = vecTbl[(4*calNo) + 3]; + adi_common_ChannelNumber_e channel; + for (channel = ADI_CHANNEL_1; channel <= ADI_CHANNEL_2; channel++) + { + uint32_t chInitMask = maskChannel1; + profMask = profMask >> (8 * (channel - 1)); + if (profMask == 0) + continue; + if (((initMask & chInitMask) != 0) && ((profMask & device->devStateInfo.chProfEnMask[channel - 1]) != 0)) + { + ADI_EXPECT(adi_adrv9001_arm_Memory_Read, device, addr, calVal, size, 0); + memcpy(calVal, memStartAddress, ADI_ADRV9001_WB_MAX_NUM_COEFF); + memStartAddress+= ADI_ADRV9001_WB_MAX_NUM_COEFF; + } + } + } ADI_API_RETURN(device); } -int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Set(adi_adrv9001_Device_t *device, +int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_MaxArray_Set(adi_adrv9001_Device_t *device, adi_adrv9001_Warmboot_Coeff_t *savedCals, uint32_t maskChannel1, uint32_t maskChannel2) { - uint32_t tblSize[4]; #ifndef __KERNEL__ - uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY] = { 0 }; + uint32_t tblSize[4]; + uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_BYTES] = { 0 }; uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; #else + static uint32_t tblSize[4]; static uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY]; static uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; #endif - int calNo; + int calNo; ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0]*16, 1); @@ -865,5 +952,48 @@ int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_Set(adi_adrv9001_Device } } + ADI_API_RETURN(device); +} +int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_UniqueArray_Set(adi_adrv9001_Device_t *device, + char *memStartAddress, + uint32_t maskChannel1, + uint32_t maskChannel2) +{ +#ifndef __KERNEL__ + uint32_t tblSize[4]; + uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_BYTES] = { 0 }; + uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; +#else + static uint32_t tblSize[4]; + static uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY]; + static uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; +#endif + int calNo; + + ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); + ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0] * 16, 1); + + for (calNo = 0; calNo < tblSize[0]; calNo++) + { + uint32_t addr = vecTbl[4*calNo]; + uint32_t size = vecTbl[(4*calNo) + 1]; + uint32_t initMask = vecTbl[(4*calNo) + 2]; + uint32_t profMask = vecTbl[(4*calNo) + 3]; + adi_common_ChannelNumber_e channel; + for (channel = ADI_CHANNEL_1; channel <= ADI_CHANNEL_2; channel++) + { + uint32_t chInitMask = maskChannel1; + profMask = profMask >> (8 * (channel - 1)); + if (profMask == 0) + continue; + if (((initMask & chInitMask) != 0) && ((profMask & device->devStateInfo.chProfEnMask[channel - 1]) != 0)) + { + memcpy(memStartAddress, calVal, ADI_ADRV9001_WB_MAX_NUM_COEFF); + ADI_EXPECT(adi_adrv9001_arm_Memory_Write, device, addr, calVal, size, 0); + memStartAddress += ADI_ADRV9001_WB_MAX_NUM_COEFF; + } + } + } + ADI_API_RETURN(device); } \ No newline at end of file diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c index 43bd89095b9ee3..f0d9e35ecc1bcd 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_dpd.c @@ -150,6 +150,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_dpd_Configure_Validate static const uint32_t DPD_MAX_SAMPLES = 4096; static const uint32_t MAX_RX_TX_NORMALIZATION_THRESHOLD_U2D30 = 1 << 30; // 1.0 in U2.30 static const uint32_t MAX_TIME_FILTER_COEFFICIENT = 0x7FFFFFFF; // 0.999... in U1.31 + static const uint32_t DPD_MAX_CAPTURE_DELAY_US = 1000000; ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); @@ -161,6 +162,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_dpd_Configure_Validate ADI_RANGE_CHECK(adrv9001, dpdConfig->countsGreaterThanPeakThreshold, 0, 4096); ADI_RANGE_CHECK(adrv9001, dpdConfig->timeFilterCoefficient, 0, MAX_TIME_FILTER_COEFFICIENT); ADI_RANGE_CHECK(adrv9001, dpdConfig->clgcLoopOpen, 0, 1); + ADI_RANGE_CHECK(adrv9001, dpdConfig->captureDelay_us, 0, DPD_MAX_CAPTURE_DELAY_US); ADI_API_RETURN(adrv9001); } @@ -169,7 +171,7 @@ int32_t adi_adrv9001_dpd_Configure(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_DpdCfg_t *dpdConfig) { - uint8_t armData[64] = { 0 }; + uint8_t armData[68] = { 0 }; uint8_t extData[5] = { 0 }; uint32_t offset = 0; @@ -200,7 +202,9 @@ int32_t adi_adrv9001_dpd_Configure(adi_adrv9001_Device_t *adrv9001, adrv9001_LoadFourBytes(&offset, armData, dpdConfig->clgcGainTarget_HundredthdB); adrv9001_LoadFourBytes(&offset, armData, dpdConfig->clgcFilterAlpha); offset += 8; /* space for clgcLastGain_HundredthdB & clgcFilteredGain_HundredthdB , which are read-only */ - + adrv9001_LoadFourBytes(&offset, armData, dpdConfig->captureDelay_us); + + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_TX, channel); extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_TC_TX_DPD; @@ -224,7 +228,7 @@ int32_t adi_adrv9001_dpd_Inspect(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_DpdCfg_t *dpdConfig) { - uint8_t armReadBack[60] = { 0 }; + uint8_t armReadBack[68] = { 0 }; uint8_t channelMask = 0; uint32_t offset = 0; @@ -258,6 +262,8 @@ int32_t adi_adrv9001_dpd_Inspect(adi_adrv9001_Device_t *adrv9001, adrv9001_ParseFourBytes(&offset, armReadBack, &dpdConfig->clgcFilterAlpha); adrv9001_ParseFourBytes(&offset, armReadBack, (uint32_t*)&dpdConfig->clgcLastGain_HundredthdB); adrv9001_ParseFourBytes(&offset, armReadBack, (uint32_t*)&dpdConfig->clgcFilteredGain_HundredthdB); + adrv9001_ParseFourBytes(&offset, armReadBack, (uint32_t*)&dpdConfig->captureDelay_us); + ADI_API_RETURN(adrv9001); } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c index 299e0b62998b32..53f17306deb561 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_fh.c @@ -59,7 +59,7 @@ if (device->devStateInfo.frequencyHoppingEnabled == 0) \ ADI_API_RETURN(device); \ } -/* TODO JP: Determine if we need to validate the whole table. +/* TODO JP: Determine if we need to validate the whole table. It's difficult to validate the hop table due to the following: 1) At the time of receiving the HOP table, we don't know the channel sequence. So a tx or rx gain index might be valid, or it might be a 'don't care' value, programmed by the user. We could potentially enforce the @@ -67,7 +67,7 @@ if (device->devStateInfo.frequencyHoppingEnabled == 0) \ 2) There doesn't seem a nice way to validate the rx gain in API, since there is no state of the FH operating gain range. The best we could do would be to ensure its within the absolute min/max. However, this could be effected by point 1. - 3) Validating the whole table before its written to ARM might be valuable, however, it might + 3) Validating the whole table before its written to ARM might be valuable, however, it might also waste time. Especially considering we can't validate every field in the table. It might be better for ARM to validate it once received, or on the fly. */ @@ -77,8 +77,8 @@ static __maybe_unused int32_t adi_adrv9001_fh_FrameInfo_Validate(adi_adrv9001_De /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); - ADI_RANGE_CHECK_X(adrv9001, hopFrame->hopFrequencyHz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, hopFrame->hopFrequencyHz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); ADI_API_RETURN(adrv9001); } @@ -97,11 +97,11 @@ static uint32_t adi_adrv9001_fh_GetHopTableBufferAddress(adi_adrv9001_Device_t * adrv9001_ParseFourBytes(&offset, hopTableBufferAddressBlock, &hopTableBufferAddress); return hopTableBufferAddress; -} +} static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) -{ +{ uint32_t i; uint32_t j; uint8_t numHopSignals; @@ -141,7 +141,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } /* Can be unassigned but throw an error if it's set to analog*/ ADI_RANGE_CHECK(adrv9001, fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[0].pin, ADI_ADRV9001_GPIO_UNASSIGNED, ADI_ADRV9001_GPIO_DIGITAL_15); - if ((fhConfig->hopTableSelectConfig.hopTableSelectMode == ADI_ADRV9001_FHHOPTABLESELECTMODE_INDEPENDENT) + if ((fhConfig->hopTableSelectConfig.hopTableSelectMode == ADI_ADRV9001_FHHOPTABLESELECTMODE_INDEPENDENT) && (fhConfig->mode == ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP)) { /* Can be unassigned but throw an error if it's set to analog*/ @@ -186,18 +186,18 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De "Value must be non-zero in Tx only operation"); ADI_API_RETURN(adrv9001); } - + /* Check mode*/ ADI_RANGE_CHECK(adrv9001, fhConfig->mode, ADI_ADRV9001_FHMODE_LO_MUX_PREPROCESS, ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP); /* Check tableIndexCtrl_e */ ADI_RANGE_CHECK(adrv9001, fhConfig->tableIndexCtrl, ADI_ADRV9001_TABLEINDEXCTRL_AUTO_LOOP, ADI_ADRV9001_TABLEINDEXCTRL_GPIO); /* Check operating frequency range */ - ADI_RANGE_CHECK_X(adrv9001, fhConfig->minOperatingFrequency_Hz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, fhConfig->minOperatingFrequency_Hz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); - ADI_RANGE_CHECK_X(adrv9001, fhConfig->maxOperatingFrequency_Hz, - ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, + ADI_RANGE_CHECK_X(adrv9001, fhConfig->maxOperatingFrequency_Hz, + ADI_ADRV9001_FH_MIN_CARRIER_FREQUENCY_HZ, ADI_ADRV9001_FH_MAX_CARRIER_FREQUENCY_HZ, "%llu"); if (fhConfig->minOperatingFrequency_Hz >= fhConfig->maxOperatingFrequency_Hz) @@ -211,12 +211,12 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De ADI_API_RETURN(adrv9001); } /* Check RX gain ranges */ - ADI_RANGE_CHECK(adrv9001, fhConfig->minRxGainIndex, - ADI_ADRV9001_RX_GAIN_INDEX_MIN, + ADI_RANGE_CHECK(adrv9001, fhConfig->minRxGainIndex, + ADI_ADRV9001_RX_GAIN_INDEX_MIN, fhConfig->maxRxGainIndex); /* Max index can be equal to min and no greater than rx1MaxGainIndex */ - ADI_RANGE_CHECK(adrv9001, fhConfig->maxRxGainIndex, - fhConfig->minRxGainIndex, + ADI_RANGE_CHECK(adrv9001, fhConfig->maxRxGainIndex, + fhConfig->minRxGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); /* TODO JP: Investigate requirements for TX attenuation in diversity mode. Will min/max be the same, or will we need a seperate field? @@ -245,7 +245,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } /* Check frequency select pins */ - if (ADI_ADRV9001_TABLEINDEXCTRL_GPIO == fhConfig->tableIndexCtrl) + if (ADI_ADRV9001_TABLEINDEXCTRL_GPIO == fhConfig->tableIndexCtrl) { ADI_RANGE_CHECK(adrv9001, fhConfig->numTableIndexPins, 1u, ADI_ADRV9001_FH_MAX_NUM_FREQ_SELECT_PINS); for (i = 0; i < fhConfig->numTableIndexPins; i++) @@ -254,13 +254,13 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De } } /* Configure gain select pins */ - if (true == fhConfig->gainSetupByPin) + if (true == fhConfig->gainSetupByPin) { for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) { if ((initializedChannelMask & (j == 0? channel1Mask:channel2Mask)) != 0x00u) { - + ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].numGainCtrlPins, 1u, ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_PINS); for (i = 0; i < fhConfig->gainSetupByPinConfig[j].numGainCtrlPins; i++) { @@ -269,7 +269,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De maxPossibleGainEntries = (1u << fhConfig->gainSetupByPinConfig[j].numGainCtrlPins); } - + if (ADRV9001_BF_EQUAL(adrv9001->devStateInfo.initializedChannels, CHANNELS[ADI_RX][j])) { /* Validate Rx gain table is within range specified by fhConfig */ @@ -287,7 +287,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De { ADI_RANGE_CHECK(adrv9001, fhConfig->gainSetupByPinConfig[j].txAttenTable[i], fhConfig->minTxAtten_mdB, fhConfig->maxTxAtten_mdB); } - } + } } } @@ -296,7 +296,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Configure_Validate(adi_adrv9001_De static __maybe_unused int32_t adi_adrv9001_fh_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) -{ +{ /* Check for NULL pointer */ ADI_NULL_PTR_RETURN(&adrv9001->common, fhConfig); ADI_API_RETURN(adrv9001); @@ -305,7 +305,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_Inspect_Validate(adi_adrv9001_Devi static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhMode_e mode, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t tableSize) { @@ -356,7 +356,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate ADI_API_RETURN(adrv9001); } - if ((hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_2) + if ((hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_2) && (mode != ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP)) { ADI_ERROR_REPORT(&adrv9001->common, @@ -368,7 +368,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate ADI_API_RETURN(adrv9001); } - + /* Check fhHopTable->numHopFrames are valid */ ADI_RANGE_CHECK(adrv9001, tableSize, 1u, maxNumHopFrequencies); @@ -378,7 +378,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Static_Configure_Validate } ADI_API_RETURN(adrv9001); -} +} static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal, @@ -430,7 +430,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Inspect_Validate(adi_adrv } ADI_API_RETURN(adrv9001); -} +} int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhCfg_t *fhConfig) @@ -476,7 +476,7 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, armData[offset++] = fhConfig->tableIndexCtrl; armData[offset++] = fhConfig->gainSetupByPin; armData[offset++] = fhConfig->hopTableSelectConfig.hopTableSelectMode; - + armData[offset++] = hop1SignalsPortMask; armData[offset++] = hop2SignalsPortMask; @@ -493,16 +493,17 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, adrv9001_LoadFourBytes(&offset, armData, fhConfig->minFrameDuration_us); armData[offset++] = fhConfig->txAnalogPowerOnFrameDelay; armData[offset++] = fhConfig->rxZeroIfEnable; - offset += 2u; /* padding */ + armData[offset++] = fhConfig->enableAGCGainIndexSeeding; + offset += 1u; /* padding */ /* If in gain select by pin mode, load Rx gain and Tx attenuation tables */ - if (fhConfig->gainSetupByPin == true) + if (fhConfig->gainSetupByPin == true) { /* Load Rx gain and Tx atten table */ armData[offset++] = fhConfig->gainSetupByPinConfig[0].numRxGainTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[1].numRxGainTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[0].numTxAttenTableEntries; armData[offset++] = fhConfig->gainSetupByPinConfig[1].numTxAttenTableEntries; - /* Create a second offset variable to point to the Tx atten table location. + /* Create a second offset variable to point to the Tx atten table location. Rx gain index is 1 byte, so second offset is offset + (ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES * 1) */ tempOffset = offset + 2 * ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; @@ -577,7 +578,7 @@ int32_t adi_adrv9001_fh_Configure(adi_adrv9001_Device_t *adrv9001, } } /* Configure gain index pins if selected */ - if (fhConfig->gainSetupByPin == true) + if (fhConfig->gainSetupByPin == true) { /* Configure ADRV9001 GPIOs */ for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) @@ -636,7 +637,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a fhConfig->tableIndexCtrl = armData[offset++]; fhConfig->gainSetupByPin = armData[offset++]; fhConfig->hopTableSelectConfig.hopTableSelectMode = armData[offset++]; - + hop1SignalsPortMask = armData[offset++]; offset++; fhConfig->rxPortHopSignals[0] = ((hop1SignalsPortMask & 0x1) == 1) ? ADI_ADRV9001_FH_HOP_SIGNAL_1 : ADI_ADRV9001_FH_HOP_SIGNAL_2; @@ -654,7 +655,8 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a adrv9001_ParseFourBytes(&offset, armData, &fhConfig->minFrameDuration_us); fhConfig->txAnalogPowerOnFrameDelay = armData[offset++]; fhConfig->rxZeroIfEnable = armData[offset++]; - offset += 2u; + fhConfig->enableAGCGainIndexSeeding = armData[offset++]; + offset += 1u; /* Get gain setup by pin information */ if (fhConfig->gainSetupByPin) { @@ -666,7 +668,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a { fhConfig->gainSetupByPinConfig[j].numTxAttenTableEntries = armData[offset++]; } - + tempOffset = offset + 2 * ADI_ADRV9001_FH_MAX_NUM_GAIN_SELECT_ENTRIES; /* Rx and Tx tables */ for (j = 0; j < ADI_ADRV9001_NUM_CHANNELS; j++) @@ -703,13 +705,13 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP, &(fhConfig->hopSignalGpioConfig[0])); ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_TABLE_SELECT, &(fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[0])); - + if (fhConfig->mode == ADI_ADRV9001_FHMODE_LO_RETUNE_REALTIME_PROCESS_DUAL_HOP) { ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2, &(fhConfig->hopSignalGpioConfig[1])); ADI_EXPECT(adi_adrv9001_gpio_Inspect, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP_2_TABLE_SELECT, &(fhConfig->hopTableSelectConfig.hopTableSelectGpioConfig[1])); } - + /* Inspect table index pins if selected */ if (fhConfig->tableIndexCtrl == ADI_ADRV9001_TABLEINDEXCTRL_GPIO) { @@ -732,7 +734,7 @@ int32_t adi_adrv9001_fh_Configuration_Inspect(adi_adrv9001_Device_t *adrv9001, a int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhMode_e mode, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t hopTableSize) { @@ -742,7 +744,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 uint32_t frequencyIndex = 0; uint8_t numHopTableEntries[4u]; uint32_t hopTableBufferAddress = 0; - + /* ARM Data is written directly to ARM memory because FREQ_HOPPING_NUM_BYTES is greater than set buffer size */ #ifndef __KERNEL__ uint8_t armData[FREQ_HOPPING_MAX_NUM_BYTES] = { 0 }; @@ -780,8 +782,8 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 hopTableAddress = adrv9001->devStateInfo.fhHopTableB2Addr; hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB2Addr; } - } - + } + adrv9001_LoadFourBytes(&offset, numHopTableEntries, hopTableSize); offset = 0; for (frequencyIndex = 0; frequencyIndex < hopTableSize; frequencyIndex++) @@ -796,7 +798,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 armData[offset++] = hopTable[frequencyIndex].tx1Attenuation_fifthdB; armData[offset++] = hopTable[frequencyIndex].tx2Attenuation_fifthdB; } - + /* Write the data directly to the ARM memory */ /* 'offset' is used to represent the exact number of bytes to write to avoid writing over the entire table */ ADI_EXPECT(adi_adrv9001_arm_Memory_WriteFH, adrv9001, hopSignal, tableId, hopTableAddress, numHopTableEntries, sizeof(numHopTableEntries), hopTableBufferAddress, armData, offset); @@ -805,7 +807,7 @@ int32_t adi_adrv9001_fh_HopTable_Static_Configure(adi_adrv9001_Device_t *adrv900 int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal, - adi_adrv9001_FhHopTable_e tableId, + adi_adrv9001_FhHopTable_e tableId, adi_adrv9001_FhHopFrame_t hopTable[], uint32_t hopTableSize, uint32_t *numHopFramesRead) @@ -832,7 +834,7 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, memset(&armData, 0, sizeof(armData)); #endif - + if (tableId == ADI_ADRV9001_FHHOPTABLE_A) { if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) @@ -858,10 +860,10 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, hopTableAddress = adrv9001->devStateInfo.fhHopTableB2Addr; hopTableBufferAddress = adrv9001->devStateInfo.fhHopTableBufferB2Addr; } - } + } ADI_PERFORM_VALIDATION(adi_adrv9001_fh_HopTable_Inspect_Validate, adrv9001, hopSignal, tableId, hopTable, hopTableSize); - /* Even though we are going to read directly from ARM memory, we can still use the GET protocol to + /* Even though we are going to read directly from ARM memory, we can still use the GET protocol to tell ARM how many bytes we will read. ARM will return an error if the read size is invalid */ adrv9001_LoadFourBytes(&offset, armData, sizeof(armData)); @@ -877,7 +879,7 @@ int32_t adi_adrv9001_fh_HopTable_Inspect(adi_adrv9001_Device_t *adrv9001, OBJID_GO_GET_FH_HOP_TABLE, ADI_ADRV9001_DEFAULT_TIMEOUT_US, ADI_ADRV9001_DEFAULT_INTERVAL_US); - + /* First read number of frequencies in hop table */ offset = 0; ADI_EXPECT(adi_adrv9001_arm_Memory_Read, adrv9001, hopTableAddress, numHopFrequenciesReadbackBlock, sizeof(numHopFrequenciesReadbackBlock), false); @@ -979,12 +981,12 @@ int32_t adi_adrv9001_fh_HopTable_Get(adi_adrv9001_Device_t *adrv9001, ADI_API_RETURN(adrv9001); } -int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, - adi_adrv9001_FhHopSignal_e fhHopSignal, - adi_adrv9001_FhFrameIndex_e frameIndex, - adi_adrv9001_FhHopFrame_t *hopFrame) +int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, + adi_adrv9001_FhHopSignal_e fhHopSignal, + adi_adrv9001_FhFrameIndex_e frameIndex, + adi_adrv9001_FhHopFrame_t *hopFrame) { - uint8_t armData[sizeof(adrv9001_FhHopFrame_t)] = { 0 }; + uint8_t armData[sizeof(adrv9001_FhHopFrame_t)] = { 0 }; uint8_t extData[5u] = { 0 }; uint32_t offset = 0; uint32_t hopFrequencyHz_LSB = 0; @@ -993,10 +995,10 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, /* Check if FH is enabled in device profile */ ADI_FH_CHECK_FH_ENABLED(adrv9001); ADI_NULL_PTR_RETURN(&adrv9001->common, hopFrame); - ADI_RANGE_CHECK(adrv9001, fhHopSignal, ADI_ADRV9001_FH_HOP_SIGNAL_1, ADI_ADRV9001_FH_HOP_SIGNAL_2); - ADI_RANGE_CHECK(adrv9001, frameIndex, ADI_ADRV9001_FHFRAMEINDEX_CURRENT_FRAME, ADI_ADRV9001_FHFRAMEINDEX_UPCOMING_FRAME); - - + ADI_RANGE_CHECK(adrv9001, fhHopSignal, ADI_ADRV9001_FH_HOP_SIGNAL_1, ADI_ADRV9001_FH_HOP_SIGNAL_2); + ADI_RANGE_CHECK(adrv9001, frameIndex, ADI_ADRV9001_FHFRAMEINDEX_CURRENT_FRAME, ADI_ADRV9001_FHFRAMEINDEX_UPCOMING_FRAME); + + /* Write the size to the GET buffer */ adrv9001_LoadFourBytes(&offset, armData, sizeof(armData)); ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_GET, armData, sizeof(uint32_t), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); @@ -1029,9 +1031,9 @@ int32_t adi_adrv9001_fh_FrameInfo_Inspect(adi_adrv9001_Device_t *adrv9001, hopFrame->tx1Attenuation_fifthdB = armData[offset++]; hopFrame->tx2Attenuation_fifthdB = armData[offset++]; ADI_API_RETURN(adrv9001); -} +} -int32_t adi_adrv9001_fh_Hop(adi_adrv9001_Device_t *adrv9001, +int32_t adi_adrv9001_fh_Hop(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_FhHopSignal_e hopSignal) { /* Flip the hop signal */ @@ -1068,7 +1070,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_NumberOfHops_Get(adi_adrv9001_Devi default: ADI_SHOULD_NOT_EXECUTE(adrv9001); } - + ADI_API_RETURN(adrv9001); } @@ -1100,7 +1102,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure_Validat mode, "FH mode must be dual hop for hopSignal to be HOP_2 "); } - + } ADI_ENTRY_PTR_EXPECT(adrv9001, spiPackedFhTable); @@ -1128,7 +1130,7 @@ static __maybe_unused int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure_Validat ADI_COMMON_ACT_ERR_CHECK_PARAM, tableSize, "spiPackedFhTable[] size is not sufficient "); - + } for (frequencyIndex = 0; frequencyIndex < tableSize; frequencyIndex++) { @@ -1205,7 +1207,7 @@ static uint32_t adrv9001_HopTable_Spi_Pack(adi_adrv9001_Device_t *adrv9001, /* Issue SW interrupt 4 or 11 to load FH table A or B. The SPI reg is self-cleared so there is no need to do read/mod/write. */ adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADRV9001_ADDR_SW_INTERRUPT_4, bitmSwInt, ADRV9001_SPI_WRITE_POLARITY); - + /* Restore back the original values of ADRV9001 DMA control register */ adi_adrv9001_HopTable_Spi_DataPack(spiPackedFhTable, numWrBytes, ADRV9001_ADDR_ARM_DMA_CTL, regVal, ADRV9001_SPI_WRITE_POLARITY); @@ -1245,10 +1247,10 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 if (ADI_ADRV9001_FH_HOP_SIGNAL_1 == hopSignal) { bitmSwInt_A = 0x1; - hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; armAddr_A = adrv9001->devStateInfo.fhHopTableA1Addr; - bitmSwInt_B = 0x80; + bitmSwInt_B = 0x80; hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; armAddr_B = adrv9001->devStateInfo.fhHopTableB1Addr; } @@ -1265,12 +1267,12 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 } else { - bitmSwInt_A = 0x1; - hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; + bitmSwInt_A = 0x1; + hopTableBufferAddress_A = adrv9001->devStateInfo.fhHopTableBufferA1Addr; armAddr_A = adrv9001->devStateInfo.fhHopTableA1Addr; - bitmSwInt_B = 0x2; - hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; + bitmSwInt_B = 0x2; + hopTableBufferAddress_B = adrv9001->devStateInfo.fhHopTableBufferB1Addr; armAddr_B = adrv9001->devStateInfo.fhHopTableB1Addr; } @@ -1307,11 +1309,11 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 adrv9001_LoadFourBytes(&offset, fhTable_A, hopTable[i + j].rx2OffsetFrequencyHz); fhTable_A[offset++] = hopTable[i + j].rx1GainIndex; fhTable_A[offset++] = hopTable[i + j].rx2GainIndex; - adrv9001_LoadTwoBytes(&offset, fhTable_A, hopTable[i + j].tx1Attenuation_fifthdB); - adrv9001_LoadTwoBytes(&offset, fhTable_A, hopTable[i + j].tx2Attenuation_fifthdB); + fhTable_A[offset++] = hopTable[i + j].tx1Attenuation_fifthdB; + fhTable_A[offset++] = hopTable[i + j].tx2Attenuation_fifthdB; } ADI_EXPECT(adrv9001_HopTable_Spi_Pack, adrv9001, addrArray_A, fhTable_A, numberOfHops, &numWrBytes, bitmSwInt_A, spiPackedFhTable); - + offset = 0; for (j = numberOfHops; j < (2 * numberOfHops); j++) { @@ -1321,8 +1323,8 @@ int32_t adi_adrv9001_fh_HopTable_Dynamic_Configure(adi_adrv9001_Device_t *adrv90 adrv9001_LoadFourBytes(&offset, fhTable_B, hopTable[i + j].rx2OffsetFrequencyHz); fhTable_B[offset++] = hopTable[i + j].rx1GainIndex; fhTable_B[offset++] = hopTable[i + j].rx2GainIndex; - adrv9001_LoadTwoBytes(&offset, fhTable_B, hopTable[i + j].tx1Attenuation_fifthdB); - adrv9001_LoadTwoBytes(&offset, fhTable_B, hopTable[i + j].tx2Attenuation_fifthdB); + fhTable_B[offset++] = hopTable[i + j].tx1Attenuation_fifthdB; + fhTable_B[offset++] = hopTable[i + j].tx2Attenuation_fifthdB; } ADI_EXPECT(adrv9001_HopTable_Spi_Pack, adrv9001, addrArray_B, fhTable_B, numberOfHops, &numWrBytes, bitmSwInt_B, spiPackedFhTable); } @@ -1357,7 +1359,7 @@ int32_t adi_adrv9001_fh_HopTable_BytesPerTable_Get(adi_adrv9001_Device_t *adrv90 ADI_EXPECT(adi_adrv9001_fh_NumberOfHops_Get, adrv9001, numberHopsPerDynamicLoad, &numberOfHops); spiPackBytesPerTable = spiConfigBytes + spiAddrPackLength + spiInterruptBytes; - + payloadBytes = ((sizeof(adrv9001_FhHopFrame_t) * numberOfHops) + fhBytesLength) * 3; *bytesPerTable = payloadBytes + spiPackBytesPerTable; @@ -1371,7 +1373,7 @@ int32_t adi_adrv9001_fh_RxOffsetFrequency_Set(adi_adrv9001_Device_t *adrv9001, a adrv9001_LoadFourBytes(&offset, rxOffsetFrequencyHzArray, rx2OffsetFrequencyHz); if (hopSignal == ADI_ADRV9001_FH_HOP_SIGNAL_1) { - + ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, FREQ_HOPPING_HOP1_OFFSET_FREQ_OVERWRITE_ADDR, rxOffsetFrequencyHzArray, sizeof(rxOffsetFrequencyHzArray), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); } else diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c index 41915478780e93..421451574a04ce 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_gpio.c @@ -225,15 +225,15 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_gpio_ManualAnalogInput } static __maybe_unused int32_t adi_adrv9001_gpio_PinDirection_Get_Validate(adi_adrv9001_Device_t *device, - adi_adrv9001_GpioPin_e pin) + adi_adrv9001_GpioPin_e pin) { ADI_API_RETURN(device); ADI_RANGE_CHECK(device, pin, ADI_ADRV9001_GPIO_DIGITAL_00, ADI_ADRV9001_GPIO_ANALOG_11); } int32_t adi_adrv9001_gpio_PinDirection_Get(adi_adrv9001_Device_t *device, - adi_adrv9001_GpioPin_e pin, - adi_adrv9001_GpioPinDirection_e *direction) + adi_adrv9001_GpioPin_e pin, + adi_adrv9001_GpioPinDirection_e *direction) { uint16_t gpioOutEn = 0; @@ -241,12 +241,12 @@ int32_t adi_adrv9001_gpio_PinDirection_Get(adi_adrv9001_Device_t *device, if (ADI_ADRV9001_GPIO_DIGITAL_00 <= pin && pin <= ADI_ADRV9001_GPIO_DIGITAL_15) { ADI_EXPECT(adrv9001_NvsRegmapCore_NvsGpioDirectionControlOe_Get, device, &gpioOutEn); - *direction = (gpioOutEn & (1 << (pin - 1))) >> (pin - 1); + *direction = (gpioOutEn & (1 << (pin - 1))) >> (pin - 1); } else if (ADI_ADRV9001_GPIO_ANALOG_00 <= pin && pin <= ADI_ADRV9001_GPIO_ANALOG_11) { ADI_EXPECT(adrv9001_NvsRegmapCore1_NvsGpioAnalogDirectionControlOe_Get, device, &gpioOutEn); - *direction = (gpioOutEn & (1 << (pin - ADI_ADRV9001_GPIO_ANALOG_00))) >> (pin - ADI_ADRV9001_GPIO_ANALOG_00); + *direction = (gpioOutEn & (1 << (pin - ADI_ADRV9001_GPIO_ANALOG_00))) >> (pin - ADI_ADRV9001_GPIO_ANALOG_00); } else { @@ -369,6 +369,14 @@ int32_t adi_adrv9001_gpio_ControlInit_Configure(adi_adrv9001_Device_t *adrv9001, { ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_FH_HOP2_NCO_ASYNC_CHANGE, &initCfg->fh_update_rx_nco[1]); } + if (ADI_ADRV9001_GPIO_UNASSIGNED != initCfg->rx_interfaceGain_seed_save[0].pin) + { + ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_RX1_INTERFACEGAIN_SEED_SAVE, &initCfg->rx_interfaceGain_seed_save[0]); + } + if (ADI_ADRV9001_GPIO_UNASSIGNED != initCfg->rx_interfaceGain_seed_save[1].pin) + { + ADI_EXPECT(adi_adrv9001_gpio_Configure, adrv9001, ADI_ADRV9001_GPIO_SIGNAL_RX2_INTERFACEGAIN_SEED_SAVE, &initCfg->rx_interfaceGain_seed_save[1]); + } ADI_API_RETURN(adrv9001); } diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c index 3e3e0bfa9fee53..9eecb7b383bc8d 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_rx.c @@ -1,8 +1,12 @@ /** * \file -* \brief Functions for configuring receiver (Rx) features +* \brief Receiver (Rx) functions * -* Copyright 2015 - 2021 Analog Devices Inc. +* ADRV9001 API Version: $ADI_ADRV9001_API_VERSION$ +*/ + +/** +* Copyright 2022 Analog Devices Inc. * Released under the ADRV9001 API license, for more information * see the "LICENSE.txt" file in this zip file. */ @@ -98,7 +102,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Write_Val // Maximum combined gain step must not exceed 29000 mdB ADI_RANGE_CHECK(device, totalGainSteps, 0, 29000); } - + /*Check that the gain index offset is within range*/ ADI_RANGE_CHECK(device, gainIndexOffset, ADI_ADRV9001_MIN_RX_GAIN_TABLE_INDEX, ADI_ADRV9001_START_RX_GAIN_INDEX); @@ -126,7 +130,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Write_Val } ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + ADI_RANGE_CHECK(device, gainTableType, ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE, ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE); /*Check that Rx profile or ORx profile is valid*/ @@ -203,7 +207,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, { if (i == 0) { - lnaStepOffset = (gainIndexOffset - (lnaConfig->minGainIndex - 1)); + lnaStepOffset = (gainIndexOffset - (lnaConfig->minGainIndex - 1)); } else { @@ -227,7 +231,7 @@ int32_t adi_adrv9001_Rx_GainTable_Write(adi_adrv9001_Device_t *device, } gainTablePtr = lnaGainTable; } - + baseIndex = (gainIndexOffset - (numGainIndicesToWrite - 1)); minGainIndex = (uint8_t)baseIndex; ADI_EXPECT(adrv9001_RxGainTableFormat, device, gainTablePtr, &armDmaData[0], numGainIndicesToWrite); @@ -331,7 +335,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_GainTable_Read_Vali ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcMinimumGainIndex_Get, device, instance, &minGainIndex); ADI_RANGE_CHECK(device, gainIndexOffset, minGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); - + if (((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_RX_PROFILE_VALID)) == 0) && ((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_ORX_PROFILE_VALID)) == 0) && ((ADRV9001_BF_EQUAL(device->devStateInfo.profilesValid, ADI_ADRV9001_TX_PROFILE_VALID)) == 0)) @@ -477,7 +481,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); adi_common_channel_to_index(channel, &chan_idx); - + /* Check that Rx profile is valid */ if (0 == ADRV9001_BF_EQUAL(device->devStateInfo.initializedChannels, RX_CHANNELS[chan_idx])) { @@ -496,7 +500,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Gain_Set_Validate(a ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcMinimumGainIndex_Get, device, instance, &minGainIndex); ADI_RANGE_CHECK(device, gainIndex, minGainIndex, ADI_ADRV9001_RX_GAIN_INDEX_MAX); - + /* Save the current gain control mode and set to the required mode */ ADI_EXPECT(adi_adrv9001_Rx_GainControl_Mode_Get, device, channel, gainCtrlMode); if (ADI_ADRV9001_RX_GAIN_CONTROL_MODE_SPI != *gainCtrlMode) @@ -674,7 +678,7 @@ static __maybe_unused int32_t adi_adrv9001_Rx_InterfaceGain_Validate(adi_adrv900 adi_adrv9001_RxInterfaceGain_e rxInterfaceGainMax = ADI_ADRV9001_RX_INTERFACE_GAIN_NEGATIVE_36_DB; adi_common_channel_to_index(channel, &chan_index); - + if (device->devStateInfo.rxOutputRate_kHz[chan_index] < RX_OUTPUT_RATE_kHZ) { if (gainTableType == ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE) @@ -713,7 +717,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Confi adi_adrv9001_RxInterfaceGainCtrl_t *rxInterfaceGainCtrl) { adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&device->common, rxInterfaceGainCtrl); @@ -737,18 +741,26 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Confi ADI_RANGE_CHECK(device, rxInterfaceGainCtrl->rssiDuration, - 64, + 32, 255); ADI_RANGE_CHECK(device, rxInterfaceGainCtrl->rssiMovingAverageDuration, 1, - 10); - + 50); + ADI_RANGE_CHECK(device, + rxInterfaceGainCtrl->gainControlAutomaticThreshold_dBFS, + -30, + 0); + ADI_RANGE_CHECK(device, + rxInterfaceGainCtrl->signalPAR, + 0, + 30); + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); if (ADI_ADRV9001_CHANNEL_CALIBRATED != state) { - ADI_ERROR_REPORT(device, + ADI_ERROR_REPORT(device, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -763,7 +775,7 @@ int32_t adi_adrv9001_Rx_InterfaceGain_Configure(adi_adrv9001_Device_t *device, adi_common_ChannelNumber_e channel, adi_adrv9001_RxInterfaceGainCtrl_t *rxInterfaceGainCtrl) { - uint8_t armData[8] = { 0 }; + uint8_t armData[12] = { 0 }; uint8_t extData[5] = { 0 }; ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_InterfaceGain_Configure_Validate, device, channel, rxInterfaceGainCtrl); @@ -774,8 +786,9 @@ int32_t adi_adrv9001_Rx_InterfaceGain_Configure(adi_adrv9001_Device_t *device, armData[3] = (uint8_t)(rxInterfaceGainCtrl->gain); armData[4] = (uint8_t)(rxInterfaceGainCtrl->rssiDuration); armData[5] = (uint8_t)(rxInterfaceGainCtrl->rssiMovingAverageDuration); - armData[6] = (uint8_t)(rxInterfaceGainCtrl->reserved1); - armData[7] = (uint8_t)(rxInterfaceGainCtrl->reserved2); + armData[6] = (uint8_t)(rxInterfaceGainCtrl->gainControlAutomaticThreshold_dBFS); + armData[7] = (uint8_t)(rxInterfaceGainCtrl->signalPAR); + armData[8] = (uint8_t)(rxInterfaceGainCtrl->enableFastAttack); /* Write RX interface gain control parameters to ARM mailbox */ ADI_EXPECT(adi_adrv9001_arm_Memory_Write, device, ADRV9001_ADDR_ARM_MAILBOX_SET, &armData[0], sizeof(armData), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); @@ -827,12 +840,12 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_Set_V /* Perform Range check of allowed gain value */ ADI_EXPECT(adi_adrv9001_Rx_InterfaceGain_Validate, device, channel, gainTableType, gain); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); if ((ADI_ADRV9001_CHANNEL_PRIMED != state) && (ADI_ADRV9001_CHANNEL_RF_ENABLED != state)) { - ADI_ERROR_REPORT(device, + ADI_ERROR_REPORT(device, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_API_FAIL, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -913,7 +926,7 @@ int32_t adi_adrv9001_Rx_InterfaceGain_Inspect(adi_adrv9001_Device_t *device, adi_adrv9001_RxInterfaceGainCtrl_t *rxInterfaceGainCtrl, adi_adrv9001_RxGainTableType_e *gainTableType) { - uint8_t armReadBack[8] = { 0 }; + uint8_t armReadBack[12] = { 0 }; uint8_t extData[5] = { 0 }; ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_InterfaceGain_Inspect_Validate, device, channel, rxInterfaceGainCtrl, gainTableType); @@ -940,12 +953,15 @@ int32_t adi_adrv9001_Rx_InterfaceGain_Inspect(adi_adrv9001_Device_t *device, sizeof(armReadBack), ADRV9001_ARM_MEM_READ_AUTOINCR) - rxInterfaceGainCtrl->updateInstance = (adi_adrv9001_RxInterfaceGainUpdateTiming_e)armReadBack[0]; - rxInterfaceGainCtrl->controlMode = (adi_adrv9001_RxInterfaceGainCtrlMode_e)armReadBack[1]; - *gainTableType = (adi_adrv9001_RxGainTableType_e)armReadBack[2]; - rxInterfaceGainCtrl->gain = (adi_adrv9001_RxInterfaceGain_e)armReadBack[3]; - rxInterfaceGainCtrl->rssiDuration = armReadBack[4]; - rxInterfaceGainCtrl->rssiMovingAverageDuration = armReadBack[5]; + rxInterfaceGainCtrl->updateInstance = (adi_adrv9001_RxInterfaceGainUpdateTiming_e)armReadBack[0]; + rxInterfaceGainCtrl->controlMode = (adi_adrv9001_RxInterfaceGainCtrlMode_e)armReadBack[1]; + *gainTableType = (adi_adrv9001_RxGainTableType_e)armReadBack[2]; + rxInterfaceGainCtrl->gain = (adi_adrv9001_RxInterfaceGain_e)armReadBack[3]; + rxInterfaceGainCtrl->rssiDuration = armReadBack[4]; + rxInterfaceGainCtrl->rssiMovingAverageDuration = armReadBack[5]; + rxInterfaceGainCtrl->gainControlAutomaticThreshold_dBFS = armReadBack[6]; + rxInterfaceGainCtrl->signalPAR = armReadBack[7]; + rxInterfaceGainCtrl->enableFastAttack = armReadBack[8]; ADI_API_RETURN(device); } @@ -1019,6 +1035,111 @@ int32_t adi_adrv9001_Rx_InterfaceGain_Get(adi_adrv9001_Device_t *device, ADI_API_RETURN(device); } +static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_InterfaceGain_SeedGain_Set_Validate( adi_adrv9001_Device_t *device, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxInterfaceGain_e seedGain) +{ + adi_adrv9001_RxInterfaceGainCtrl_t rxInterfaceGainCtrl = { 0 }; + adi_adrv9001_RxGainTableType_e gainTableType = ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE; + adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; + + /* Check device pointer is not null */ + ADI_NULL_DEVICE_PTR_RETURN(device); + + ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); + + ADI_EXPECT(adi_adrv9001_Rx_InterfaceGain_Inspect, device, channel, &rxInterfaceGainCtrl, &gainTableType); + + if (rxInterfaceGainCtrl.controlMode != ADI_ADRV9001_RX_INTERFACE_GAIN_CONTROL_AUTOMATIC) + { + ADI_ERROR_REPORT(&device->common, + ADI_COMMON_ERRSRC_API, + ADI_COMMON_ERR_INV_PARAM, + ADI_COMMON_ACT_ERR_CHECK_PARAM, + rxInterfaceGainCtrl->gainControlMode, + "Invalid gainControlMode - must be in Automatic mode to set the seed gain"); + + ADI_API_RETURN(device); + } + + ADI_EXPECT(adi_adrv9001_Rx_InterfaceGain_Validate, device, channel, gainTableType, seedGain); + + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_RX, channel, &state); + if ((ADI_ADRV9001_CHANNEL_CALIBRATED != state) + && (ADI_ADRV9001_CHANNEL_PRIMED != state) + && (ADI_ADRV9001_CHANNEL_RF_ENABLED != state)) + { + ADI_ERROR_REPORT(device, + ADI_COMMON_ERRSRC_API, + ADI_COMMON_ERR_API_FAIL, + ADI_COMMON_ACT_ERR_CHECK_PARAM, + state, + "Error attempting to set the seed for Rx Interface gain. Specified channel must be in CALIBRATED, PRIMED or RF_ENABLED state"); + } + + ADI_API_RETURN(device); +} + +int32_t adi_adrv9001_Rx_InterfaceGain_SeedGain_Set( adi_adrv9001_Device_t *device, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxInterfaceGain_e seedGain) +{ + uint8_t seedGainArray[4] = { 0 }; + uint32_t offset = 0; + adrv9001_LoadFourBytes(&offset, seedGainArray, seedGain); + ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_InterfaceGain_SeedGain_Set_Validate, device, channel, seedGain); + + if (channel == ADI_CHANNEL_1) + { + ADI_EXPECT(adi_adrv9001_arm_Memory_Write, device, RX1_INTERFACE_GAIN_SEED_ADDR, seedGainArray, sizeof(seedGain), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); + } + else + { + ADI_EXPECT(adi_adrv9001_arm_Memory_Write, device, RX2_INTERFACE_GAIN_SEED_ADDR, seedGainArray, sizeof(seedGain), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); + } + + ADI_API_RETURN(device); +} + +int32_t adi_adrv9001_Rx_InterfaceGain_SeedGain_Get( adi_adrv9001_Device_t *device, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxInterfaceGain_e *seedGain) +{ + uint8_t armReadBack[4] = { 0 }; + if (channel == ADI_CHANNEL_1) + { + ADI_EXPECT(adi_adrv9001_arm_Memory_Read, device, RX1_INTERFACE_GAIN_SEED_ADDR, armReadBack, sizeof(armReadBack), false); + } + else + { + ADI_EXPECT(adi_adrv9001_arm_Memory_Read, device, RX2_INTERFACE_GAIN_SEED_ADDR, armReadBack, sizeof(armReadBack), false); + } + + *seedGain = (adi_adrv9001_RxInterfaceGain_e)armReadBack[0]; + + ADI_API_RETURN(device); +} + +int32_t adi_adrv9001_Rx_InterfaceGain_EndOfFrameGain_Get( adi_adrv9001_Device_t *device, + adi_common_ChannelNumber_e channel, + adi_adrv9001_RxInterfaceGain_e *endOfFrameGain) +{ + uint8_t armReadBack[4] = { 0 }; + if (channel == ADI_CHANNEL_1) + { + + ADI_EXPECT(adi_adrv9001_arm_Memory_Read, device, RX1_INTERFACE_GAIN_END_OF_FRAME_ADDR, armReadBack, sizeof(armReadBack), false); + } + else + { + ADI_EXPECT(adi_adrv9001_arm_Memory_Read, device, RX2_INTERFACE_GAIN_END_OF_FRAME_ADDR, armReadBack, sizeof(armReadBack), false); + } + + *endOfFrameGain = (adi_adrv9001_RxInterfaceGain_e)armReadBack[0]; + + ADI_API_RETURN(device); +} + static __maybe_unused int32_t __maybe_unused adrv9001_Rx_FrequencyCorrection_Set_Validate(adi_adrv9001_Device_t *device, adi_common_ChannelNumber_e channel, int32_t frequencyOffset_Hz) @@ -1450,12 +1571,12 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_PortSwitch_Configur } /* NULL pointer check */ - ADI_NULL_PTR_RETURN(&device->common, switchConfig); + ADI_NULL_PTR_RETURN(&device->common, switchConfig); /* Freuqency range check */ - ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); - ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); - ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortA_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); + ADI_RANGE_CHECK_X(device, switchConfig->minFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); ADI_RANGE_CHECK_X(device, switchConfig->maxFreqPortB_Hz, ADI_ADRV9001_CARRIER_FREQUENCY_MIN_HZ, ADI_ADRV9001_CARRIER_FREQUENCY_MAX_HZ, "%llu"); /* Min frequency must be smaller than max */ @@ -1483,7 +1604,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_PortSwitch_Configur "Port A and B freuqency ranges cannot overlap."); ADI_API_RETURN(device) } - + ADI_API_RETURN(device); } @@ -1492,7 +1613,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Configure(adi_adrv9001_Device_t *device, { uint8_t armData[42] = { 0 }; uint8_t extData[3] = { 0 }; - uint32_t offset = 0u; + uint32_t offset = 0u; ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_PortSwitch_Configure_Validate, device, switchConfig); @@ -1517,7 +1638,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Configure(adi_adrv9001_Device_t *device, extData[0] = 0; extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_CFG_RX_PORT_SWITCHING; - + ADI_EXPECT(adi_adrv9001_arm_Config_Write, device, armData, sizeof(armData), extData, sizeof(extData)) ADI_API_RETURN(device); @@ -1540,7 +1661,7 @@ int32_t adi_adrv9001_Rx_PortSwitch_Inspect(adi_adrv9001_Device_t *device, ADI_PERFORM_VALIDATION(adi_adrv9001_Rx_PortSwitch_Inspect_Validate, device, switchConfig); ADI_EXPECT(adi_adrv9001_arm_Config_Read, device, OBJID_CFG_RX_PORT_SWITCHING, channelMask, offset, armReadBack, sizeof(armReadBack)) - + adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->minFreqPortA_Hz); adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->maxFreqPortA_Hz); adrv9001_ParseEightBytes(&offset, armReadBack, &switchConfig->minFreqPortB_Hz); @@ -1563,7 +1684,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_RANGE_CHECK(device, gainTableType, ADI_ADRV9001_RX_GAIN_CORRECTION_TABLE, ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE); ADI_NULL_PTR_RETURN(&device->common, lnaConfig); - + if (!lnaConfig->externalLnaPresent) { ADI_ERROR_REPORT(&device->common, @@ -1590,7 +1711,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu ADI_RANGE_CHECK(device, lnaConfig->numberLnaGainSteps, 2, 4); //ADI_RANGE_CHECK(device, lnaConfig->settlingDelay, 0, 0); //ADI_RANGE_CHECK(device, lnaConfig->lnaDigitalGainDelay, 0, 0); - + if(0 != lnaConfig->lnaGainSteps_mdB[0]) { ADI_ERROR_REPORT(&device->common, @@ -1601,7 +1722,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_ExternalLna_Configu "lnaConfig->lnaGainSteps_mdB[0] should have the gain step as '0' only"); ADI_ERROR_RETURN(device->common.error.newAction); } - + for (i = 1; i < lnaConfig->numberLnaGainSteps; i++) { if ((lnaConfig->lnaGainSteps_mdB[i] == 0) || ((lnaConfig->lnaGainSteps_mdB[i] % 500) != 0)) @@ -1685,12 +1806,12 @@ int32_t adi_adrv9001_Rx_ExternalLna_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapRxb_FeGainDelayIncr_Set, device, rxbAddr, (lnaConfig->lnaDigitalGainDelay + FEGAIN_INCR_FIXED_VALUE)); ADI_EXPECT(adrv9001_NvsRegmapRxb_FeGainDelayDecr_Set, device, rxbAddr, (lnaConfig->lnaDigitalGainDelay + FEGAIN_DECR_FIXED_VALUE)); ADI_EXPECT(adrv9001_NvsRegmapRx_ExtLnaDigitalGainDelay_Set, device, rxAddr, (lnaConfig->lnaDigitalGainDelay + EXTDIGGAIN_DELAY_FIXED_VALUE)); - + if (ADI_ADRV9001_RX_GAIN_COMPENSATION_TABLE == gainTableType) { ADI_EXPECT(adrv9001_NvsRegmapRx_GainCompForExtGain_Set, device, rxAddr, (uint8_t)lnaConfig->externalLnaPresent); } - + ADI_API_RETURN(device); } @@ -1778,11 +1899,11 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Loid_Configure_Vali adi_adrv9001_RadioState_t state = { 0 }; uint8_t port_index = 0; uint8_t chan_index = 0; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, loidConfig); - + /* Validate state is STANDBY or CALIBRATED*/ ADI_EXPECT(adi_adrv9001_Radio_State_Get, adrv9001, &state); adi_common_port_to_index(ADI_RX, &port_index); @@ -1817,7 +1938,7 @@ int32_t adi_adrv9001_Rx_Loid_Configure(adi_adrv9001_Device_t *adrv9001, /* Write LOID config to ARM mailbox */ ADI_EXPECT(adi_adrv9001_arm_Memory_Write, adrv9001, ADRV9001_ADDR_ARM_MAILBOX_SET, &armData[0], sizeof(armData), ADI_ADRV9001_ARM_SINGLE_SPI_WRITE_MODE_STANDARD_BYTES_4); - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_RX, channel); extData[1] = OBJID_GS_LOID; @@ -1829,14 +1950,14 @@ int32_t adi_adrv9001_Rx_Loid_Configure(adi_adrv9001_Device_t *adrv9001, extData[1], (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_TIMEOUT_US, (uint32_t)ADI_ADRV9001_RX_INTERFACE_CONTROL_INTERVAL_US); - + ADI_API_RETURN(adrv9001); } static __maybe_unused int32_t __maybe_unused adi_adrv9001_Rx_Loid_Inspect_Validate(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) -{ +{ ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, loidConfig); @@ -1848,9 +1969,9 @@ int32_t adi_adrv9001_Rx_Loid_Inspect(adi_adrv9001_Device_t *adrv9001, adi_common_ChannelNumber_e channel, adi_adrv9001_RxrfdcLoidCfg_t *loidConfig) { - uint8_t armReadBack[4] = { 0 }; + uint8_t armReadBack[4] = { 0 }; uint8_t extData[2] = { 0 }; - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_RX, channel); extData[1] = OBJID_GS_LOID; @@ -1869,9 +1990,9 @@ int32_t adi_adrv9001_Rx_Loid_Inspect(adi_adrv9001_Device_t *adrv9001, &armReadBack[0], sizeof(armReadBack), ADRV9001_ARM_MEM_READ_AUTOINCR) - + loidConfig->loidEnable = armReadBack[0]; loidConfig->loidThreshold_negdBFS = armReadBack[2] + 6; ADI_API_RETURN(adrv9001); -} \ No newline at end of file +} diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c index 6d3c0e08a254e2..1222201bd9c4b1 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_tx.c @@ -169,7 +169,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_AttenuationMode_Set currentState.channelStates[port_index][chan_index], "Error while attempting to set attenuation mode. Channel must be in STANDBY or CALIBRATED."); } - + /* Retrieve attenuation mode */ ADI_EXPECT(adi_adrv9001_Tx_AttenuationMode_Get, device, channel, &txModeRead); if (txModeRead == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) @@ -196,14 +196,14 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Set(adi_adrv9001_Device_t *device, txChannelBaseAddr = Tx_Addr_Get(channel); device->devStateInfo.txAttenMode[channel - 1] = mode; - + if (mode == ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_CLGC) { mode = ADI_ADRV9001_TX_ATTENUATION_CONTROL_MODE_SPI; } ADI_EXPECT(adrv9001_NvsRegmapTx_TxAttenMode_Set, device, txChannelBaseAddr, (uint8_t)mode); - + ADI_API_RETURN(device) } @@ -224,7 +224,7 @@ int32_t adi_adrv9001_Tx_AttenuationMode_Get(adi_adrv9001_Device_t *device, adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_AttenuationMode_Get_Validate, device, channel, mode); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, device, ADI_TX, channel, &state); if (state == ADI_ADRV9001_CHANNEL_PRIMED) { @@ -963,9 +963,9 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat { int32_t txSampleRateDiv2_Hz = 0; adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + ADI_NULL_PTR_RETURN(&adrv9001->common, tone); if (tone->enable) { @@ -984,7 +984,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat "Channel state must be CALIBRATED"); } } - + ADI_API_RETURN(adrv9001); } @@ -995,7 +995,7 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Configure(adi_adrv9001_Device_t * uint8_t armData[12] = { 0 }; uint8_t extData[5] = { 0 }; uint32_t offset = 0; - + ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_InternalToneGeneration_Configure_Validate, adrv9001, channel, tone); adrv9001_LoadFourBytes(&offset, armData, sizeof(armData) - sizeof(uint32_t)); @@ -1003,7 +1003,7 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Configure(adi_adrv9001_Device_t * armData[offset++] = tone->amplitude; offset += 2; adrv9001_LoadFourBytes(&offset, armData, tone->frequency_Hz); - + extData[0] = adi_adrv9001_Radio_MailboxChannel_Get(ADI_TX, channel); extData[1] = OBJID_GS_CONFIG; extData[2] = OBJID_CFG_TX_INTERNAL_TONE_GENERATION; @@ -1018,10 +1018,10 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat adi_adrv9001_TxInternalToneGeneration_t *tone) { adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, tone); - + ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, adrv9001, ADI_TX, channel, &state); if (ADI_ADRV9001_CHANNEL_STANDBY == state) { @@ -1032,7 +1032,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_InternalToneGenerat state, "Channel state must be any of CALIBRATED, PRIMED, RF_ENABLED"); } - + ADI_API_RETURN(adrv9001); } @@ -1043,12 +1043,12 @@ int32_t adi_adrv9001_Tx_InternalToneGeneration_Inspect(adi_adrv9001_Device_t *ad uint8_t armReadBack[8] = { 0 }; uint8_t channelMask = 0; uint32_t offset = 0; - + ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_InternalToneGeneration_Inspect_Validate, adrv9001, channel, tone); channelMask = adi_adrv9001_Radio_MailboxChannel_Get(ADI_TX, channel); ADI_EXPECT(adi_adrv9001_arm_Config_Read, adrv9001, OBJID_CFG_TX_INTERNAL_TONE_GENERATION, channelMask, offset, armReadBack, sizeof(armReadBack)); - + tone->enable = (bool)armReadBack[offset++]; tone->amplitude = (adi_adrv9001_TxInternalToneAmplitude_e)armReadBack[offset++]; offset += 2; @@ -1206,7 +1206,7 @@ static __maybe_unused int32_t __maybe_unused adi_adrv9001_Tx_PaRamp_Configure_Va { ADI_RANGE_CHECK(device, paRampCfg->gpioSource, ADI_ADRV9001_GPIO_UNASSIGNED, ADI_ADRV9001_GPIO_DIGITAL_15); } - + ADI_RANGE_CHECK(device, paRampCfg->rampClock_kHz, ADRV9001_TX_PA_RAMP_MIN_CLK_KHZ, ADRV9001_TX_PA_RAMP_MAX_CLK_KHZ); ADI_API_RETURN(device); @@ -1293,7 +1293,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, uint32_t refClk_Hz = 0; ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_PaRamp_Configure_Validate, device, channel, paRampCfg); - + // Use Analog RefClkDivRatio, DEVCLKOUT Divider not used here ADI_EXPECT(adrv9001_NvsRegmapCore3_RefClkIntDevclkDivideRatio_Get, device, &clkDivRatio); @@ -1301,9 +1301,9 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, refClk_Hz = KILO_TO_BASE_UNIT(device->devStateInfo.deviceClock_kHz) >> clkDivRatio; paRampDpClkDiv = DIV_ROUND_CLOSEST(refClk_Hz, KILO_TO_BASE_UNIT(paRampCfg->rampClock_kHz)); - + ADI_EXPECT(adi_adrv9001_AuxDac_Configure, device, paRampCfg->auxDacChannelSelect, paRampCfg->enable); - + switch (paRampCfg->auxDacChannelSelect) { case ADI_ADRV9001_AUXDAC0: @@ -1322,7 +1322,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_SHOULD_NOT_EXECUTE(device); break; } - + /* crossbar config for AUX DAC 0/1/2/3. Bit[0]: xbar 0 select: 1: TX2, 0: TX1 Bit[1]: xbar 1 select: 1: TX2, 0: TX1 @@ -1385,7 +1385,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, } muxSel = dataConfig; ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, muxSel); - + bfValue = (uint8_t) paRampCfg->triggerSelect; if (channel == ADI_CHANNEL_1) @@ -1398,14 +1398,14 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigStartDelay_Set, device, paRampCfg->triggerDelayRise); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigEndDelay_Set, device, paRampCfg->triggerDelayFall); // Set Ramp Clock to max for LUTWrite - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_ENABLE_PIN) - { + { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStopSel_Set, device, 0x1); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStopSel_Set, device, 0x1); @@ -1415,16 +1415,16 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStartSel_Set, device, bfValue); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableStopSel_Set, device, bfValue); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStartSel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampDelayedEnableTx1EnableStopSel_Set, device, 0x0); } - + // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioSel_Set, device, (uint8_t)paRampCfg->gpioSource - 1); - - + + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_GPIO) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioMask_Set, device, 0x0); @@ -1450,16 +1450,16 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, /* Configure the delays */ ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigStartDelay_Set, device, paRampCfg->triggerDelayRise); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigEndDelay_Set, device, paRampCfg->triggerDelayFall); - + // Set Ramp Clock to max for LUTWrite - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + if (bfValue == 0x2) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStartSel_Set, device, 0x1); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, 0x1); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, 0x1); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStartSel_Set, device, 0x1); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStopSel_Set, device, 0x1); @@ -1469,7 +1469,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStartSel_Set, device, bfValue); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableStopSel_Set, device, bfValue); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStartSel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampDelayedEnableTx2EnableStopSel_Set, device, 0x0); @@ -1478,7 +1478,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioSel_Set, device, (uint8_t)paRampCfg->gpioSource - 1); - + if (paRampCfg->triggerSelect == ADI_ADRV9001_TX_PA_RAMP_TRIGGER_GPIO) { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioMask_Set, device, 0x0); @@ -1488,7 +1488,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, { ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioMask_Set, device, 0x1); } - + /* Enable the clock only after all registers are configured */ ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Set, device, 0x1); @@ -1525,7 +1525,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_LutRdEnable_Set, device, 0x1); /* Read PA LUT data */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampLutRdData_Get, device, &bfValue); - + if (channel == ADI_CHANNEL_1) { @@ -1536,7 +1536,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1UpThreshold_Set, device, paRampCfg->upEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1DownThreshold_Set, device, paRampCfg->downEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1Asymmetric_Set, device, (uint8_t)paRampCfg->asymmetricRamp); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkEn_Set, device, (uint8_t)paRampCfg->enable); } else @@ -1548,10 +1548,10 @@ int32_t adi_adrv9001_Tx_PaRamp_Configure(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2UpThreshold_Set, device, paRampCfg->upEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2DownThreshold_Set, device, paRampCfg->downEndIndex); ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2Asymmetric_Set, device, (uint8_t)paRampCfg->asymmetricRamp); - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Set, device, (uint8_t)paRampCfg->enable); } - + ADI_API_RETURN(device); } @@ -1662,14 +1662,14 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, uint8_t triggerSelectValue = 0; ADI_PERFORM_VALIDATION(adi_adrv9001_Tx_PaRamp_Inspect_Validate, device, channel, paRampCfg); - + // Set all AuxDAC SPI Words to 0x0, Set Mux to 0x0 (all SPI), restore after LUTRead to prevent unwanted output on AuxDACs ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Get, device, &muxSelProgrammed); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Get, device, &spiWordProgrammed[0]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac1_Get, device, &spiWordProgrammed[1]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac2_Get, device, &spiWordProgrammed[2]); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac3_Get, device, &spiWordProgrammed[3]); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Set, device, 0x0); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac1_Set, device, 0x0); @@ -1680,7 +1680,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore3_RefClkIntDevclkDivideRatio_Get, device, &clkDivRatio); refClk_Hz = KILO_TO_BASE_UNIT(device->devStateInfo.deviceClock_kHz) >> clkDivRatio; - + // Not possible to return the configured AuxDAC for each channel based on XBAR..._Inspect will always return ADI_ADRV9001_AUXDAC0 paRampCfg->auxDacChannelSelect = ADI_ADRV9001_AUXDAC0; @@ -1697,7 +1697,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, rampClock_kHz = refClk_Hz / paRampDpClkDiv; /* Convert to kHz */ paRampCfg->rampClock_kHz = rampClock_kHz / 1000; - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, 0x0); } else { @@ -1712,7 +1712,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, rampClock_kHz = refClk_Hz / paRampDpClkDiv; /* Convert to kHz */ paRampCfg->rampClock_kHz = rampClock_kHz / 1000; - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, 0x0); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, 0x0); } for (idx = 0; idx < ADRV9001_TX_PA_RAMP_LUT_SIZE; idx++) @@ -1731,7 +1731,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, /* De-select pa_ramp_tx1_lut_sel bit */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1LutSel_Set, device, 0x0); // Restore Ramp Clock to configured after read - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkDivValue_Set, device, paRampDpClkDiv); /* Set PA Ramp up/down threshold for Tx1 */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx1UpThreshold_Get, device, &(paRampCfg->upEndIndex)); @@ -1744,7 +1744,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, /* De-select pa_ramp_tx2_lut_sel bit */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2LutSel_Set, device, 0x0); // Restore Ramp Clock to configured after read - ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkDivValue_Set, device, paRampDpClkDiv); /* Set PA Ramp up/down threshold for Tx2 */ ADI_EXPECT(adrv9001_NvsRegmapCore2_PaRampTx2UpThreshold_Get, device, &(paRampCfg->upEndIndex)); @@ -1767,7 +1767,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnableGpioSel_Get, device, &bfValue); - paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; + paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampEnable_Get, device, &bfValue); @@ -1776,7 +1776,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigStartDelay_Get, device, &(paRampCfg->triggerDelayRise)); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampPedTrigEndDelay_Get, device, &(paRampCfg->triggerDelayFall)); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx1PaRampClkEn_Get, device, &bfValue); paRampCfg->enable = (bool)bfValue; } @@ -1794,7 +1794,7 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, // Hardware bitfield does not have an unassigned value, ADI_ADRV9001_GPIO_DIGITAL_UNASSIGNED is not valid bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnableGpioSel_Get, device, &bfValue); - paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; + paRampCfg->gpioSource = (adi_adrv9001_GpioPin_e)bfValue + 1; bfValue = 0; ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampEnable_Get, device, &bfValue); @@ -1803,11 +1803,11 @@ int32_t adi_adrv9001_Tx_PaRamp_Inspect(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigStartDelay_Get, device, &(paRampCfg->triggerDelayRise)); ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampPedTrigEndDelay_Get, device, &(paRampCfg->triggerDelayFall)); - + ADI_EXPECT(adrv9001_NvsRegmapCore2_Tx2PaRampClkEn_Get, device, &bfValue); paRampCfg->enable = (bool)bfValue; } - + // Restore AuxDAC SPI Words and Mux after LUTRead complete ADI_EXPECT(adrv9001_NvsRegmapCore2_AuxdacMuxsel_Set, device, muxSelProgrammed); ADI_EXPECT(adrv9001_NvsRegmapCore2_Auxdac0_Set, device, spiWordProgrammed[0]); @@ -2059,7 +2059,7 @@ int32_t adi_adrv9001_Tx_DataPath_Loopback_Set(adi_adrv9001_Device_t *device, { adrv9001_BfNvsRegmapTx_e baseAddr = ADRV9001_BF_TX1_CORE; ADI_RANGE_CHECK(device, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); - + if (ADI_CHANNEL_2 == channel) { baseAddr = ADRV9001_BF_TX2_CORE; From a6be8f813305e5a27a5f91e23bc0dd30a9d44580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 10 Jun 2022 14:50:59 +0200 Subject: [PATCH 355/407] firmware: Update firmware for adrv9002 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Arm firmware updated to version 0.21.0.8. Update default profiles. Signed-off-by: Nuno Sá --- firmware/Navassa_CMOS_profile.json | 3 ++- firmware/Navassa_EvaluationFw.bin | Bin 294912 -> 294912 bytes firmware/Navassa_LVDS_profile.json | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/firmware/Navassa_CMOS_profile.json b/firmware/Navassa_CMOS_profile.json index 80b9f62664a985..166338a5916cfa 100644 --- a/firmware/Navassa_CMOS_profile.json +++ b/firmware/Navassa_CMOS_profile.json @@ -1179,7 +1179,8 @@ "pllModulus": { "modulus": [ 8388593, 8388593, 8388593, 8388593, 8388593 ], "dmModulus": [ 8388593, 8388593 ] - } + }, + "warmBootEnable": false }, "pfirBuffer": { "pfirRxWbNbChFilterCoeff_A": { diff --git a/firmware/Navassa_EvaluationFw.bin b/firmware/Navassa_EvaluationFw.bin index 4d05aa885cafb64c5ad1516ae4cd24bb41cdbbfc..2c8b8c0443eb927a1677cfad93c455b0af7270e5 100644 GIT binary patch delta 76331 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 HzkmJ-o^a)k delta 76449 zcmbTecYIXE`aeF;*_ut;5K>9V*-Zio5J)Hz2*`%AB(wxXMG*;2H-MKQmQXZ7q}sp( z98^%STmh99F$4$!D;AU>C|A@(+d}a-g`gy`}w}Uuh;L7+4IcIGkxZn zr_EMZx2vvhS5=luV$K74+O&=RKSNBN?q4`{`*c)tRtUux=QEntq9b<~qW8Mdzi|F< zb-pu!XdA)@6R3)I1K5jDhft4j1c4Wv6u~GwmeJi&jH2=V-zt0OZ~yMlf9LPK|9|hu zmrv*@;Yl4Oea7>vZdLrwKB5B%aq|RPH(#J_KzOH#Xx$`%rXln}P!W<4_98R_cPa2v zpAg8lK%mF68FZA5@E3v&aNd8!`vERSxDTNmp%7s#!W4wL2!EC1-#+^V z8jf%u!YqXU%=^ElQSA`~JFLnuc0?+(P-7$r6T&n4h#JaF7W0@1+h0wwYYPdu4OqF&F$ zZ^D^qVGfdF^j&pqRFZV3zT*&A7oAAVe3I-;NuwsMxnPyU5jI2<#fsr!Brx5{Chd6m z;_(&3o3w8V1SMKX9x7=1l#1cu&KT$6L_wJ?y`k?Kvt4^6MW1uwOkRD?g+NJ@wn#do z?-M;*TkI5_g-%k6v?gtUlxE0INDOB!9~(|xVCfr%nNDXltQ~AR(WHGSO*TA5-%Gz3 z+Q=dOXq=z=O$W3XZZ0di-fLcyHakLBM)ol`&3PmW%H7f)eJl{@Eonz z(wnsR!~cy(%5|xSd8wg2+EyeAOOTG6yBU;VleQJHVf2kOJS>gu(!*hChAT)-k)8|d zLpP)&h#x`xQ|X^!eJM*ywRE65sh_1EZItF&2GVM2w; z=TBOyPj!lPC}A)&ze z41RBQ8qEG7OT>yg;NdgvSbJIN+Gnew)`Nppqw zDAh6;Uyb_n%5XuMdJw&~px4Q{dv(0m6RBm1e(|m?t}ad{2Gw_^q=-KByi^jA8ri(6 zNjqJ>LHp3yr2Q<-kLW?Wq-_!DG+sIuk&x-Qqe*kbH)-dcN3~tXB&^SNhln*Sxjw6q zL{eV#H)-Rgu*e?b`8d5}tkx5AIOb+VUfnd&8B}+8hc~ls!;Uv;M-5VGbWdqj@_5=v2-qvMLf?M`eh$547B zw8s`0iagW**^!rhSUQQKdypdKMaPEk@%+{Faj7Kw19D0J==-9oe`n3?ENf1@%$oO| zmmad7rN^a_F{3F=dL?EO6-sK%G3q3J)^1$9xcyHOxBkhPHD50_&(nz~1twNVIk5vH zzYjQ^I^|%{;nXYbq$gvCQ*}*4td8iA^hx^`dQjRKw+Y=C9iJ8{`}NIw3M{MXQgEc-2`7i`Y@qW()obNZbE$FdNk(J{e_DHSsv3bBf*y!+8f9q63YHK|YZZ-HH*93hl*RhpC3A+0vRYz9%U91SQ_ z3>ge7eutNr)`xJKq;0@?H9#Sp_X4?74H^A55JtoB@ zr6sSU0%>pZKuVFWCHEph>fE8%edB}14SZG(17{3Q?&e|=pVgdG^cy*k@dVnFrcy8vGm->31tCT&U? zVk}M6iCIa~pDC-1i$2!THy3N3NPU~4-_a&tG*{?OF&m+c*QM;V$>|lIqTQog4PwuF zBhtz}R>X{m?H-+Fx20w|&B~+Fduauo$9t@Hy}OhQtshmGmC>I1^LdW?KlArCY5Bum z0WK#IW~ESy6bqu$feXC3diN-1R#K#U#bemTnYPiCCe5=wNyDWUTZe=(xrsQfHYZ`8 z%wEyiTCW^nq9Uc*Q-N1tPogQ(-S(%j1HQN4O>?E}^a8BRjP$$7Dji7Aq#chuvh_~kOi`b&d7stsrARAMDo6(8$v79)UISRo5AtbGn5iJ`V9KK1ZGC zUivM)PYP&#WR^Qgfpd zILm(o7?z(?&Xa+RQEB$H5d5taot2&bM_U#Xjte!}W{@p-TGSeIp#EP1;mB{X>#6)_7o zzF@{Ns6Q__7`D-eQrE7jRY7mK`)9%Ma#FfsL%4goz-(sahBy4iib{QYxLZNofod-y z<>mQExl#QnvlSub52S3Ypw;0wc0D0D4e5LUX5}CDdI zKfN3(c5=Ac%N|6;7V7y=xQOz1^UT6f{Dk+6rnmA_-z$$J|Asib9nVGlA6}l?(aYfu zUfMu*vfVkxti0;W#g1hg2m@IwWp*2uF|LhwxTMXjSlY-r7&n+v(IciqYy@_;QSoci zi`}|JPVz82XH=p_8I?z*&${*KRP+WDOA%J2>P5c8EZ9kWhn>Za3+=YAUM+Y!R!Yt( zO1|jVJ2!zsWIMx@Cjy2LY(u-J{L-SFO{NN5@#b1|@fBk&UHV zl$WKNoM|*&O6Y#X@T;RoLBTrQWl33P;z6&_D8=za8V~J3U!bD{#E^PJYL7 zEM3c|NPo)%R!`64EEInY@!Z?-p;ogZA)cXUEkmvRfO9;vvT}dU1+C;6)D)pV?kv@^ zN~Ni}_JRqTCYVl5z8FUO;}f0ZLj2aCwulYp-Ar+{)t`62#JNpg?4T~n`8^7Db%2+Q z<@{tr?tP<~ay|INh{0M{Mxj+12Tn9rqYY!hx2@J1iwi?JU0r=(+NiiIzAhASDqb+}c!I{SxW zV|>xgQ=aFT}b9R{poZOf9aD0bV!Xzit0(2| z=Jn}zfuk!4S3ao^L6|A6WU+IV^QhC}&SHi0A41uzQiFSdv7}?~%7(&-Iudg$B*%f&e6~l8bD1~dZoLuLq z8aGAgoV|gWUa?loWQ`Y?Yj#USM9IaU7lAd666=1|%#J&fidxQA9!)g4N9b2;BFn6d zQ*_a~2Gn7lpGexMXp{B;YF{y|SCQ`YvcdTcp!8MWuNY=*STT+}0GrObQRw1K^wR~bl!?_a&AJ&wf?8bn( znC(IVvWf2?pv5VFGO;K{Cz?}rqIMZX7pK*CmWc!Y$wbbBy^m1L88Ut+9sW`fPhLci zT9}x4o{2}#G0}mqf-gVb{HRyFh;-on47>>7ai)*oa%{%2)ZS8K@21FoD3J@|kcaT8 zRNp7v@WQ^Jx<&eDpUjy1Ap$MZeOg9h{rR4bpqf_G;f^MXDe@LxN({FttdQ)kk>Sd8 zDLg+ZvX}R+ONm|66*eSXDVOr{@1up%bNP#DrWDyP-7>*%ZnmaID1UmS{{1pyp7FJu zv!({sj=^*I2Gm?>PQO$k>x%SZzm7K7drTCFIT-`tM90AkI9U=u_A$<6XF$Cm9qac? z%!j_{o81zG_XK-CryxcsJ){HuUx?i9`*#YH?k?z)u*YX;rfhSA)fRDF$Tl`wZCRkW z?@C(=;vkvT7BuGW^!BO9a|#fiq zqH3~;<-?2#JoObClmz7HCjBbA9#)18?KZ)lrcb{8$QBL5|gd^V_<=ou-x@IKlkl^3R>isgk% zsfQFfxPW#@#ed{a`mGsEa##poRW3VcPdOZ7!u6aK$g9xQS8awQ9 z;jC9WI&3h#C51ct(K2b6vk%RZ7CP^uze(RYUklq6_-qfaq*|IcycaF5d3U&pgx}kw zT}4xc7O&L4cx&`m{w!yt(!XsnRwhyzA$?suoR}0lA`_$Ohu=G-$sCC7k>M7kAHJmON*>bds0f;4w_U zy&uMWxAg9q8=WR;Of+zM`VwO+I_ku4u$TF4@>y+Op%W{s1u^-m^l`~d(`PQy?LGNr|(3&(Eq8=arKb@V0XB|>@5pXcP?<$f-(WZ@9pg-MT4`uX|qYzV~;o&Hs- zj2Rpb;demns>mntZ7K{I$h7 z7kq_AXM}ULvsWEcI%*6=IzlOyq`P{=j0jQ%X?a&9F*CQl(JQ{zx!fQha3-=N8p*hZ@-V((-zk#`{(d+0wWBp;NCQ#QWc z_+&9c01*J&zJ2^N?dAoeZ)#!DH(4@MUezqhm0-=Cck3x^WsoUJh-XV9@0rvm9Y>0v zcbn6S^KNOhIrDKFCI&gzXj0nao8{Cs>#_~V$%V9V9a2S@^vgXB^kU7Xd!K{iS<1dI zoyJO|?@JSY^-6!cFR|ll|L*eUq;Kr!bM?w9zwyTV6-!(nyQs1`DN8hd{pfVIuSQ#yL}*BP%VHEQ^m{f1I!{a~+XN*}lJ^g;MH+ zv-FWlYp~||2R8^+T*l;gPSS@EcM!JKFzSpi-@V5{BRFTd5&6}7Pl-OY(xbQW?;gmI zf`dZ~_E+!y5#L$J;oo;cIUITfIgR)}h#dai5X#|D8FIeIcdSRBW#hnep)3yFwVziy zaX+tM!hVi?_kNx}uIB40FHvOvzWVd6FHHfjXHa@d4^LaC*DHTEygYp>JuOX}oDYyTT#pVl0Eq!(GPr-2^E>cq98WSO(fXvef4N|x5o8Dr#(Kf5Shob#qI zw0+Hs70Dz#dr{gxw`fRyKXc6)^9>GhWA&cVMf#y4R7yUNlso^hg`dlB5I_<<^G6i$ z3HcDa<|}A__*nRgzug46p&8O91ejYoT#qVqDg8fgW{O%;f`c z!M?kExbVAIQkHK{{%5H7fhA?oj-9q}iMwJrOJvTi7o_bgo~CtD_R35;ES0Rh8=LZ- zl`Ul8Co4%>_uLW#KVOeasn0(w?7AW?d*03$bNllrNVr-jJ^kVXSkp5vrbh3sv)b~V z9(BqAu1Q8uUdp2{q<$}bXD?K4~63+iqdR^*Htmc>$PVszCJXl1F zk}AMd4rh$-Jv4A-ZKur9ZCr_e{YJw{&2A=hWWaub;`U zGqilFw^h7Z@kfPHU(`xWsn6fbY`vx6`p&@XEZgu~Ecc);(tLS2`6SxVxkE`{5>)2Q z7T%n=cj+#@6GLgu8rvQQl)=)F4P6I49$=ZzIL&UWG1pbd^ruR3L>>uPvefT+yr^MR zYgAnFN$S?OETNGp4+c!mT-V`i)sJQD&IjfM>4Ocw3C2Ux>Q|QKeC!vUJ?nWh5us+P z^LR6({j6I=!`7m$MPwIV*1bH_`EIdM`K)HhtJw59>5JFe>@E$+tbRp??hG9Il*~@bd!RBjY?(sBS6<2W=F4f--u-*BozRz+ znwrCJJYO24Jb621HQ>2Y(px=}`Tcbs74iN0073@ezrkoWG_GdqTZ4tLq=Q`35~IXP zAH4G%{aDlQ?~e#VvRB%=Rf*?{Szi8q1b&?Px!6`C?bx>7(CCkWhPZfp=XP($lb8WR zL|GDv1K=7^mMT57eFb>p@b}X5DuQOwqTJ=@zwh}?wke{j{_c-%O(LFB7I>&=@a+jr zw(*n)rOEGoCe-<)PVbAjnTEfgO_DVC{Uhv1*tXTi>@+xfJ(7ozT%I9si(9 zwiyb@3J2HLl@@6#9n9ZbQd~N!r~-^|mZc)Hk>`v?&UGn$M~~>Ap>yU}wO|))ntDo_ zvZHh2A+K0wRo)H?AVq97OBY>ai&3t5rOi7AM9K&9>h*R#cxp{uBVE`rh$cwcJJaJ+ z_)H4S`BDNdK`hhjxD0)NN>g_ZfF0|No$q%2-NTi-`!)XCpc&lbOsnk*=rUUMltC>q zHagrM9f}{5=I**X{7oneE1*r&)J;<3uD2c>>7nLPHzSjZ_+7W80yk-|V(4qj1WZ(> zhwC+MkZUc<9Uhi>&m9~Rz1F&1aBx~9L~aJDQ{1D6eoY7y9ZkUOu*DV ztLSU#@}5V?DNU>?riY|=YR*C8dEvvcbV6$SFq7s;hP?$~qYC$eVeTUx`zS3g!4EAe zl)vqir4Tx9L1QJV?Wd1XJ_$;9)+TqoFKBGt7SHwJxlUCb7tGxKz;3=!`C!Ol3Z8Z(Y5>5 zDG2c~Yx_L8;uI6dV^|_uG99W3)O}28KCd!6tE`JN?~(GdU9-2A?Vf$1Oswp;2%5%8 z?UaY4rUS$KobrP`H#-!$noC+m7*3Z!-NGVBTf-@Q6JPP5Mls}}o z4O4`AuXM8EI@AVV9?lWKlWB*iQb%dxknzUPy~D~`#;FTNvMPck9hpQy$$jK& zS|!zg`~`*8Ed8V_wfn42ypmLeP8Rjy&6owUy`ljYyDPMLkym;||O;C%*U=x6+oQv*@%G`K2oS8K^OSwVBeweA$a~VUJG9h*1{# zx-2S&l_a44-CvGxjAE2N`+5#%9>3{f$;NS?Fh&qj+26hyGvi30YqJ@B{4H?of58Jm1p`5u}Y0(JC-oy-B6i!$~*|M%TT94JZ~e~g=5Ejt&+DJtE|0^ zRTktm$11Of@|94n%cOpm9E+}RG*mg>KkTc$Vzl;g=bQa(YBnO%ODU^(tyvNeo zwMXnR#DpMM0=83*2c>S`c8`0gfolNUDZd{QoZ(JP1@_7VHFLg=B>GT#>btaIR!p*E z%G}n21#=oxMC7ycGq-=gF~3buiLxAPyY}()JLlqO|p! z&r{|H-*XZ|^9Yv?#9IX4kee$#x zG7HV^6Nli-(!1c6@v5GXnXM`tSEN_{DZtjTbivMTTVA!vXMi!c8Ejs!M&4j|n98re z9M7fCCOhSF;3E~9gZlh2(Vc1;U9w@jn$gv+MA@^Ray%Q{ONq-?!YydqjmN=l&q z%3+K3iuL}>d)h-NDlMJWJaLGVuS71^WqPQBhqSo5A+7qMlbUlvl(o5P!WfcVFHELVEwcD-KK34d!ZMoIlKc$7=cc|(I zl@sV$U}{kw%uY63$h{5xKFq?d?AxYypENn_4%~+~)!a6A8|vD|%S;IjZ_O>`>}%S_02uoFQX3mQ>tS$AB&RN}pxd(BGTtaEmoYCJV4e2G`s?%tCHqLeRn_#p`j%sxM)L$7_` z4>@2Qm;cZpg!!bRAG<`i_)YF=3$yENrOq2_iM05~4t;(AlX5FQAb1c4Piwq$NYv2v z+5nNd=o-m(9@65Tw)1-eYOD5)^Ea1R8BkA3jX$PRyma+PTR&5<*#&p8xWn2$tIet3 zAe3|5o7nL-7{GjLTL5)2%F;EmP+gCP1Q5&=Nuk1CFtu86=_oSU)MX6nTDouo0pX3%nJ-mmXck<_8-$^0T{<3*=c+21DJ!R#W=>V!@*#aa zkeSV@+}tO1X--ah9NFQ>KKozUA4rp$OK7O{L31YD{l0G=9Zeov<$0F{C$Pd1twc#Z ze#=Xq<2&Lsx<4@GE~u=_g;95N(CAKKaY~h6TJYQb`O`e-%S)7CUcBXR=1(IslEFKYp1361+6iHCMj zvY%aFRpZU7B#0h)&Uhu<_febPinu)7Pz?gAM&cT{-s(q!wrZ+`=uHG z>=*9#le1@K7MggVX4^mOhz8V5JGWdH)6s8o8d`?3!snlGiMYl@$$RlGx+Imf%%Lc$ zp~W_q?=UXf9T*_ckY+~T#4XfSiC9c(OxzPk6Ex z4eoeiPa2#%da>(jp~tnT&@`$+m&r1-v2%L^H{D}w-5Z~c5mCiq47D|+_>EBJOJBMt zcRSZM#bt6&3gK-5R0b%+^P6ks9+P_};PxI{xyii*5P78Wt#%q9J=xmBcA?F_(1b<{ z(C9~PThOfmKsk%bjBW>@e@I`n_J!AMur-wyOR3kg`_69T5;N(!cFO=y3K9Hw#c-~| zFo!XxIg&ZKJ>q}rq_3%iYM#25L>;=}Fx8*Gx!Af_XJ;87JH9uKZ{U^1D>2gU>uKo) z{>r*8@NqRYbJjz|{_p9}MGA-cRTQrj)Lgs%nPB6)!2xEJTc&y2{QCSKDn;oZ>Qa8h z$}~qzU%&HWSXk%Xn^PFv4C7&>-mS&K7|v|R#du}BUplTWOIQ*h`)_+DfHiu^XZD0E zrXkHh&6XZ%8{X~(580acgemW94BvR=hF|);?NuSEO`7W207I(RGceVxTn>^=L+%~^ z{a|#n1`j))sF_N&JvY@mq`SRqXn}Oj+co>3kMmTT+Un)DbU|!WoA%k!YP@F0z!`j8 zxW++Kw@L-R^r(~jLo~qn(gbDv_GU=f%gqmD+>-~u@Iz6$8SzKvS$Jqg4jj6uDV7(Cq}6zSRiBt zB_){AwNDVXe+YHedj%Uq4|n*uR)PBv&khJSJyPEB2^dA2x@FxUitDgGluyVXk9-5t zUqHSN-<9j;P)QQ~?=ay8i!{ZVX=iwH?VWbGKkSsqVP_9tnlRp$_6kU-? zM?>N}`|`)|;~cN#_&%(TR}Kf`mGeRQe$csSCm2uG%sHoCYtQAD zGgm@LcHmepjXPi7A1X0RJ9JKP?w(mOQ&SJMT|D=fc*@PyYbS%!V4}xglz%tVY&IRDVf$&W%0J>H+EFG z)#*X_SYqE_Q{VKCfU=E4o8(yul#?_BdIwNw_efMa@HTu8;J)(i1nQ8IjU;2UkP{x# z3A}fqbCM}8>6m}&{Ak+*w0hM4=7M&nc2T*Z*b#YCG9^v^FeC$n-8h2b@3;+r z3wY~o_zd7T{hJr);Q2E_%UsRntuXgb7&+YiIUFjv<~GbrK6e}DC6~%^9cXOi1AhCW zXspPeD0YuLuLGqg4fVgd=+*)Z^8dbQ9J(cjmLp%@*?|g$gnGHP19hjMY)hdeYLyF8 z$QJt>-g=0AxVD+kZey-n#UNAQcl)_4rQodYkq@L$SK26_gBwuTvj-iZBW|@?PD`b( zRWp5qomJ@jujs^d5I+KZ0Pur8ww}B09>&sGl~ZtiFe!o{*n;Y}5c9c${MJH_fchVA zGJ2u;()LaZ>N2>`q5PfDIvU*P8NaEkY;N_AgB5#IVZ;BFW0u{*G`i2F12r3{RhWnK zfYW^+7`sFn-6v77!V!Uj$p__2skD~9lNWcSyXYPHR7dJTFUW>88WeE>`m?b(hw+dF zK>QB4@n#)wSRI~Q?BcFtNjn~vGQ%#N8X!8V}*zV zvRR}~pq@QMD(~<)9BkqI+hSyjdKm7tD2Wk^!2d|D5$UeTcRf>F74U(pa46~)Io3wD z2d80GV96OGl|#`(lD(Pgc# z-m4R@s$2X<+|^grGk)$h!lAe1IbErP&=#nDzAHUTUB2)cabsUqDTKkHFAwtH#)F-U zJC7*28LTi@TU{|q=^?p)4(L<;6o_jl+H z_(W7-$}$hs{?G$-&%p1_lk(+UXdAEKmd>LTLDl4odGu`b{cZco#ogc7BX9hDimKiv zKh={8sE=INlO8tS^1YEe^`hR<&$KlIPk5!|`r$`a^%uFk7mXGIK6zg+>LNUNP(BMJ z>Le%irZc&de0nI_a?2{pOzunr7Yl#JHn%F^J~DXh*PzFh2hRtlY=PkE^vM~0=wouq z=laki!Y;3T&mFX?V`65;veS~-)W-LJ_H^`!v`VWD&rlosU`qAQHwj3qIORj%tx^B+9q zSrV#asn6zexK<2a(ufvCE(ati{B$Nj|GV%U7h+2>ge?tvd-{AE98F-AZ>V-9=LXf! z>$JU0`9(`q>Je5We65wu&w3zHIjqU6^XWn15wEP|Q-9%aUb$O8O1W#+p$eSy!x;vr zb%lthLssQzwElQL?2FUdgpA1MXH3FL)@j#ZePchQ-Pgu4bj>_>e48#KsJ_}3RKICU zg!dY=Tj7TBnEt9dSbnV^^&+wMyMFWwS(o^zn_+cYV>#^43Chtn8AhAI!ZvOF0Qxv> zl{d@P`xS?FGA+;9>(#+!#z(VU%#HV0H-=UuC{eY)4WMX>&@>Z^~z!bc_mWw+*K`cq<|&71Lru zAB$-&Maq#QD3d&LuMspn@dqC@ms}q+oHJCdOZef;*v7={tMbbuXjk;32i^4oRJGt8 zaQ0@&V@J|^LX2MyjHLX8>%KU}65YOGy(Wt5HM?lC*@~{H7ive3qKN`!)NUI?_v)x~ zEsdl1h{nnv+(lR0Kfj()1zHF~SDFh|rbRhkSG#LGXB8ZB!aX!e80(jxxQ99k1O4*r z_mEwGS=DRur}t29)v1OE+maDQLt+wl!_t09J&kzPf5gu;RPW`y{EtDSEmFLsdV`#E zKaN-wV%LM5NB4@zJMj*BX zu^EWH8;nG35n>M^wmBGu*yD&jjMyu|XvF>&tUn*7cL+8Yl2*&!dugRm?30&Gpe#_! zofGIj5ZAE#Xb9L}FzD93@k*IDUYY4-8P>Xz>ybl^&GE`?q&)7GXWviV+Uo*FTPM^t zFu-XehYW}0_wT0(onP>u{TJb{wp~`2*5}m=Sr(`9r(0HFvQ?*ERu{-!C(>dIS8{Nh zXnt(%M-yqiKtIZ(AEdl{k9#BV7Rdys{>$oDUInIWle<0OPeYnBE#

;JpW~{G8)r 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 Date: Fri, 10 Jun 2022 15:51:10 +0200 Subject: [PATCH 356/407] iio: adrv9002: api: fix stdlib includes and misc warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change makes sure is not included when compiling under the linux kernel. On top of that it fixes some implicit-int and unused variable warnings. Signed-off-by: Nuno Sá --- .../adrv9001/public/src/adi_adrv9001_cals.c | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c index 80ca6c09ab86a7..7006887e9d8d61 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_cals.c @@ -27,7 +27,11 @@ #include "adrv9001_reg_addr_macros.h" #include "object_ids.h" +#ifdef __KERNEL__ +#include +#else #include +#endif int32_t adi_adrv9001_cals_InitCals_Run(adi_adrv9001_Device_t *adrv9001, adi_adrv9001_InitCals_t *initCals, @@ -78,7 +82,7 @@ int32_t adi_adrv9001_cals_InitCals_Run(adi_adrv9001_Device_t *adrv9001, /* Mode to select the Init calibration algorithms to run */ payload[1] = (uint8_t)(initCals->calMode); - + /* A value of true will force all enabled calibrations to re-run */ payload[2] = (uint8_t)(initCals->force); @@ -588,7 +592,7 @@ int32_t adi_adrv9001_cals_InternalPathDelay_Get_Validate(adi_adrv9001_Device_t * { static uint8_t MAX_NUM_PROFILE = 6; adi_adrv9001_ChannelState_e state = ADI_ADRV9001_CHANNEL_STANDBY; - + ADI_RANGE_CHECK(adrv9001, port, ADI_RX, ADI_TX); ADI_RANGE_CHECK(adrv9001, channel, ADI_CHANNEL_1, ADI_CHANNEL_2); ADI_NULL_PTR_RETURN(&adrv9001->common, internalPathDelays_ns); @@ -596,7 +600,7 @@ int32_t adi_adrv9001_cals_InternalPathDelay_Get_Validate(adi_adrv9001_Device_t * ADI_EXPECT(adi_adrv9001_Radio_Channel_State_Get, adrv9001, port, channel, &state); if (ADI_ADRV9001_CHANNEL_STANDBY == state) { - ADI_ERROR_REPORT(&adrv9001->common, + ADI_ERROR_REPORT(&adrv9001->common, ADI_COMMON_ERRSRC_API, ADI_COMMON_ERR_INV_PARAM, ADI_COMMON_ACT_ERR_CHECK_PARAM, @@ -728,7 +732,7 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate_Validate(adi_adrv9001_Devic ADI_ENTRY_PTR_EXPECT(adrv9001, initCals); ADI_NULL_PTR_RETURN(&adrv9001->common, errorFlag); - ADI_NULL_PTR_RETURN(&adrv9001->common, dynamicProfile); + ADI_NULL_PTR_RETURN(&adrv9001->common, dynamicProfile); ADI_RANGE_CHECK(adrv9001, length, 1, MAX_NUM_PROFILE); for (port = ADI_RX; port <= ADI_TX; port++) @@ -766,7 +770,7 @@ int32_t adi_adrv9001_cals_Dynamic_profiles_calibrate(adi_adrv9001_Device_t *adrv { int8_t i = 0; ADI_EXPECT(adi_adrv9001_cals_Dynamic_profiles_calibrate_Validate, adrv9001, initCals, errorFlag, dynamicProfile, length); - + for (i = 0; i <= (length - 1); i++) { ADI_EXPECT(adi_adrv9001_arm_NextDynamicProfile_Set, adrv9001, &dynamicProfile[i]); @@ -786,9 +790,8 @@ int32_t adi_adrv9001_cals_InitCals_WarmBoot_UniqueEnabledCals_Get(adi_adrv9001_D uint32_t tblSize[4]; uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_WORDS] = { 0 }; #else - static tblSize[4]; + static uint32_t tblSize[4]; static uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_WORDS]; - static uint32_t calNumbersEnabled[ADI_ADRV9001_WB_MAX_NUM_UNIQUE_CALS]; #endif int calNo; int arrayIndex = 0; @@ -796,7 +799,7 @@ int32_t adi_adrv9001_cals_InitCals_WarmBoot_UniqueEnabledCals_Get(adi_adrv9001_D ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0] * 16, 1); - + for (calNo = 0; calNo < tblSize[0]; calNo++) { uint32_t initMask = vecTbl[(4*calNo) + 2]; @@ -830,7 +833,7 @@ int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_MaxArray_Get(adi_adrv90 uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_BYTES] = { 0 }; uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; #else - static tblSize[4]; + static uint32_t tblSize[4]; static uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY]; static uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; #endif @@ -838,7 +841,7 @@ int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_MaxArray_Get(adi_adrv90 ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0] * 16, 1); - + for (calNo = 0; calNo < tblSize[0]; calNo++) { uint32_t addr = vecTbl[4*calNo]; @@ -876,14 +879,14 @@ int32_t adi_adrv9001_cals_InitCals_WarmBoot_Coefficients_UniqueArray_Get(adi_adr uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_VECTOR_TABLE_BYTES] = { 0 }; uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; #else - static tblSize[4]; + static uint32_t tblSize[4]; static uint32_t vecTbl[ADI_ADRV9001_WB_MAX_NUM_ENTRY]; static uint8_t calVal[ADI_ADRV9001_WB_MAX_NUM_COEFF]; #endif int calNo; ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020000, tblSize, sizeof(tblSize), 0); ADI_EXPECT(adi_adrv9001_arm_Memory_Read32, device, 0x20020004, vecTbl, tblSize[0] * 16, 1); - + for (calNo = 0; calNo < tblSize[0]; calNo++) { uint32_t addr = vecTbl[4*calNo]; From a3e7c5f912dbbaabd5de055f688df19773c6c859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 10 Jun 2022 15:57:04 +0200 Subject: [PATCH 357/407] iio: adrv9002: api: do no use floating points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kernel does not support floating point. As such, let#s avoid using them as it's really not needed: 1. 2E+6 can just be replaced by plain 2000000; 2: As we only want a power of 2, we don't really need to use pow(). Just do left shift. Signed-off-by: Nuno Sá --- .../adrv9001/public/src/adi_adrv9001_auxadc.c | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c index 264a3219d3fa05..17c3a3cda18ead 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c @@ -18,7 +18,6 @@ /* System header files */ #ifdef __KERNEL__ #include -#include #else #include #include @@ -144,27 +143,27 @@ int32_t adi_adrv9001_AuxAdc_Voltage_Get(adi_adrv9001_Device_t *device, uint16_t *auxAdc_mV) { uint16_t auxAdcCode = 0; - uint32_t auxAdcWait, armClk_Hz, auxAdcClk_Hz; + uint32_t auxAdcWait, armClk_Hz, auxAdcClk_Hz; uint8_t refClkDiv, hsClkDiv, armClkDiv, auxAdcClkSel; static const uint16_t MEASURED_OFFSET = 0; static const uint16_t MEASURED_GAIN = 4096; ADI_PERFORM_VALIDATION(adi_adrv9001_AuxAdc_Voltage_Get_Validate, device, auxAdc, auxAdc_mV); - + //These settings are hardcoded in auxadc configure - uint32_t auxadcClkDiv = 63; //clk divider is hardcoded as x6. This is an encoded divider and x6 ==>x3F or d63 + uint32_t auxadcClkDiv = 63; //clk divider is hardcoded as x6. This is an encoded divider and x6 ==>x3F or d63 uint32_t decimator = 2048; //decimator is hardcoded as x0. This correspons to 2048. - + ADI_EXPECT(adrv9001_NvsRegmapCore1_AuxAdcClkArmSel_Get, device, &auxAdcClkSel); if (auxAdcClkSel == 0) { //Clock is ref clock ADI_EXPECT(adrv9001_NvsRegmapCore3_RefClkIntDevclkDivideRatio_Get, device, &refClkDiv); - auxAdcClk_Hz = device->devStateInfo.deviceClock_kHz / pow(2, refClkDiv) * 1000; + auxAdcClk_Hz = device->devStateInfo.deviceClock_kHz / (1U << refClkDiv) * 1000; } - + else - { + { //Clock is arm clock ADI_EXPECT(adrv9001_NvsRegmapCore_Clk1105ClkSel_Get, device, &hsClkDiv); if (hsClkDiv == 0) @@ -187,14 +186,14 @@ int32_t adi_adrv9001_AuxAdc_Voltage_Get(adi_adrv9001_Device_t *device, } auxAdcClk_Hz = armClk_Hz; } - + /* Get 12 bit ADC word from selected AuxADC */ if (auxAdc == ADI_ADRV9001_AUXADC0) { ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc0Linearity_Set, device, 0x800); ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc0DecLinearDataCapture_Set, device, 0x1); //Add harware configurable timer based on AUXADC clock - auxAdcWait = 2E+6 / (auxAdcClk_Hz / auxadcClkDiv / decimator); + auxAdcWait = 2000000 / (auxAdcClk_Hz / auxadcClkDiv / decimator); adi_common_hal_Wait_us(&device->common, auxAdcWait); ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc0ReadData_Get, device, &auxAdcCode); } @@ -203,7 +202,7 @@ int32_t adi_adrv9001_AuxAdc_Voltage_Get(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc1Linearity_Set, device, 0x800); ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc1DecLinearDataCapture_Set, device, 0x1); //Add harware configurable timer based on AUXADC clock - auxAdcWait = 2E+6 / (auxAdcClk_Hz / auxadcClkDiv / decimator); + auxAdcWait = 2000000 / (auxAdcClk_Hz / auxadcClkDiv / decimator); adi_common_hal_Wait_us(&device->common, auxAdcWait); ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc1ReadData_Get, device, &auxAdcCode); } @@ -212,7 +211,7 @@ int32_t adi_adrv9001_AuxAdc_Voltage_Get(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc2Linearity_Set, device, 0x800); ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc2DecLinearDataCapture_Set, device, 0x1); //Add harware configurable timer based on AUXADC clock - auxAdcWait = 2E+6 / (auxAdcClk_Hz / auxadcClkDiv / decimator); + auxAdcWait = 2000000 / (auxAdcClk_Hz / auxadcClkDiv / decimator); adi_common_hal_Wait_us(&device->common, auxAdcWait); ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc2ReadData_Get, device, &auxAdcCode); } @@ -221,7 +220,7 @@ int32_t adi_adrv9001_AuxAdc_Voltage_Get(adi_adrv9001_Device_t *device, ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc3Linearity_Set, device, 0x800); ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc3DecLinearDataCapture_Set, device, 0x1); //Add harware configurable timer based on AUXADC clock - auxAdcWait = 2E+6 / (auxAdcClk_Hz / auxadcClkDiv / decimator); + auxAdcWait = 2000000 / (auxAdcClk_Hz / auxadcClkDiv / decimator); adi_common_hal_Wait_us(&device->common, auxAdcWait); ADI_EXPECT(adrv9001_NvsRegmapCore3_AuxAdc3ReadData_Get, device, &auxAdcCode); } From fe323bb8279a99a15b013e973b1321f3ce55e2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 10 Jun 2022 16:04:47 +0200 Subject: [PATCH 358/407] iio: adrv9002: api fix mixed code declarations warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the mixed code declarations warnings for platforms using C90 where it is forbidden. Example of this is compiling the API under the linux kernel. Signed-off-by: Nuno Sá --- .../adrv9001/public/src/adi_adrv9001_auxadc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c index 17c3a3cda18ead..c90d8d1e8cc4e5 100644 --- a/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c +++ b/drivers/iio/adc/navassa/devices/adrv9001/public/src/adi_adrv9001_auxadc.c @@ -143,17 +143,16 @@ int32_t adi_adrv9001_AuxAdc_Voltage_Get(adi_adrv9001_Device_t *device, uint16_t *auxAdc_mV) { uint16_t auxAdcCode = 0; - uint32_t auxAdcWait, armClk_Hz, auxAdcClk_Hz; - uint8_t refClkDiv, hsClkDiv, armClkDiv, auxAdcClkSel; - static const uint16_t MEASURED_OFFSET = 0; - static const uint16_t MEASURED_GAIN = 4096; - - ADI_PERFORM_VALIDATION(adi_adrv9001_AuxAdc_Voltage_Get_Validate, device, auxAdc, auxAdc_mV); - - //These settings are hardcoded in auxadc configure + uint32_t auxAdcWait, armClk_Hz, auxAdcClk_Hz; + uint8_t refClkDiv, hsClkDiv, armClkDiv, auxAdcClkSel; + static const uint16_t MEASURED_OFFSET = 0; + static const uint16_t MEASURED_GAIN = 4096; + //These settings are hardcoded in auxadc configure uint32_t auxadcClkDiv = 63; //clk divider is hardcoded as x6. This is an encoded divider and x6 ==>x3F or d63 uint32_t decimator = 2048; //decimator is hardcoded as x0. This correspons to 2048. + ADI_PERFORM_VALIDATION(adi_adrv9001_AuxAdc_Voltage_Get_Validate, device, auxAdc, auxAdc_mV); + ADI_EXPECT(adrv9001_NvsRegmapCore1_AuxAdcClkArmSel_Get, device, &auxAdcClkSel); if (auxAdcClkSel == 0) { From fe7afa475499598adc351a53a7a0029ecaee6114 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 14 Jun 2022 08:18:30 +0200 Subject: [PATCH 359/407] iio: adc: adrv9009_conv.c: Remove unused adrv9009_hdl_loopback function This symbol is not used anywhere. And actually not supported by the JESD204 TPL DAC core. Signed-off-by: Michael Hennerich --- drivers/iio/adc/adrv9009.h | 1 - drivers/iio/adc/adrv9009_conv.c | 36 --------------------------------- 2 files changed, 37 deletions(-) diff --git a/drivers/iio/adc/adrv9009.h b/drivers/iio/adc/adrv9009.h index c46314a356f400..db63ac3aca00dc 100644 --- a/drivers/iio/adc/adrv9009.h +++ b/drivers/iio/adc/adrv9009.h @@ -239,7 +239,6 @@ struct adrv9009_rf_phy { u32 orx_channel_enabled; }; -int adrv9009_hdl_loopback(struct adrv9009_rf_phy *phy, bool enable); int adrv9009_register_axi_converter(struct adrv9009_rf_phy *phy); struct adrv9009_rf_phy *adrv9009_spi_to_phy(struct spi_device *spi); int adrv9009_spi_read(struct spi_device *spi, u32 reg); diff --git a/drivers/iio/adc/adrv9009_conv.c b/drivers/iio/adc/adrv9009_conv.c index 932eda10bb9429..e62bacbea066e9 100644 --- a/drivers/iio/adc/adrv9009_conv.c +++ b/drivers/iio/adc/adrv9009_conv.c @@ -167,36 +167,6 @@ static int adrv9009_write_raw(struct iio_dev *indio_dev, return 0; } -int adrv9009_hdl_loopback(struct adrv9009_rf_phy *phy, bool enable) -{ - struct axiadc_converter *conv = spi_get_drvdata(phy->spi); - struct axiadc_state *st; - unsigned reg, addr, chan, version; - - if (!conv) - return -ENODEV; - - st = iio_priv(conv->indio_dev); - version = axiadc_read(st, 0x4000); - - addr = 0x4418; - - for (chan = 0; chan < conv->chip_info->num_channels; chan++) { - reg = axiadc_read(st, addr + (chan) * 0x40); - - if (enable && reg != 0x8) { - conv->scratch_reg[chan] = reg; - reg = 0x8; - } else if (reg == 0x8) - reg = conv->scratch_reg[chan]; - - axiadc_write(st, addr + (chan) * 0x40, reg); - } - - return 0; -} -EXPORT_SYMBOL(adrv9009_hdl_loopback); - static int adrv9009_post_setup(struct iio_dev *indio_dev) { struct axiadc_state *st = iio_priv(indio_dev); @@ -271,12 +241,6 @@ EXPORT_SYMBOL(adrv9009_spi_to_phy); #else /* CONFIG_CF_AXI_ADC */ -int adrv9009_hdl_loopback(struct adrv9009_rf_phy *phy, bool enable) -{ - return -ENODEV; -} -EXPORT_SYMBOL(adrv9009_hdl_loopback); - int adrv9009_register_axi_converter(struct adrv9009_rf_phy *phy) { struct spi_device *spi = phy->spi; From 3b57537c314ef2e80bc327acafd373631843e5dc Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 14 Jun 2022 08:19:03 +0200 Subject: [PATCH 360/407] iio: adc: ad9371_conv.c: Remove unused ad9371_hdl_loopback function This symbol is not used anywhere. And actually not supported by the JESD204 TPL DAC core. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9371.h | 1 - drivers/iio/adc/ad9371_conv.c | 38 ----------------------------------- 2 files changed, 39 deletions(-) diff --git a/drivers/iio/adc/ad9371.h b/drivers/iio/adc/ad9371.h index 011e72f273a36b..fcfcfdd5d00c95 100644 --- a/drivers/iio/adc/ad9371.h +++ b/drivers/iio/adc/ad9371.h @@ -234,7 +234,6 @@ struct ad9371_rf_phy { bool large_freq_step_cal_en; }; -int ad9371_hdl_loopback(struct ad9371_rf_phy *phy, bool enable); int ad9371_register_axi_converter(struct ad9371_rf_phy *phy); struct ad9371_rf_phy* ad9371_spi_to_phy(struct spi_device *spi); int ad9371_spi_read(struct spi_device *spi, u32 reg); diff --git a/drivers/iio/adc/ad9371_conv.c b/drivers/iio/adc/ad9371_conv.c index 62b52ad51a3509..c560c244f401cd 100644 --- a/drivers/iio/adc/ad9371_conv.c +++ b/drivers/iio/adc/ad9371_conv.c @@ -125,38 +125,6 @@ static int ad9371_write_raw(struct iio_dev *indio_dev, return 0; } -int ad9371_hdl_loopback(struct ad9371_rf_phy *phy, bool enable) -{ - struct axiadc_converter *conv = spi_get_drvdata(phy->spi); - struct axiadc_state *st; - unsigned reg, addr, chan, version; - - if (!conv) - return -ENODEV; - - st = iio_priv(conv->indio_dev); - version = axiadc_read(st, 0x4000); - - /* Still there but implemented a bit different */ - addr = 0x4418; - - for (chan = 0; chan < conv->chip_info->num_channels; chan++) { - reg = axiadc_read(st, addr + (chan) * 0x40); - - if (enable && reg != 0x8) { - conv->scratch_reg[chan] = reg; - reg = 0x8; - } else if (reg == 0x8) { - reg = conv->scratch_reg[chan]; - } - - axiadc_write(st, addr + (chan) * 0x40, reg); - } - - return 0; -} -EXPORT_SYMBOL(ad9371_hdl_loopback); - static int ad9371_post_setup(struct iio_dev *indio_dev) { struct axiadc_state *st = iio_priv(indio_dev); @@ -223,12 +191,6 @@ EXPORT_SYMBOL(ad9371_spi_to_phy); #else /* CONFIG_CF_AXI_ADC */ -int ad9371_hdl_loopback(struct ad9371_rf_phy *phy, bool enable) -{ - return -ENODEV; -} -EXPORT_SYMBOL(ad9371_hdl_loopback); - int ad9371_register_axi_converter(struct ad9371_rf_phy *phy) { struct spi_device *spi = phy->spi; From 7fc0b994a21aad98e7e2b3c2346745873456131a Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 14 Jun 2022 08:30:44 +0200 Subject: [PATCH 361/407] iio: adc: adrv9009_conv: Remove DAC Core settings from the ADC TPL Core This drops the need for overlapping memory regions. The DAC TPL Core driver already sets the RATE and the data format. So this is no longer necessary. Signed-off-by: Michael Hennerich --- drivers/iio/adc/adrv9009_conv.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/iio/adc/adrv9009_conv.c b/drivers/iio/adc/adrv9009_conv.c index e62bacbea066e9..7eed0e893b8381 100644 --- a/drivers/iio/adc/adrv9009_conv.c +++ b/drivers/iio/adc/adrv9009_conv.c @@ -180,15 +180,6 @@ static int adrv9009_post_setup(struct iio_dev *indio_dev) conv->indio_dev = indio_dev; axiadc_write(st, ADI_REG_CNTRL, 0); - if (has_tx_and_en(conv->phy)) { - unsigned tmp; - - tmp = axiadc_read(st, 0x4048); - tmp &= ~BIT(5); - axiadc_write(st, 0x4048, tmp); - axiadc_write(st, 0x404c, 3); /* RATE */ - } - for (i = 0; i < num_chan; i++) { axiadc_write(st, ADI_REG_CHAN_CNTRL_1(i), ADI_DCFILT_OFFSET(0)); @@ -199,7 +190,6 @@ static int adrv9009_post_setup(struct iio_dev *indio_dev) ADI_ENABLE | ADI_IQCOR_ENB); } - return 0; } From bd34ba3dbe07e64882ffdbbdd9052942c4e138f7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 14 Jun 2022 08:32:58 +0200 Subject: [PATCH 362/407] iio: adc: ad9371_conv: Remove DAC Core settings from the ADC TPL Core This drops the need for overlapping memory regions. The DAC TPL Core driver already sets the RATE and the data format. So this is no longer necessary. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9371_conv.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad9371_conv.c b/drivers/iio/adc/ad9371_conv.c index c560c244f401cd..37b9c9cf1a7066 100644 --- a/drivers/iio/adc/ad9371_conv.c +++ b/drivers/iio/adc/ad9371_conv.c @@ -130,18 +130,13 @@ static int ad9371_post_setup(struct iio_dev *indio_dev) struct axiadc_state *st = iio_priv(indio_dev); struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev); - unsigned tmp, num_chan; + unsigned num_chan; int i; num_chan = conv->chip_info->num_channels; conv->indio_dev = indio_dev; axiadc_write(st, ADI_REG_CNTRL, 0); - tmp = axiadc_read(st, 0x4048); - - tmp &= ~BIT(5); - axiadc_write(st, 0x4048, tmp); - axiadc_write(st, 0x404c, 3); /* RATE */ for (i = 0; i < num_chan; i++) { axiadc_write(st, ADI_REG_CHAN_CNTRL_1(i), From bc14419db983d1698008941e4fe20dba5620f191 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 14 Jun 2022 08:36:19 +0200 Subject: [PATCH 363/407] dts: ad9371: Fix JESD204 ADC/DAC TPL Core mappings This drops the overlapping memory regions for the ADC/DAC TPL Cores. In addition the mapping should only cover 8k. This fixes both. Signed-off-by: Michael Hennerich --- arch/arm/boot/dts/socfpga_arria10_socdk_adrv9371.dts | 4 ++-- arch/arm/boot/dts/zynq-zc706-adv7511-adrv9371.dts | 4 ++-- arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9371.dts | 4 ++-- arch/microblaze/boot/dts/kcu105_adrv9371x.dts | 4 ++-- arch/nios2/boot/dts/a10gx_adrv9371.dts | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9371.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9371.dts index 4a52471b315ea5..f8f6961e284496 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9371.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9371.dts @@ -237,7 +237,7 @@ axi_ad9371_rx: axi-ad9371-rx-hpc@50000 { compatible = "adi,axi-ad9371-rx-1.0"; - reg = <0x00050000 0x00008000>; + reg = <0x00050000 0x00002000>; dmas = <&axi_ad9371_rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx0_ad9371>; @@ -245,7 +245,7 @@ axi_ad9371_tx: axi-ad9371-tx-hpc@54000 { compatible = "adi,axi-ad9371-tx-1.0"; - reg = <0x00054000 0x00004000>; + reg = <0x00054000 0x00002000>; dmas = <&axi_ad9371_tx_dma 0>; dma-names = "tx"; clocks = <&trx0_ad9371 2>; diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9371.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9371.dts index 0b98ed05ee7a52..39d18ca4ff839c 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9371.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9371.dts @@ -100,7 +100,7 @@ axi_ad9371_core_rx: axi-ad9371-rx-hpc@44a00000 { compatible = "adi,axi-ad9371-rx-1.0"; - reg = <0x44a00000 0x8000>; + reg = <0x44a00000 0x2000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx0_ad9371>; @@ -119,7 +119,7 @@ axi_ad9371_core_tx: axi-ad9371-tx-hpc@44a04000 { compatible = "adi,axi-ad9371-tx-1.0"; - reg = <0x44a04000 0x4000>; + reg = <0x44a04000 0x2000>; dmas = <&tx_dma 0>; dma-names = "tx"; clocks = <&trx0_ad9371 2>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9371.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9371.dts index 715376ade2246f..7cdab2d142f713 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9371.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9371.dts @@ -109,7 +109,7 @@ axi_ad9371_core_rx: axi-ad9371-rx-hpc@84a00000 { compatible = "adi,axi-ad9371-rx-1.0"; - reg = <0x84a00000 0x8000>; + reg = <0x84a00000 0x2000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx0_ad9371>; @@ -128,7 +128,7 @@ axi_ad9371_core_tx: axi-ad9371-tx-hpc@84a04000 { compatible = "adi,axi-ad9371-tx-1.0"; - reg = <0x84a04000 0x4000>; + reg = <0x84a04000 0x2000>; dmas = <&tx_dma 0>; dma-names = "tx"; clocks = <&trx0_ad9371 2>; diff --git a/arch/microblaze/boot/dts/kcu105_adrv9371x.dts b/arch/microblaze/boot/dts/kcu105_adrv9371x.dts index eeffdc3861e025..ad3d1674ae66f9 100644 --- a/arch/microblaze/boot/dts/kcu105_adrv9371x.dts +++ b/arch/microblaze/boot/dts/kcu105_adrv9371x.dts @@ -28,7 +28,7 @@ &amba_pl { axi_ad9371_core_rx: axi-ad9371-rx-hpc@44a00000 { compatible = "adi,axi-ad9371-rx-1.0"; - reg = <0x44a00000 0x8000>; + reg = <0x44a00000 0x2000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx0_ad9371>; @@ -45,7 +45,7 @@ }; axi_ad9371_core_tx: axi-ad9371-tx-hpc@44a04000 { compatible = "adi,axi-ad9371-tx-1.0"; - reg = <0x44a04000 0x4000>; + reg = <0x44a04000 0x2000>; dmas = <&tx_dma 0>; dma-names = "tx"; clocks = <&trx0_ad9371 2>; diff --git a/arch/nios2/boot/dts/a10gx_adrv9371.dts b/arch/nios2/boot/dts/a10gx_adrv9371.dts index 9a0cfb19e9260c..4fff9b6b339a10 100644 --- a/arch/nios2/boot/dts/a10gx_adrv9371.dts +++ b/arch/nios2/boot/dts/a10gx_adrv9371.dts @@ -470,7 +470,7 @@ axi_ad9371_rx: axi-ad9371-rx-hpc@10050000 { compatible = "adi,axi-ad9371-rx-1.0"; - reg = <0x10050000 0x00008000>; + reg = <0x10050000 0x00002000>; dmas = <&axi_ad9371_rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx0_ad9371>; @@ -478,7 +478,7 @@ axi_ad9371_tx: axi-ad9371-tx-hpc@10054000 { compatible = "adi,axi-ad9371-tx-1.0"; - reg = <0x10054000 0x00004000>; + reg = <0x10054000 0x00002000>; dmas = <&axi_ad9371_tx_dma 0>; dma-names = "tx"; clocks = <&trx0_ad9371 2>; From 5c9e39510f11c399e443a950106c40cf6c147674 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 14 Jun 2022 08:36:40 +0200 Subject: [PATCH 364/407] dts: adrv9009/8: Fix JESD204 ADC/DAC TPL Core mappings This drops the overlapping memory regions for the ADC/DAC TPL Cores. In addition the mapping should only cover 8k. This fixes both. Signed-off-by: Michael Hennerich --- arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts | 4 ++-- arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-1.dts | 2 +- arch/arm/boot/dts/zynq-zc706-adv7511-adrv9009.dts | 4 ++-- arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva.dtsi | 4 ++-- arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9008-1.dts | 2 +- .../boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009-fmcomms8.dts | 4 ++-- arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009.dts | 4 ++-- arch/nios2/boot/dts/a10gx_adrv9009.dts | 4 ++-- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts index d808739ac0b957..a5abe1fb886185 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts @@ -270,7 +270,7 @@ axi_adrv9009_core_rx: axi-adrv9009-rx-hpc@50000 { compatible = "adi,axi-adrv9009-rx-1.0"; - reg = <0x00050000 0x8000>; + reg = <0x00050000 0x2000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx2_adrv9009>; @@ -287,7 +287,7 @@ axi_adrv9009_core_tx: axi-adrv9009-tx-hpc@54000 { compatible = "adi,axi-adrv9009-x2-tx-1.0"; - reg = <0x00054000 0x4000>; + reg = <0x00054000 0x2000>; dmas = <&tx_dma 0>; dma-names = "tx"; clocks = <&trx2_adrv9009 2>; diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-1.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-1.dts index b6913bb454b344..0ec370919d0ed0 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-1.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9008-1.dts @@ -59,7 +59,7 @@ axi_adrv9009_core_rx: axi-adrv9009-rx-hpc@44a00000 { compatible = "adi,axi-adrv9009-rx-1.0"; - reg = <0x44a00000 0x8000>; + reg = <0x44a00000 0x2000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx0_adrv9009>; diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9009.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9009.dts index 4b99d25897710a..b794a690fbc5e5 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9009.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9009.dts @@ -101,7 +101,7 @@ axi_adrv9009_core_rx: axi-adrv9009-rx-hpc@44a00000 { compatible = "adi,axi-adrv9009-rx-1.0"; - reg = <0x44a00000 0x8000>; + reg = <0x44a00000 0x2000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx0_adrv9009>; @@ -120,7 +120,7 @@ axi_adrv9009_core_tx: axi-adrv9009-tx-hpc@44a04000 { compatible = "adi,axi-adrv9009-tx-1.0"; - reg = <0x44a04000 0x4000>; + reg = <0x44a04000 0x2000>; dmas = <&tx_dma 0>; dma-names = "tx"; clocks = <&trx0_adrv9009 2>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva.dtsi index 70b3dff543cc52..f51406e4c91f3b 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp-adrv9009-zu11eg-reva.dtsi @@ -1390,7 +1390,7 @@ axi_adrv9009_core_rx: axi-adrv9009-rx-hpc@84a00000 { compatible = "adi,axi-adrv9009-rx-1.0"; - reg = <0x0 0x84a00000 0x8000>; + reg = <0x0 0x84a00000 0x2000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx0_adrv9009>; @@ -1408,7 +1408,7 @@ axi_adrv9009_core_tx: axi-adrv9009-tx-hpc@84a04000 { compatible = "adi,axi-adrv9009-x2-tx-1.0"; - reg = <0x0 0x84a04000 0x4000>; + reg = <0x0 0x84a04000 0x2000>; dmas = <&tx_dma 0>; dma-names = "tx"; clocks = <&trx0_adrv9009 2>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9008-1.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9008-1.dts index 7867a36bce309e..22603fd1d360a9 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9008-1.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9008-1.dts @@ -66,7 +66,7 @@ axi_adrv9009_core_rx: axi-adrv9009-rx-hpc@84a00000 { compatible = "adi,axi-adrv9009-rx-1.0"; - reg = <0x84a00000 0x8000>; + reg = <0x84a00000 0x2000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx0_adrv9009>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009-fmcomms8.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009-fmcomms8.dts index 21ca4de7a18ca4..fabba975697c15 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009-fmcomms8.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009-fmcomms8.dts @@ -269,7 +269,7 @@ axi_adrv9009_core_rx: axi-adrv9009-rx-hpc@85a00000 { compatible = "adi,axi-adrv9009-rx-1.0"; - reg = <0x85a00000 0x8000>; + reg = <0x85a00000 0x2000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx2_adrv9009>; @@ -287,7 +287,7 @@ axi_adrv9009_core_tx: axi-adrv9009-tx-hpc@85a04000 { compatible = "adi,axi-adrv9009-x2-tx-1.0"; - reg = <0x85a04000 0x4000>; + reg = <0x85a04000 0x2000>; dmas = <&tx_dma 0>; dma-names = "tx"; clocks = <&trx2_adrv9009 2>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009.dts index 38fa4d4a7e50ec..ffeece3b9da2ce 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-adrv9009.dts @@ -128,7 +128,7 @@ axi_adrv9009_core_rx: axi-adrv9009-rx-hpc@84a00000 { compatible = "adi,axi-adrv9009-rx-1.0"; - reg = <0x84a00000 0x8000>; + reg = <0x84a00000 0x2000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx0_adrv9009>; @@ -147,7 +147,7 @@ axi_adrv9009_core_tx: axi-adrv9009-tx-hpc@84a04000 { compatible = "adi,axi-adrv9009-tx-1.0"; - reg = <0x84a04000 0x4000>; + reg = <0x84a04000 0x2000>; dmas = <&tx_dma 0>; dma-names = "tx"; clocks = <&trx0_adrv9009 2>; diff --git a/arch/nios2/boot/dts/a10gx_adrv9009.dts b/arch/nios2/boot/dts/a10gx_adrv9009.dts index 5afdba18274aef..55c9033c83f6cf 100644 --- a/arch/nios2/boot/dts/a10gx_adrv9009.dts +++ b/arch/nios2/boot/dts/a10gx_adrv9009.dts @@ -828,7 +828,7 @@ axi_adrv9009_core_rx: axi-adrv9009-rx-hpc@10060000 { compatible = "adi,axi-adrv9009-rx-1.0"; - reg = <0x10060000 0x00008000>; + reg = <0x10060000 0x00002000>; dmas = <&rx_dma 0>; dma-names = "rx"; spibus-connected = <&trx0_adrv9009>; @@ -836,7 +836,7 @@ axi_adrv9009_core_tx: axi-adrv9009-tx-hpc@10064000 { compatible = "adi,axi-adrv9009-tx-1.0"; - reg = <0x10064000 0x00004000>; + reg = <0x10064000 0x00002000>; dmas = <&tx_dma 0>; dma-names = "tx"; clocks = <&trx0_adrv9009 2>; From d546169f6161ffecfdb0593f473eaee0b8568f4b Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 15 Jun 2022 10:08:53 +0200 Subject: [PATCH 365/407] iio: adc: ad9371_conv: Remove useless variable No functional changes. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9371_conv.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad9371_conv.c b/drivers/iio/adc/ad9371_conv.c index 37b9c9cf1a7066..4ea1a6bf041760 100644 --- a/drivers/iio/adc/ad9371_conv.c +++ b/drivers/iio/adc/ad9371_conv.c @@ -129,16 +129,12 @@ static int ad9371_post_setup(struct iio_dev *indio_dev) { struct axiadc_state *st = iio_priv(indio_dev); struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev); - - unsigned num_chan; int i; - num_chan = conv->chip_info->num_channels; - conv->indio_dev = indio_dev; axiadc_write(st, ADI_REG_CNTRL, 0); - for (i = 0; i < num_chan; i++) { + for (i = 0; i < conv->chip_info->num_channels; i++) { axiadc_write(st, ADI_REG_CHAN_CNTRL_1(i), ADI_DCFILT_OFFSET(0)); axiadc_write(st, ADI_REG_CHAN_CNTRL_2(i), @@ -148,7 +144,6 @@ static int ad9371_post_setup(struct iio_dev *indio_dev) ADI_ENABLE | ADI_IQCOR_ENB); } - return 0; } From 64bd432765b442a2d39c3d68b5d39bf17843adb1 Mon Sep 17 00:00:00 2001 From: Andrei Drimbarean Date: Thu, 16 Jun 2022 14:52:18 +0300 Subject: [PATCH 366/407] arch: arm: boot: dts: rename SPI Engine AXI CLKGEN Having the same node name as the HDMI AXI CLKGEN defined in zynq-zed-adv7511.dtsi caused an error where the clk driver could not be instantiated because it already existed. Signed-off-by: Andrei Drimbarean --- arch/arm/boot/dts/zynq-zed-adv7511-ad7768-1-evb.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/zynq-zed-adv7511-ad7768-1-evb.dts b/arch/arm/boot/dts/zynq-zed-adv7511-ad7768-1-evb.dts index fa6123f3c11be1..82ed046b5b1414 100644 --- a/arch/arm/boot/dts/zynq-zed-adv7511-ad7768-1-evb.dts +++ b/arch/arm/boot/dts/zynq-zed-adv7511-ad7768-1-evb.dts @@ -56,7 +56,7 @@ }; }; - spi_clock: axi-clkgen@44a70000 { + spi_clock: spieng-axi-clkgen@44a70000 { compatible = "adi,axi-clkgen-2.00.a"; reg = <0x44a70000 0x10000>; #clock-cells = <0>; From 8627bbcf7971848273632b7c50ef185f110d089b Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Tue, 21 Jun 2022 10:16:11 +0300 Subject: [PATCH 367/407] drivers: iio: addac: one-bit-adc-dac: Fix read_label() In one_bit_adc_dac_read_label() the number of input channels is being read from st->in_num_ch which is not initialized. Fixes: 88c34541d056 ("drivers: iio: addac: one-bit-adc-dac: Update label storage") Signed-off-by: Sergiu Cuciurean --- drivers/iio/addac/one-bit-adc-dac.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/iio/addac/one-bit-adc-dac.c b/drivers/iio/addac/one-bit-adc-dac.c index 24a650602f9358..4f8abeeb4e7826 100644 --- a/drivers/iio/addac/one-bit-adc-dac.c +++ b/drivers/iio/addac/one-bit-adc-dac.c @@ -142,14 +142,14 @@ static int one_bit_adc_dac_parse_dt(struct iio_dev *indio_dev) { struct one_bit_adc_dac_state *st = iio_priv(indio_dev); struct iio_chan_spec *channels; - int ret, in_num_ch = 0, out_num_ch = 0; + int ret, out_num_ch = 0; st->in_gpio_descs = devm_gpiod_get_array_optional(&st->pdev->dev, "in", GPIOD_IN); if (IS_ERR(st->in_gpio_descs)) return PTR_ERR(st->in_gpio_descs); if (st->in_gpio_descs) - in_num_ch = st->in_gpio_descs->ndescs; + st->in_num_ch = st->in_gpio_descs->ndescs; st->out_gpio_descs = devm_gpiod_get_array_optional(&st->pdev->dev, "out", GPIOD_OUT_LOW); if (IS_ERR(st->out_gpio_descs)) @@ -157,26 +157,25 @@ static int one_bit_adc_dac_parse_dt(struct iio_dev *indio_dev) if (st->out_gpio_descs) out_num_ch = st->out_gpio_descs->ndescs; - - channels = devm_kcalloc(indio_dev->dev.parent, in_num_ch + out_num_ch, + channels = devm_kcalloc(indio_dev->dev.parent, st->in_num_ch + out_num_ch, sizeof(*channels), GFP_KERNEL); if (!channels) return -ENOMEM; - ret = one_bit_adc_dac_set_ch(&channels[0], in_num_ch, CH_IN); + ret = one_bit_adc_dac_set_ch(&channels[0], st->in_num_ch, CH_IN); if (ret) return ret; - ret = one_bit_adc_dac_set_ch(&channels[in_num_ch], out_num_ch, CH_OUT); + ret = one_bit_adc_dac_set_ch(&channels[st->in_num_ch], out_num_ch, CH_OUT); if (ret) return ret; - ret = one_bit_adc_dac_set_channel_label(indio_dev, channels, in_num_ch + out_num_ch); + ret = one_bit_adc_dac_set_channel_label(indio_dev, channels, st->in_num_ch + out_num_ch); if (ret) return ret; indio_dev->channels = channels; - indio_dev->num_channels = in_num_ch + out_num_ch; + indio_dev->num_channels = st->in_num_ch + out_num_ch; return 0; } From 57bcd7d945eea3191f4f184e13d48557add28499 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Tue, 21 Jun 2022 10:16:31 +0300 Subject: [PATCH 368/407] drivers: iio: addac: one-bit-adc-dac: Remove unused var Remove unused member from the device structure. Signed-off-by: Sergiu Cuciurean --- drivers/iio/addac/one-bit-adc-dac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/addac/one-bit-adc-dac.c b/drivers/iio/addac/one-bit-adc-dac.c index 4f8abeeb4e7826..38bb47525013a5 100644 --- a/drivers/iio/addac/one-bit-adc-dac.c +++ b/drivers/iio/addac/one-bit-adc-dac.c @@ -19,7 +19,6 @@ enum ch_direction { struct one_bit_adc_dac_state { int in_num_ch; - int out_num_ch; struct platform_device *pdev; struct gpio_descs *in_gpio_descs; struct gpio_descs *out_gpio_descs; From d01347fe0beedcf4dfc710ea3898f03307b096d0 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 27 Jun 2022 10:42:58 +0200 Subject: [PATCH 369/407] dts: vcu118_ad9081.dts: Drop redundant axi-dmac channel nodes These are no longer needed. Signed-off-by: Michael Hennerich --- arch/microblaze/boot/dts/vcu118_ad9081.dts | 25 ---------------------- 1 file changed, 25 deletions(-) diff --git a/arch/microblaze/boot/dts/vcu118_ad9081.dts b/arch/microblaze/boot/dts/vcu118_ad9081.dts index 0bb681486c843e..d752df76692bc6 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081.dts @@ -41,19 +41,6 @@ interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <256>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <256>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: dma@7c430000 { @@ -65,18 +52,6 @@ interrupts = <13 2>; clocks = <&clk_bus_0>; - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <256>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <256>; - adi,destination-bus-type = <2>; - }; - }; }; axi_ad9081_core_rx: axi-ad9081-rx-hpc@44a10000 { From c179ef2aa6cfdcf12ae4a0a9b572126f1522aaaf Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 27 Jun 2022 10:44:12 +0200 Subject: [PATCH 370/407] dts: vcu118_ad9081.dts: Add axi-data-offload engine support This adds device nodes for the axi-data-offload engine. Signed-off-by: Michael Hennerich --- arch/microblaze/boot/dts/vcu118_ad9081.dts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/microblaze/boot/dts/vcu118_ad9081.dts b/arch/microblaze/boot/dts/vcu118_ad9081.dts index d752df76692bc6..7a1f70bc811303 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081.dts @@ -75,6 +75,7 @@ clock-names = "sampl_clk"; spibus-connected = <&trx0_ad9081>; adi,axi-pl-fifo-enable; + adi,axi-data-offload-connected = <&axi_data_offload_tx>; jesd204-device; #jesd204-cells = <2>; @@ -161,6 +162,16 @@ compatible = "adi,axi-sysid-1.00.a"; reg = <0x45000000 0x10000>; }; + + axi_data_offload_rx: data_offload_rx@7c450000 { + compatible = "adi,axi-data-offload-1.0.a"; + reg = <0x7c450000 0x10000>; + }; + + axi_data_offload_tx: data_offload_tx@7c440000 { + compatible = "adi,axi-data-offload-1.0.a"; + reg = <0x7c440000 0x10000>; + }; }; #include "adi-ad9081-fmc-ebz.dtsi" From 84bf8b8b4054d3c5f5866930defdc4e592c47ed8 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 27 Jun 2022 10:45:43 +0200 Subject: [PATCH 371/407] dts: vcu128_ad9081.dts: Fix axi-data-offload node names These need to be unique otherwise debugfs entries are not generated. Signed-off-by: Michael Hennerich --- arch/microblaze/boot/dts/vcu128_ad9081.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/microblaze/boot/dts/vcu128_ad9081.dts b/arch/microblaze/boot/dts/vcu128_ad9081.dts index 96cc4874b6ee1e..71d76e13dd1973 100644 --- a/arch/microblaze/boot/dts/vcu128_ad9081.dts +++ b/arch/microblaze/boot/dts/vcu128_ad9081.dts @@ -188,12 +188,12 @@ reg = <0x45000000 0x10000>; }; - axi_data_offload_rx: data_offload@7c450000 { + axi_data_offload_rx: data_offload_rx@7c450000 { compatible = "adi,axi-data-offload-1.0.a"; reg = <0x7c450000 0x10000>; }; - axi_data_offload_tx: data_offload@7c440000 { + axi_data_offload_tx: data_offload_tx@7c440000 { compatible = "adi,axi-data-offload-1.0.a"; reg = <0x7c440000 0x10000>; }; From 03abe91f4a47f1bdd3846b8dfb9ad93d5bed0942 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 27 Jun 2022 11:23:36 +0200 Subject: [PATCH 372/407] dts: microblaze: vcu118_quad_ad908*: Fix typo ADRF4360 -> ADF4371 No functional changes. Signed-off-by: Michael Hennerich --- ...vcu118_quad_ad9081_204b_txmode_5_rxmode_6.dts | 16 ++++++++-------- ...cu118_quad_ad9081_204b_txmode_9_rxmode_10.dts | 14 +++++++------- ...u118_quad_ad9081_204c_txmode_10_rxmode_11.dts | 12 ++++++------ ...cu118_quad_ad9081_204c_txmode_11_rxmode_4.dts | 12 ++++++------ ...quad_ad9081_204c_txmode_23_rxmode_25_revc.dts | 12 ++++++------ ...quad_ad9081_204c_txmode_29_rxmode_24_revc.dts | 12 ++++++------ ...u118_quad_ad9082_204c_txmode_12_rxmode_13.dts | 12 ++++++------ ...u118_quad_ad9082_204c_txmode_23_rxmode_25.dts | 12 ++++++------ ...vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts | 12 ++++++------ 9 files changed, 57 insertions(+), 57 deletions(-) diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6.dts index ae4271f342aed4..bb5080e9fd1365 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_5_rxmode_6.dts @@ -29,15 +29,15 @@ // * DAC-Side JESD204B Lane Rate: 5.00Gbps // * ADC-Side JESD204B Lane Rate: 5.00Gbps -#define ADRF4360_RFx_FREQUENCY_HZ 4000000000 +#define ADF4371_RFx_FREQUENCY_HZ 4000000000 #define HMC7043_FPGA_XCVR_CLKDIV 2 #define HMC7043_FPGA_LINK_CLKDIV 4 #define HMC7043_SYSREF_CLKDIV 256 #define HMC7043_SYSREF_TIMER (HMC7043_SYSREF_CLKDIV * 4) -#define AD9081_DAC_FREQUENCY ADRF4360_RFx_FREQUENCY_HZ -#define AD9081_ADC_FREQUENCY ADRF4360_RFx_FREQUENCY_HZ +#define AD9081_DAC_FREQUENCY ADF4371_RFx_FREQUENCY_HZ +#define AD9081_ADC_FREQUENCY ADF4371_RFx_FREQUENCY_HZ /* TX path */ #define AD9081_TX_MAIN_INTERPOLATION 4 @@ -108,7 +108,7 @@ adrf5020_ctrl { gpio-hog; gpios = <34 GPIO_ACTIVE_HIGH>; -#if ADRF4360_RFx_FREQUENCY_HZ < 8000000000 +#if ADF4371_RFx_FREQUENCY_HZ < 8000000000 #define ADF4371_OUTPUT 1 output-low; /* output-low for the RF2 <-> clk-rfaux8 output */ #else @@ -122,28 +122,28 @@ &adf4371_clk0 { channel@ADF4371_OUTPUT { reg = ; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk1 { channel@ADF4371_OUTPUT { reg = ; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk2 { channel@ADF4371_OUTPUT { reg = ; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk3 { channel@ADF4371_OUTPUT { reg = ; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts index 9f702b2856612d..43d2e94742ab08 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts @@ -29,8 +29,8 @@ // * DAC-Side JESD204B Lane Rate: 10.00Gbps // * ADC-Side JESD204B Lane Rate: 10.00Gbps -#define ADRF4360_RF16_FREQUENCY_HZ 12000000000 -//#define ADRF4360_RF16_FREQUENCY_HZ 500000000 +#define ADF4371_RF16_FREQUENCY_HZ 12000000000 +//#define ADF4371_RF16_FREQUENCY_HZ 500000000 #define HMC7043_FPGA_XCVR_CLKDIV 1 #define HMC7043_FPGA_LINK_CLKDIV 2 @@ -38,7 +38,7 @@ #define HMC7043_SYSREF_TIMER (HMC7043_SYSREF_CLKDIV * 4) -#define AD9081_DAC_FREQUENCY ADRF4360_RF16_FREQUENCY_HZ +#define AD9081_DAC_FREQUENCY ADF4371_RF16_FREQUENCY_HZ #define AD9081_ADC_FREQUENCY 4000000000 /* TX path */ @@ -213,28 +213,28 @@ &adf4371_clk0 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk1 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk2 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk3 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts index 5595383d8a2aeb..d76da06e880ac4 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts @@ -21,7 +21,7 @@ // TX JESD204C MODE 10, M=4, L=4 // RX JESD204C MODE 11, M=4, L=4 -#define ADRF4360_RF16_FREQUENCY_HZ 12000000000 +#define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 2 #define HMC7043_FPGA_LINK_CLKDIV_TX 2 @@ -29,7 +29,7 @@ #define HMC7043_SYSREF_CLKDIV 1024 // Later try setting this to 128 to see if it still works #define HMC7043_SYSREF_TIMER (HMC7043_SYSREF_CLKDIV * 4) -#define AD9081_DAC_FREQUENCY ADRF4360_RF16_FREQUENCY_HZ +#define AD9081_DAC_FREQUENCY ADF4371_RF16_FREQUENCY_HZ #define AD9081_ADC_FREQUENCY 4000000000 /* TX path */ @@ -146,28 +146,28 @@ &adf4371_clk0 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk1 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk2 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk3 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts index c97c9f0a3b7411..57dcf2d70ba97e 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts @@ -21,7 +21,7 @@ // TX JESD204C MODE 11, M=16, L=4 // RX JESD204C MODE 4, M=8, L=2 -#define ADRF4360_RF16_FREQUENCY_HZ 12000000000 +#define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 2 #define HMC7043_FPGA_LINK_CLKDIV_TX 2 @@ -29,7 +29,7 @@ #define HMC7043_SYSREF_CLKDIV 256 #define HMC7043_SYSREF_TIMER (HMC7043_SYSREF_CLKDIV * 4) -#define AD9081_DAC_FREQUENCY ADRF4360_RF16_FREQUENCY_HZ +#define AD9081_DAC_FREQUENCY ADF4371_RF16_FREQUENCY_HZ #define AD9081_ADC_FREQUENCY 4000000000 /* TX path */ @@ -148,28 +148,28 @@ &adf4371_clk0 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk1 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk2 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk3 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts index a0d65195de64ca..4e04ff5d6f56f3 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts @@ -47,14 +47,14 @@ // RX_KS_PER_CHANNEL=16 // TX_KS_PER_CHANNEL=16 -#define ADRF4360_RF16_FREQUENCY_HZ 12000000000 +#define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 2 #define HMC7043_FPGA_LINK_CLKDIV_TX 2 #define HMC7043_FPGA_LINK_CLKDIV_RX 2 #define HMC7043_SYSREF_CLKDIV 1024 -#define AD9081_DAC_FREQUENCY ADRF4360_RF16_FREQUENCY_HZ +#define AD9081_DAC_FREQUENCY ADF4371_RF16_FREQUENCY_HZ #define AD9081_ADC_FREQUENCY 4000000000 /* TX path */ @@ -196,28 +196,28 @@ &adf4371_clk0 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk1 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk2 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk3 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts index 52d52e9f264d46..9315d76cca7340 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts @@ -47,14 +47,14 @@ // RX_KS_PER_CHANNEL=16 // TX_KS_PER_CHANNEL=16 -#define ADRF4360_RF16_FREQUENCY_HZ 12000000000 +#define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 2 #define HMC7043_FPGA_LINK_CLKDIV_TX 2 #define HMC7043_FPGA_LINK_CLKDIV_RX 2 #define HMC7043_SYSREF_CLKDIV 1024 -#define AD9081_DAC_FREQUENCY ADRF4360_RF16_FREQUENCY_HZ +#define AD9081_DAC_FREQUENCY ADF4371_RF16_FREQUENCY_HZ #define AD9081_ADC_FREQUENCY 4000000000 /* TX path */ @@ -196,28 +196,28 @@ &adf4371_clk0 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk1 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk2 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk3 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts index 898c7b872fb649..b8a3cae3440ab2 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts @@ -49,14 +49,14 @@ // RX_KS_PER_CHANNEL=64 // TX_KS_PER_CHANNEL=64 -#define ADRF4360_RF16_FREQUENCY_HZ 12000000000 +#define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 3 #define HMC7043_FPGA_LINK_CLKDIV_TX 2 #define HMC7043_FPGA_LINK_CLKDIV_RX 2 #define HMC7043_SYSREF_CLKDIV 1024 -#define AD9081_DAC_FREQUENCY ADRF4360_RF16_FREQUENCY_HZ +#define AD9081_DAC_FREQUENCY ADF4371_RF16_FREQUENCY_HZ #define AD9081_ADC_FREQUENCY 6000000000 /* TX path */ @@ -169,28 +169,28 @@ &adf4371_clk0 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk1 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk2 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk3 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts index e4f6a1e10cc829..9715abcf0bca31 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts @@ -47,14 +47,14 @@ // RX_KS_PER_CHANNEL=16 // TX_KS_PER_CHANNEL=16 -#define ADRF4360_RF16_FREQUENCY_HZ 12000000000 +#define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 2 #define HMC7043_FPGA_LINK_CLKDIV_TX 2 #define HMC7043_FPGA_LINK_CLKDIV_RX 2 #define HMC7043_SYSREF_CLKDIV 1024 -#define AD9081_DAC_FREQUENCY ADRF4360_RF16_FREQUENCY_HZ +#define AD9081_DAC_FREQUENCY ADF4371_RF16_FREQUENCY_HZ #define AD9081_ADC_FREQUENCY 6000000000 /* TX path */ @@ -182,28 +182,28 @@ &adf4371_clk0 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk1 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk2 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk3 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts index 0c4a9372c5c2c3..27c8fe9f5f1e9d 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts @@ -45,14 +45,14 @@ // RX_KS_PER_CHANNEL=16 // TX_KS_PER_CHANNEL=16 -#define ADRF4360_RF16_FREQUENCY_HZ 12000000000 +#define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 2 #define HMC7043_FPGA_LINK_CLKDIV_TX 2 #define HMC7043_FPGA_LINK_CLKDIV_RX 2 #define HMC7043_SYSREF_CLKDIV 1024 -#define AD9081_DAC_FREQUENCY ADRF4360_RF16_FREQUENCY_HZ +#define AD9081_DAC_FREQUENCY ADF4371_RF16_FREQUENCY_HZ #define AD9081_ADC_FREQUENCY 6000000000 /* TX path */ @@ -165,28 +165,28 @@ &adf4371_clk0 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk1 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk2 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; &adf4371_clk3 { channel@2 { reg = <2>; - adi,power-up-frequency = /bits/ 64 ; + adi,power-up-frequency = /bits/ 64 ; }; }; From a0a9fd1775027c76349c53758bc3153cdfde8073 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 27 Jun 2022 12:30:13 +0200 Subject: [PATCH 373/407] dts: vcu118_quad_ad908*: Add HDL Synthesis Parameters comments This adds the parameters used to synthesize the FPGA project. No functional changes. Signed-off-by: Michael Hennerich --- ...rxmode_10_onchip_pll_nshot_sysref_revc.dts | 11 +++++- ...onchip_pll_nshot_sysref_secondary_revc.dts | 11 +++++- ...04b_txmode_9_rxmode_10_onchip_pll_revc.dts | 11 +++++- ...txmode_9_rxmode_10_onchip_pll_revc_nz1.dts | 11 +++++- ...ad_ad9081_204b_txmode_9_rxmode_10_revc.dts | 11 +++++- ...d9081_204b_txmode_9_rxmode_10_revc_nz1.dts | 11 +++++- ...8_quad_ad9081_204c_txmode_10_rxmode_11.dts | 16 +++++++- ...4c_txmode_10_rxmode_11_onchip_pll_revc.dts | 16 +++++++- ...xmode_10_rxmode_11_onchip_pll_revc_nz1.dts | 16 +++++++- ...d_ad9081_204c_txmode_10_rxmode_11_revc.dts | 16 +++++++- ...9081_204c_txmode_10_rxmode_11_revc_nz1.dts | 16 +++++++- ...18_quad_ad9081_204c_txmode_11_rxmode_4.dts | 16 +++++++- ...9081_204c_txmode_11_rxmode_4_direct_6g.dts | 16 +++++++- ...04c_txmode_11_rxmode_4_onchip_pll_revc.dts | 16 +++++++- ...txmode_11_rxmode_4_onchip_pll_revc_nz1.dts | 16 +++++++- ...ad_ad9081_204c_txmode_11_rxmode_4_revc.dts | 16 +++++++- ...d9081_204c_txmode_11_rxmode_4_revc_nz1.dts | 16 +++++++- ...4c_txmode_23_rxmode_25_onchip_pll_revc.dts | 20 +++++++++- ...xmode_23_rxmode_25_onchip_pll_revc_nz1.dts | 20 +++++++++- ...d_ad9081_204c_txmode_23_rxmode_25_revc.dts | 38 +++++++++---------- ...9081_204c_txmode_23_rxmode_25_revc_nz1.dts | 22 ++++++++++- ...4c_txmode_29_rxmode_24_onchip_pll_revc.dts | 20 +++++++++- ...xmode_29_rxmode_24_onchip_pll_revc_nz1.dts | 20 +++++++++- ...d_ad9081_204c_txmode_29_rxmode_24_revc.dts | 38 +++++++++---------- ...9081_204c_txmode_29_rxmode_24_revc_nz1.dts | 20 +++++++++- ...8_quad_ad9082_204c_txmode_12_rxmode_13.dts | 38 +++++++++---------- ...82_204c_txmode_12_rxmode_13_onchip_pll.dts | 20 +++++++++- ...8_quad_ad9082_204c_txmode_23_rxmode_25.dts | 38 +++++++++---------- ...82_204c_txmode_23_rxmode_25_onchip_pll.dts | 20 +++++++++- ...118_quad_ad9082_204c_txmode_3_rxmode_2.dts | 34 ++++++++--------- ...9082_204c_txmode_3_rxmode_2_onchip_pll.dts | 18 ++++++++- 31 files changed, 488 insertions(+), 120 deletions(-) diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_nshot_sysref_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_nshot_sysref_revc.dts index ee595c4dbdd728..9e08fda6add402 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_nshot_sysref_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_nshot_sysref_revc.dts @@ -8,9 +8,18 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=8B10B +// RX_JESD_M=8 +// RX_JESD_L=4 +// RX_JESD_S=1 +// TX_JESD_M=8 +// TX_JESD_L=4 +// TX_JESD_S=1 + #include "vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_revc.dts" #include #include diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_nshot_sysref_secondary_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_nshot_sysref_secondary_revc.dts index b28961b959b8bb..2b186787ea073c 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_nshot_sysref_secondary_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_nshot_sysref_secondary_revc.dts @@ -8,9 +8,18 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=8B10B +// RX_JESD_M=8 +// RX_JESD_L=4 +// RX_JESD_S=1 +// TX_JESD_M=8 +// TX_JESD_L=4 +// TX_JESD_S=1 + #include "vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_revc.dts" #include #include diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_revc.dts index ac35eae11ea7c7..cd8a3d02f18324 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_revc.dts @@ -8,9 +8,18 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=8B10B +// RX_JESD_M=8 +// RX_JESD_L=4 +// RX_JESD_S=1 +// TX_JESD_M=8 +// TX_JESD_L=4 +// TX_JESD_S=1 + // For MxFE0 // * Cap rotate: DNI C886, Populate C1118 // * Cap rotate: DNI C887, Populate C1119 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_revc_nz1.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_revc_nz1.dts index a350ffc315ae86..2a55ca689455ac 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_revc_nz1.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_onchip_pll_revc_nz1.dts @@ -8,9 +8,18 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=8B10B +// RX_JESD_M=8 +// RX_JESD_L=4 +// RX_JESD_S=1 +// TX_JESD_M=8 +// TX_JESD_L=4 +// TX_JESD_S=1 + #include #define AD9081_TX_MAIN_NCO_SHIFT 1000000000 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_revc.dts index 36a51e2df26ed8..8dbf76e2baf572 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_revc.dts @@ -8,9 +8,18 @@ * hdl_project: * board_revision: * - * Copyright (C) 2019-2020 Analog Devices Inc. + * Copyright (C) 2019-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=8B10B +// RX_JESD_M=8 +// RX_JESD_L=4 +// RX_JESD_S=1 +// TX_JESD_M=8 +// TX_JESD_L=4 +// TX_JESD_S=1 + #include "vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts" / { diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_revc_nz1.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_revc_nz1.dts index 9b3a0fdb741a1e..d3a3d21d48b01a 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_revc_nz1.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10_revc_nz1.dts @@ -8,9 +8,18 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=8B10B +// RX_JESD_M=8 +// RX_JESD_L=4 +// RX_JESD_S=1 +// TX_JESD_M=8 +// TX_JESD_L=4 +// TX_JESD_S=1 + #include #define AD9081_TX_MAIN_NCO_SHIFT 1000000000 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts index d76da06e880ac4..c45c9eb9e489e8 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts @@ -8,9 +8,23 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2019-2020 Analog Devices Inc. + * Copyright (C) 2019-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=4 +// RX_JESD_L=4 +// RX_JESD_S=1 +// TX_JESD_M=4 +// TX_JESD_L=4 +// TX_JESD_S=1 +// RX_KS_PER_CHANNEL=64 +// TX_KS_PER_CHANNEL=16 + #include #include #include diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_onchip_pll_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_onchip_pll_revc.dts index 7f1edf34ca43bb..692e2f84f5609d 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_onchip_pll_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_onchip_pll_revc.dts @@ -8,9 +8,23 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=4 +// RX_JESD_L=4 +// RX_JESD_S=1 +// TX_JESD_M=4 +// TX_JESD_L=4 +// TX_JESD_S=1 +// RX_KS_PER_CHANNEL=64 +// TX_KS_PER_CHANNEL=16 + // For MxFE0 // * Cap rotate: DNI C886, Populate C1118 // * Cap rotate: DNI C887, Populate C1119 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_onchip_pll_revc_nz1.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_onchip_pll_revc_nz1.dts index 0c29ddb0ff42cc..0db4c95287e383 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_onchip_pll_revc_nz1.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_onchip_pll_revc_nz1.dts @@ -8,9 +8,23 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=4 +// RX_JESD_L=4 +// RX_JESD_S=1 +// TX_JESD_M=4 +// TX_JESD_L=4 +// TX_JESD_S=1 +// RX_KS_PER_CHANNEL=64 +// TX_KS_PER_CHANNEL=16 + #include #define AD9081_TX_MAIN_NCO_SHIFT 1000000000 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_revc.dts index ea55388076c1e8..6dcf938cb50cd1 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_revc.dts @@ -8,9 +8,23 @@ * hdl_project: * board_revision: * - * Copyright (C) 2019-2020 Analog Devices Inc. + * Copyright (C) 2019-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=4 +// RX_JESD_L=4 +// RX_JESD_S=1 +// TX_JESD_M=4 +// TX_JESD_L=4 +// TX_JESD_S=1 +// RX_KS_PER_CHANNEL=64 +// TX_KS_PER_CHANNEL=16 + #include "vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts" / { diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_revc_nz1.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_revc_nz1.dts index 10eb9bc7028950..c2f7ed449ac26f 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_revc_nz1.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11_revc_nz1.dts @@ -8,9 +8,23 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=4 +// RX_JESD_L=4 +// RX_JESD_S=1 +// TX_JESD_M=4 +// TX_JESD_L=4 +// TX_JESD_S=1 +// RX_KS_PER_CHANNEL=64 +// TX_KS_PER_CHANNEL=16 + #include #define AD9081_TX_MAIN_NCO_SHIFT 1000000000 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts index 57dcf2d70ba97e..ce900ed7d45cc0 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts @@ -8,9 +8,23 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2019-2020 Analog Devices Inc. + * Copyright (C) 2019-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=8 +// RX_JESD_L=2 +// RX_JESD_S=1 +// TX_JESD_M=16 +// TX_JESD_L=4 +// TX_JESD_S=1 +// RX_KS_PER_CHANNEL=32 +// TX_KS_PER_CHANNEL=16 + #include #include #include diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts index ca7a0b523fb7a2..7fbe8634adec53 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts @@ -8,9 +8,23 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2019-2020 Analog Devices Inc. + * Copyright (C) 2019-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=8 +// RX_JESD_L=2 +// RX_JESD_S=1 +// TX_JESD_M=16 +// TX_JESD_L=4 +// TX_JESD_S=1 +// RX_KS_PER_CHANNEL=32 +// TX_KS_PER_CHANNEL=16 + #include #include #include diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_onchip_pll_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_onchip_pll_revc.dts index e12dd8fda6cadd..094559f9ae97f8 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_onchip_pll_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_onchip_pll_revc.dts @@ -8,9 +8,23 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=8 +// RX_JESD_L=2 +// RX_JESD_S=1 +// TX_JESD_M=16 +// TX_JESD_L=4 +// TX_JESD_S=1 +// RX_KS_PER_CHANNEL=32 +// TX_KS_PER_CHANNEL=16 + // For MxFE0 // * Cap rotate: DNI C886, Populate C1118 // * Cap rotate: DNI C887, Populate C1119 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_onchip_pll_revc_nz1.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_onchip_pll_revc_nz1.dts index 25abf24c817677..d0227829fb0143 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_onchip_pll_revc_nz1.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_onchip_pll_revc_nz1.dts @@ -8,9 +8,23 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=8 +// RX_JESD_L=2 +// RX_JESD_S=1 +// TX_JESD_M=16 +// TX_JESD_L=4 +// TX_JESD_S=1 +// RX_KS_PER_CHANNEL=32 +// TX_KS_PER_CHANNEL=16 + #include #define AD9081_TX_MAIN_NCO_SHIFT 1000000000 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_revc.dts index ed25f955685b8c..83bdf29a1ace97 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_revc.dts @@ -8,9 +8,23 @@ * hdl_project: * board_revision: * - * Copyright (C) 2019-2020 Analog Devices Inc. + * Copyright (C) 2019-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=8 +// RX_JESD_L=2 +// RX_JESD_S=1 +// TX_JESD_M=16 +// TX_JESD_L=4 +// TX_JESD_S=1 +// RX_KS_PER_CHANNEL=32 +// TX_KS_PER_CHANNEL=16 + #include "vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts" / { diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_revc_nz1.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_revc_nz1.dts index ec2bfd836941ff..30ac94f20af0cd 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_revc_nz1.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_revc_nz1.dts @@ -8,9 +8,23 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=8 +// RX_JESD_L=2 +// RX_JESD_S=1 +// TX_JESD_M=16 +// TX_JESD_L=4 +// TX_JESD_S=1 +// RX_KS_PER_CHANNEL=32 +// TX_KS_PER_CHANNEL=16 + #include #define AD9081_TX_MAIN_NCO_SHIFT 1000000000 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_onchip_pll_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_onchip_pll_revc.dts index 5f5c1b14c42a8d..e23e5a292eabdf 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_onchip_pll_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_onchip_pll_revc.dts @@ -8,9 +8,27 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=24.75 +// TX_RATE=24.75 +// REF_CLK_RATE=250 +// RX_JESD_M=4 +// RX_JESD_L=4 +// RX_JESD_S=2 +// RX_JESD_NP=12 +// TX_JESD_M=4 +// TX_JESD_L=4 +// TX_JESD_S=2 +// TX_JESD_NP=12 +// RX_PLL_SEL=1 +// TX_PLL_SEL=1 +// RX_KS_PER_CHANNEL=16 +// TX_KS_PER_CHANNEL=16 + // For MxFE0 // * Cap rotate: DNI C886, Populate C1118 // * Cap rotate: DNI C887, Populate C1119 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_onchip_pll_revc_nz1.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_onchip_pll_revc_nz1.dts index 2e3be7613c56c6..86cc5f958cdf07 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_onchip_pll_revc_nz1.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_onchip_pll_revc_nz1.dts @@ -8,9 +8,27 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=24.75 +// TX_RATE=24.75 +// REF_CLK_RATE=250 +// RX_JESD_M=4 +// RX_JESD_L=4 +// RX_JESD_S=2 +// RX_JESD_NP=12 +// TX_JESD_M=4 +// TX_JESD_L=4 +// TX_JESD_S=2 +// TX_JESD_NP=12 +// RX_PLL_SEL=1 +// TX_PLL_SEL=1 +// RX_KS_PER_CHANNEL=16 +// TX_KS_PER_CHANNEL=16 + #include #define AD9081_TX_MAIN_NCO_SHIFT 1000000000 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts index 4e04ff5d6f56f3..2523234827cef7 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts @@ -8,27 +8,9 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2019-2020 Analog Devices Inc. + * Copyright (C) 2019-2022 Analog Devices Inc. */ -#include -#include -#include - -#include "vcu118_quad_ad9081.dtsi" - -// This setup assumes 500MHz clock into J41 (0 dBm) -// ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps: Np 12 use case with high lane rate -// * 2Txs / 2Rxs per MxFE -// * DAC_CLK = 12GSPS -// * ADC_CLK = 4GSPS -// * Tx I/Q Rate: 2 GSPS (Interpolation of 6x1) -// * Rx I/Q Rate: 2 GSPS (Decimation of 2x1) -// * DAC JESD204C: Mode 23, L=4, M=4, N=N'=12 -// * ADC JESD204C: Mode 25, L=4, M=4, N=N'=12 -// * DAC-Side JESD204C Lane Rate: 24.75Gbps -// * ADC-Side JESD204C Lane Rate: 24.75Gbps - // HDL Synthesis Parameters: // JESD_MODE=64B66B // RX_RATE=24.75 @@ -47,6 +29,24 @@ // RX_KS_PER_CHANNEL=16 // TX_KS_PER_CHANNEL=16 +#include +#include +#include + +#include "vcu118_quad_ad9081.dtsi" + +// This setup assumes 500MHz clock into J41 (0 dBm) +// ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps: Np 12 use case with high lane rate +// * 2Txs / 2Rxs per MxFE +// * DAC_CLK = 12GSPS +// * ADC_CLK = 4GSPS +// * Tx I/Q Rate: 2 GSPS (Interpolation of 6x1) +// * Rx I/Q Rate: 2 GSPS (Decimation of 2x1) +// * DAC JESD204C: Mode 23, L=4, M=4, N=N'=12 +// * ADC JESD204C: Mode 25, L=4, M=4, N=N'=12 +// * DAC-Side JESD204C Lane Rate: 24.75Gbps +// * ADC-Side JESD204C Lane Rate: 24.75Gbps + #define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 2 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc_nz1.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc_nz1.dts index 1de6909a54478b..e226ce32e875ad 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc_nz1.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc_nz1.dts @@ -8,9 +8,27 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=24.75 +// TX_RATE=24.75 +// REF_CLK_RATE=250 +// RX_JESD_M=4 +// RX_JESD_L=4 +// RX_JESD_S=2 +// RX_JESD_NP=12 +// TX_JESD_M=4 +// TX_JESD_L=4 +// TX_JESD_S=2 +// TX_JESD_NP=12 +// RX_PLL_SEL=1 +// TX_PLL_SEL=1 +// RX_KS_PER_CHANNEL=16 +// TX_KS_PER_CHANNEL=16 + #include #define AD9081_TX_MAIN_NCO_SHIFT 1000000000 @@ -25,4 +43,4 @@ / { model = "Analog Devices AD-QUADMXFE2-EBZ"; -}; \ No newline at end of file +}; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_onchip_pll_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_onchip_pll_revc.dts index 8bbe9d2a405177..5287474cdeb496 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_onchip_pll_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_onchip_pll_revc.dts @@ -8,9 +8,27 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=24.75 +// TX_RATE=24.75 +// REF_CLK_RATE=250 +// RX_JESD_M=8 +// RX_JESD_L=4 +// RX_JESD_S=1 +// RX_JESD_NP=12 +// TX_JESD_M=8 +// TX_JESD_L=4 +// TX_JESD_S=1 +// TX_JESD_NP=12 +// RX_PLL_SEL=1 +// TX_PLL_SEL=1 +// RX_KS_PER_CHANNEL=16 +// TX_KS_PER_CHANNEL=16 + // For MxFE0 // * Cap rotate: DNI C886, Populate C1118 // * Cap rotate: DNI C887, Populate C1119 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_onchip_pll_revc_nz1.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_onchip_pll_revc_nz1.dts index 215fd727defdcd..be2debba9ac553 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_onchip_pll_revc_nz1.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_onchip_pll_revc_nz1.dts @@ -8,9 +8,27 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=24.75 +// TX_RATE=24.75 +// REF_CLK_RATE=250 +// RX_JESD_M=8 +// RX_JESD_L=4 +// RX_JESD_S=1 +// RX_JESD_NP=12 +// TX_JESD_M=8 +// TX_JESD_L=4 +// TX_JESD_S=1 +// TX_JESD_NP=12 +// RX_PLL_SEL=1 +// TX_PLL_SEL=1 +// RX_KS_PER_CHANNEL=16 +// TX_KS_PER_CHANNEL=16 + #include #define AD9081_TX_MAIN_NCO_SHIFT 1000000000 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts index 9315d76cca7340..becb6e6956df8e 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts @@ -8,27 +8,9 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2019-2020 Analog Devices Inc. + * Copyright (C) 2019-2022 Analog Devices Inc. */ -#include -#include -#include - -#include "vcu118_quad_ad9081.dtsi" - -// This setup assumes 500MHz clock into J41 (0 dBm) -// ad9081_204c_txmode_29_rxmode_24_lr_24_75Gbps: Np 12 use case with high lane rate -// * 8Txs / 8Rxs per MxFE -// * DAC_CLK = 12GSPS -// * ADC_CLK = 4GSPS -// * Tx I/Q Rate: 1 GSPS (Interpolation of 12x1) -// * Rx I/Q Rate: 1 GSPS (Decimation of 4x1) -// * DAC JESD204C: Mode 24, L=4, M=8, N=N'=12 -// * ADC JESD204C: Mode 29, L=4, M=8, N=N'=12 -// * DAC-Side JESD204C Lane Rate: 24.75Gbps -// * ADC-Side JESD204C Lane Rate: 24.75Gbps - // HDL Synthesis Parameters: // JESD_MODE=64B66B // RX_RATE=24.75 @@ -47,6 +29,24 @@ // RX_KS_PER_CHANNEL=16 // TX_KS_PER_CHANNEL=16 +#include +#include +#include + +#include "vcu118_quad_ad9081.dtsi" + +// This setup assumes 500MHz clock into J41 (0 dBm) +// ad9081_204c_txmode_29_rxmode_24_lr_24_75Gbps: Np 12 use case with high lane rate +// * 8Txs / 8Rxs per MxFE +// * DAC_CLK = 12GSPS +// * ADC_CLK = 4GSPS +// * Tx I/Q Rate: 1 GSPS (Interpolation of 12x1) +// * Rx I/Q Rate: 1 GSPS (Decimation of 4x1) +// * DAC JESD204C: Mode 24, L=4, M=8, N=N'=12 +// * ADC JESD204C: Mode 29, L=4, M=8, N=N'=12 +// * DAC-Side JESD204C Lane Rate: 24.75Gbps +// * ADC-Side JESD204C Lane Rate: 24.75Gbps + #define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 2 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc_nz1.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc_nz1.dts index b91517dc35abe7..105033b587492f 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc_nz1.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc_nz1.dts @@ -8,9 +8,27 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=24.75 +// TX_RATE=24.75 +// REF_CLK_RATE=250 +// RX_JESD_M=8 +// RX_JESD_L=4 +// RX_JESD_S=1 +// RX_JESD_NP=12 +// TX_JESD_M=8 +// TX_JESD_L=4 +// TX_JESD_S=1 +// TX_JESD_NP=12 +// RX_PLL_SEL=1 +// TX_PLL_SEL=1 +// RX_KS_PER_CHANNEL=16 +// TX_KS_PER_CHANNEL=16 + #include #define AD9081_TX_MAIN_NCO_SHIFT 1000000000 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts index b8a3cae3440ab2..54345de3fbdfa8 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts @@ -8,9 +8,27 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=24.75 +// TX_RATE=24.75 +// REF_CLK_RATE=250 +// RX_JESD_M=2 +// RX_JESD_L=4 +// RX_JESD_S=1 +// RX_JESD_NP=16 +// TX_JESD_M=2 +// TX_JESD_L=4 +// TX_JESD_S=1 +// TX_JESD_NP=16 +// RX_PLL_SEL=1 +// TX_PLL_SEL=1 +// RX_KS_PER_CHANNEL=64 +// TX_KS_PER_CHANNEL=64 + #include #include #include @@ -31,24 +49,6 @@ // * DAC-Side JESD204C Lane Rate: 24.75Gbps // * ADC-Side JESD204C Lane Rate: 24.75Gbps -// HDL Synthesis Parameters: -// JESD_MODE=64B66B -// RX_RATE=24.75 -// TX_RATE=24.75 -// REF_CLK_RATE=250 -// RX_JESD_M=2 -// RX_JESD_L=4 -// RX_JESD_S=1 -// RX_JESD_NP=16 -// TX_JESD_M=2 -// TX_JESD_L=4 -// TX_JESD_S=1 -// TX_JESD_NP=16 -// RX_PLL_SEL=1 -// TX_PLL_SEL=1 -// RX_KS_PER_CHANNEL=64 -// TX_KS_PER_CHANNEL=64 - #define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 3 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13_onchip_pll.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13_onchip_pll.dts index 179267f8ff6a0a..de420bd48a778f 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13_onchip_pll.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13_onchip_pll.dts @@ -8,9 +8,27 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=24.75 +// TX_RATE=24.75 +// REF_CLK_RATE=250 +// RX_JESD_M=2 +// RX_JESD_L=4 +// RX_JESD_S=1 +// RX_JESD_NP=16 +// TX_JESD_M=2 +// TX_JESD_L=4 +// TX_JESD_S=1 +// TX_JESD_NP=16 +// RX_PLL_SEL=1 +// TX_PLL_SEL=1 +// RX_KS_PER_CHANNEL=64 +// TX_KS_PER_CHANNEL=64 + // For MxFE0 // * Cap rotate: DNI C886, Populate C1118 // * Cap rotate: DNI C887, Populate C1119 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts index 9715abcf0bca31..4237af8c463163 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts @@ -8,27 +8,9 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ -#include -#include -#include - -#include "vcu118_quad_ad9081.dtsi" - -// This setup assumes 500MHz clock into J41 (0 dBm) -// ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps: Np 12 use case with high lane rate -// * 2Txs / 2Rxs per MxFE -// * DAC_CLK = 12GSPS -// * ADC_CLK = 6GSPS -// * Tx I/Q Rate: 2 GSPS (Interpolation of 6x1) -// * Rx I/Q Rate: 2 GSPS (Decimation of 3x1) -// * DAC JESD204C: Mode 23, L=4, M=4, N=N'=12 -// * ADC JESD204C: Mode 25, L=4, M=4, N=N'=12 -// * DAC-Side JESD204C Lane Rate: 24.75Gbps -// * ADC-Side JESD204C Lane Rate: 24.75Gbps - // HDL Synthesis Parameters: // JESD_MODE=64B66B // RX_RATE=24.75 @@ -47,6 +29,24 @@ // RX_KS_PER_CHANNEL=16 // TX_KS_PER_CHANNEL=16 +#include +#include +#include + +#include "vcu118_quad_ad9081.dtsi" + +// This setup assumes 500MHz clock into J41 (0 dBm) +// ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps: Np 12 use case with high lane rate +// * 2Txs / 2Rxs per MxFE +// * DAC_CLK = 12GSPS +// * ADC_CLK = 6GSPS +// * Tx I/Q Rate: 2 GSPS (Interpolation of 6x1) +// * Rx I/Q Rate: 2 GSPS (Decimation of 3x1) +// * DAC JESD204C: Mode 23, L=4, M=4, N=N'=12 +// * ADC JESD204C: Mode 25, L=4, M=4, N=N'=12 +// * DAC-Side JESD204C Lane Rate: 24.75Gbps +// * ADC-Side JESD204C Lane Rate: 24.75Gbps + #define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 2 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25_onchip_pll.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25_onchip_pll.dts index 81ffca6e045c78..0115bbd1e70cd2 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25_onchip_pll.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25_onchip_pll.dts @@ -8,9 +8,27 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=24.75 +// TX_RATE=24.75 +// REF_CLK_RATE=250 +// RX_JESD_M=4 +// RX_JESD_L=4 +// RX_JESD_S=2 +// RX_JESD_NP=12 +// TX_JESD_M=4 +// TX_JESD_L=4 +// TX_JESD_S=2 +// TX_JESD_NP=12 +// RX_PLL_SEL=1 +// TX_PLL_SEL=1 +// RX_KS_PER_CHANNEL=16 +// TX_KS_PER_CHANNEL=16 + // For MxFE0 // * Cap rotate: DNI C886, Populate C1118 // * Cap rotate: DNI C887, Populate C1119 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts index 27c8fe9f5f1e9d..76fe95e12bbae9 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts @@ -8,9 +8,25 @@ * hdl_project: * board_revision: <> * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=4 +// RX_JESD_L=1 +// RX_JESD_NP=16 +// RX_JESD_S=1 +// TX_JESD_M=8 +// TX_JESD_L=2 +// TX_JESD_S=1 +// TX_JESD_NP=16 +// RX_KS_PER_CHANNEL=16 +// TX_KS_PER_CHANNEL=16 + #include #include #include @@ -29,22 +45,6 @@ // * DAC-Side JESD204C Lane Rate: 16.5Gbps // * ADC-Side JESD204C Lane Rate: 16.5Gbps -// HDL Synthesis Parameters: -// JESD_MODE=64B66B -// RX_RATE=16.5 -// TX_RATE=16.5 -// REF_CLK_RATE=250 -// RX_JESD_M=4 -// RX_JESD_L=1 -// RX_JESD_NP=16 -// RX_JESD_S=1 -// TX_JESD_M=8 -// TX_JESD_L=2 -// TX_JESD_S=1 -// TX_JESD_NP=16 -// RX_KS_PER_CHANNEL=16 -// TX_KS_PER_CHANNEL=16 - #define ADF4371_RF16_FREQUENCY_HZ 12000000000 #define HMC7043_FPGA_XCVR_CLKDIV 2 diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2_onchip_pll.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2_onchip_pll.dts index cdf32afa8cfeb4..b686ec81e48bf7 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2_onchip_pll.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2_onchip_pll.dts @@ -8,9 +8,25 @@ * hdl_project: * board_revision: * - * Copyright (C) 2021 Analog Devices Inc. + * Copyright (C) 2021-2022 Analog Devices Inc. */ +// HDL Synthesis Parameters: +// JESD_MODE=64B66B +// RX_RATE=16.5 +// TX_RATE=16.5 +// REF_CLK_RATE=250 +// RX_JESD_M=4 +// RX_JESD_L=1 +// RX_JESD_NP=16 +// RX_JESD_S=1 +// TX_JESD_M=8 +// TX_JESD_L=2 +// TX_JESD_S=1 +// TX_JESD_NP=16 +// RX_KS_PER_CHANNEL=16 +// TX_KS_PER_CHANNEL=16 + // For MxFE0 // * Cap rotate: DNI C886, Populate C1118 // * Cap rotate: DNI C887, Populate C1119 From 46169000cbb79e8644c68f19ddc209868d094caf Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 27 Jun 2022 12:40:50 +0200 Subject: [PATCH 374/407] microblaze: dts: adi-fmcjesdadc1.dtsi: Fix reg format warning Fix reg format warning. No functional changes. Signed-off-by: Michael Hennerich --- arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi b/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi index 53cfd73043a289..44a67d40504180 100644 --- a/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi +++ b/arch/microblaze/boot/dts/adi-fmcjesdadc1.dtsi @@ -35,7 +35,7 @@ clock-output-names = "out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7"; }; - adc0_ad9250: ad9250-0@0 { + adc0_ad9250: ad9250-0@2 { compatible = "adi,ad9250_2"; reg = <2>; spi-max-frequency = <10000000>; @@ -43,7 +43,7 @@ clock-names = "jesd_dac_clk", "adc_clk"; }; - adc1_ad9250: ad9250-1@1 { + adc1_ad9250: ad9250-1@3 { compatible = "adi,ad9250_2"; reg = <3>; spi-max-frequency = <10000000>; From 7e0edcaa2c44a100d23e5c4569388caece1d6c16 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 27 Jun 2022 13:26:44 +0200 Subject: [PATCH 375/407] microblaze: boot: dts: Remove redundant axi-dmac channel nodes This information is read from the HDL core synthesis parameters. Signed-off-by: Michael Hennerich --- arch/microblaze/boot/dts/kc705_ad9467_fmc.dts | 13 ------- arch/microblaze/boot/dts/kc705_fmcdaq2.dts | 26 ------------- .../microblaze/boot/dts/kc705_fmcjesdadc1.dts | 26 ------------- arch/microblaze/boot/dts/kc705_fmcomms1.dts | 26 ------------- arch/microblaze/boot/dts/kc705_fmcomms2-3.dts | 26 ------------- arch/microblaze/boot/dts/kc705_fmcomms4.dts | 26 ------------- arch/microblaze/boot/dts/kcu105_adrv9371x.dts | 39 ------------------- arch/microblaze/boot/dts/kcu105_fmcdaq2.dts | 26 ------------- arch/microblaze/boot/dts/kcu105_fmcdaq3.dts | 26 ------------- .../microblaze/boot/dts/kcu105_fmcomms2-3.dts | 26 ------------- arch/microblaze/boot/dts/kcu105_fmcomms4.dts | 26 ------------- arch/microblaze/boot/dts/vc707_ad6676evb.dts | 13 ------- arch/microblaze/boot/dts/vc707_fmcadc2.dts | 13 ------- arch/microblaze/boot/dts/vc707_fmcadc5.dts | 13 ------- arch/microblaze/boot/dts/vc707_fmcdaq2.dts | 26 ------------- .../microblaze/boot/dts/vc707_fmcjesdadc1.dts | 13 ------- arch/microblaze/boot/dts/vc707_fmcomms1.dts | 13 ------- arch/microblaze/boot/dts/vc707_fmcomms2-3.dts | 26 ------------- arch/microblaze/boot/dts/vc707_fmcomms4.dts | 26 ------------- ...vcu118_ad9081_204c_txmode_10_rxmode_11.dts | 20 ---------- ..._204c_txmode_10_rxmode_11_lr_24_75Gbps.dts | 20 ---------- ...vcu118_ad9081_204c_txmode_23_rxmode_25.dts | 20 ---------- ..._204c_txmode_23_rxmode_25_lr_24_75Gbps.dts | 20 ---------- ..._204c_txmode_24_rxmode_26_lr_24_75Gbps.dts | 20 ---------- .../boot/dts/vcu118_ad9081_m8_l4.dts | 24 ------------ .../boot/dts/vcu118_dual_ad9208.dts | 13 ------- arch/microblaze/boot/dts/vcu118_fmcdaq3.dts | 26 ------------- .../boot/dts/vcu118_quad_ad9081.dtsi | 27 ------------- ...18_quad_ad9081_204b_txmode_9_rxmode_10.dts | 24 ------------ ...8_quad_ad9081_204c_txmode_10_rxmode_11.dts | 24 ------------ ...18_quad_ad9081_204c_txmode_11_rxmode_4.dts | 25 ------------ ...9081_204c_txmode_11_rxmode_4_direct_6g.dts | 23 ----------- ...d_ad9081_204c_txmode_23_rxmode_25_revc.dts | 8 ---- ...d_ad9081_204c_txmode_29_rxmode_24_revc.dts | 8 ---- ...8_quad_ad9082_204c_txmode_12_rxmode_13.dts | 8 ---- ...8_quad_ad9082_204c_txmode_23_rxmode_25.dts | 8 ---- ...118_quad_ad9082_204c_txmode_3_rxmode_2.dts | 8 ---- arch/microblaze/boot/dts/vcu128_ad9081.dts | 27 ------------- .../boot/dts/vcu128_ad9081_m8_l4.dts | 24 ------------ 39 files changed, 806 deletions(-) diff --git a/arch/microblaze/boot/dts/kc705_ad9467_fmc.dts b/arch/microblaze/boot/dts/kc705_ad9467_fmc.dts index 99a3a8765e5bbf..1a9fae86751ef5 100644 --- a/arch/microblaze/boot/dts/kc705_ad9467_fmc.dts +++ b/arch/microblaze/boot/dts/kc705_ad9467_fmc.dts @@ -42,19 +42,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <16>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; }; diff --git a/arch/microblaze/boot/dts/kc705_fmcdaq2.dts b/arch/microblaze/boot/dts/kc705_fmcdaq2.dts index fe91c89c480eef..2ba18f76ab38a0 100644 --- a/arch/microblaze/boot/dts/kc705_fmcdaq2.dts +++ b/arch/microblaze/boot/dts/kc705_fmcdaq2.dts @@ -33,19 +33,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <1>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: tx-dmac@7c420000 { #dma-cells = <1>; @@ -54,19 +41,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <128>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <128>; - adi,destination-bus-type = <1>; - }; - }; }; axi_ad9680_core: axi-ad9680-hpc@44a10000 { diff --git a/arch/microblaze/boot/dts/kc705_fmcjesdadc1.dts b/arch/microblaze/boot/dts/kc705_fmcjesdadc1.dts index 9b11d4bec1ad8e..f20335fc9bb1f6 100644 --- a/arch/microblaze/boot/dts/kc705_fmcjesdadc1.dts +++ b/arch/microblaze/boot/dts/kc705_fmcjesdadc1.dts @@ -41,19 +41,6 @@ reg = <0x7c420000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; axi_ad9250_core1: axi-ad9250-hpc-1@44a20000 { compatible = "xlnx,axi-ad9250-1.00.a"; @@ -69,19 +56,6 @@ reg = <0x7c430000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; axi_adxcvr: axi-adxcvr@44a60000 { #address-cells = <1>; diff --git a/arch/microblaze/boot/dts/kc705_fmcomms1.dts b/arch/microblaze/boot/dts/kc705_fmcomms1.dts index b2b402553671e0..61439a47677a53 100644 --- a/arch/microblaze/boot/dts/kc705_fmcomms1.dts +++ b/arch/microblaze/boot/dts/kc705_fmcomms1.dts @@ -28,19 +28,6 @@ reg = <0x7c420000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <2>; - }; - }; }; axi_ad9643: cf-ad9643-core-lpc@79020000 { compatible = "adi,axi-ad9643-6.00.a"; @@ -56,19 +43,6 @@ reg = <0x7c400000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; }; diff --git a/arch/microblaze/boot/dts/kc705_fmcomms2-3.dts b/arch/microblaze/boot/dts/kc705_fmcomms2-3.dts index 1864017528755b..a585024100c34a 100644 --- a/arch/microblaze/boot/dts/kc705_fmcomms2-3.dts +++ b/arch/microblaze/boot/dts/kc705_fmcomms2-3.dts @@ -32,19 +32,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: dma@7c420000 { #dma-cells = <1>; @@ -53,19 +40,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <2>; - }; - }; }; cf-ad9361-lpc@79020000 { compatible = "adi,axi-ad9361-6.00.a"; diff --git a/arch/microblaze/boot/dts/kc705_fmcomms4.dts b/arch/microblaze/boot/dts/kc705_fmcomms4.dts index 35e0e37d2f283f..23f350168c93e2 100644 --- a/arch/microblaze/boot/dts/kc705_fmcomms4.dts +++ b/arch/microblaze/boot/dts/kc705_fmcomms4.dts @@ -33,19 +33,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: dma@7c420000 { #dma-cells = <1>; @@ -54,19 +41,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <2>; - }; - }; }; cf-ad9361-lpc@79020000 { compatible = "adi,axi-ad9361-6.00.a"; diff --git a/arch/microblaze/boot/dts/kcu105_adrv9371x.dts b/arch/microblaze/boot/dts/kcu105_adrv9371x.dts index ad3d1674ae66f9..d020e0f47f2375 100644 --- a/arch/microblaze/boot/dts/kcu105_adrv9371x.dts +++ b/arch/microblaze/boot/dts/kcu105_adrv9371x.dts @@ -62,19 +62,6 @@ reg = <0x7c400000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; rx_obs_dma: rx-obs-dmac@7c440000 { compatible = "adi,axi-dmac-1.00.a"; @@ -83,19 +70,6 @@ reg = <0x7c440000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: tx-dmac@7c420000 { compatible = "adi,axi-dmac-1.00.a"; @@ -104,19 +78,6 @@ reg = <0x7c420000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <128>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <128>; - adi,destination-bus-type = <1>; - }; - }; }; axi_rx_clkgen: axi-clkgen@43c10000 { compatible = "adi,axi-clkgen-2.00.a"; diff --git a/arch/microblaze/boot/dts/kcu105_fmcdaq2.dts b/arch/microblaze/boot/dts/kcu105_fmcdaq2.dts index 3dae69b43dfc4b..5334995b2ad6d1 100644 --- a/arch/microblaze/boot/dts/kcu105_fmcdaq2.dts +++ b/arch/microblaze/boot/dts/kcu105_fmcdaq2.dts @@ -33,19 +33,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <1>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: tx-dmac@7c420000 { #dma-cells = <1>; @@ -54,19 +41,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <128>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <128>; - adi,destination-bus-type = <1>; - }; - }; }; axi_ad9680_core: axi-ad9680-hpc@44a10000 { diff --git a/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts b/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts index 5fabf16cfcef93..808c1799bea1db 100644 --- a/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts +++ b/arch/microblaze/boot/dts/kcu105_fmcdaq3.dts @@ -32,19 +32,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <1>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: tx-dmac@7c420000 { #dma-cells = <1>; @@ -53,19 +40,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <128>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <128>; - adi,destination-bus-type = <1>; - }; - }; }; axi_ad9680_core: axi-ad9680-hpc@44a10000 { diff --git a/arch/microblaze/boot/dts/kcu105_fmcomms2-3.dts b/arch/microblaze/boot/dts/kcu105_fmcomms2-3.dts index daa4012a43f5a5..e491fe10f843d6 100644 --- a/arch/microblaze/boot/dts/kcu105_fmcomms2-3.dts +++ b/arch/microblaze/boot/dts/kcu105_fmcomms2-3.dts @@ -32,19 +32,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: dma@7c420000 { #dma-cells = <1>; @@ -53,19 +40,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <2>; - }; - }; }; cf-ad9361-lpc@79020000 { compatible = "adi,axi-ad9361-6.00.a"; diff --git a/arch/microblaze/boot/dts/kcu105_fmcomms4.dts b/arch/microblaze/boot/dts/kcu105_fmcomms4.dts index 540a0a81ac719c..29e716c710b350 100644 --- a/arch/microblaze/boot/dts/kcu105_fmcomms4.dts +++ b/arch/microblaze/boot/dts/kcu105_fmcomms4.dts @@ -32,19 +32,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: dma@7c420000 { #dma-cells = <1>; @@ -53,19 +40,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <2>; - }; - }; }; cf-ad9361-lpc@79020000 { compatible = "adi,axi-ad9361-6.00.a"; diff --git a/arch/microblaze/boot/dts/vc707_ad6676evb.dts b/arch/microblaze/boot/dts/vc707_ad6676evb.dts index 84990ff8e5d125..77b2c2d51e3063 100644 --- a/arch/microblaze/boot/dts/vc707_ad6676evb.dts +++ b/arch/microblaze/boot/dts/vc707_ad6676evb.dts @@ -52,19 +52,6 @@ reg = <0x7c420000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; axi_ad6676_jesd: axi-jesd204-rx@44aa0000 { compatible = "adi,axi-jesd204-rx-1.0"; diff --git a/arch/microblaze/boot/dts/vc707_fmcadc2.dts b/arch/microblaze/boot/dts/vc707_fmcadc2.dts index 44ac0f96d5fb19..edc06fa7fccf7b 100644 --- a/arch/microblaze/boot/dts/vc707_fmcadc2.dts +++ b/arch/microblaze/boot/dts/vc707_fmcadc2.dts @@ -62,19 +62,6 @@ reg = <0x7c420000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #address-cells = <1>; - #size-cells = <0>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <1>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; axi_adxcvr: axi-adxcvr@44a60000 { compatible = "adi,axi-adxcvr-1.0"; diff --git a/arch/microblaze/boot/dts/vc707_fmcadc5.dts b/arch/microblaze/boot/dts/vc707_fmcadc5.dts index 6e5cb7e3bfd3ee..40ecdf17ddfb81 100644 --- a/arch/microblaze/boot/dts/vc707_fmcadc5.dts +++ b/arch/microblaze/boot/dts/vc707_fmcadc5.dts @@ -138,19 +138,6 @@ reg = <0x7c420000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <1>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; }; diff --git a/arch/microblaze/boot/dts/vc707_fmcdaq2.dts b/arch/microblaze/boot/dts/vc707_fmcdaq2.dts index 7d6bf3f0e58247..ce9533f010d536 100644 --- a/arch/microblaze/boot/dts/vc707_fmcdaq2.dts +++ b/arch/microblaze/boot/dts/vc707_fmcdaq2.dts @@ -28,19 +28,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <1>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: tx-dmac@7c420000 { #dma-cells = <1>; @@ -49,19 +36,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <128>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <128>; - adi,destination-bus-type = <1>; - }; - }; }; axi_ad9680_core: axi-ad9680-hpc@44a10000 { compatible = "adi,axi-ad9680-1.0"; diff --git a/arch/microblaze/boot/dts/vc707_fmcjesdadc1.dts b/arch/microblaze/boot/dts/vc707_fmcjesdadc1.dts index 362d91e78baeb7..bdd68c1569926a 100644 --- a/arch/microblaze/boot/dts/vc707_fmcjesdadc1.dts +++ b/arch/microblaze/boot/dts/vc707_fmcjesdadc1.dts @@ -41,19 +41,6 @@ reg = <0x7c420000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; axi_ad9250_core1: axi-ad9250-hpc-1@44a20000 { compatible = "xlnx,axi-ad9250-1.00.a"; diff --git a/arch/microblaze/boot/dts/vc707_fmcomms1.dts b/arch/microblaze/boot/dts/vc707_fmcomms1.dts index 94704663e5681a..1a741a49607c5d 100644 --- a/arch/microblaze/boot/dts/vc707_fmcomms1.dts +++ b/arch/microblaze/boot/dts/vc707_fmcomms1.dts @@ -23,19 +23,6 @@ reg = <0x7c420000 0x10000>; #dma-cells = <1>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <2>; - }; - }; }; axi_ad9643: cf-ad9643-core-lpc@79020000 { compatible = "adi,axi-ad9643-6.00.a"; diff --git a/arch/microblaze/boot/dts/vc707_fmcomms2-3.dts b/arch/microblaze/boot/dts/vc707_fmcomms2-3.dts index 2dea4e2ea119d9..aedd74a0534de4 100644 --- a/arch/microblaze/boot/dts/vc707_fmcomms2-3.dts +++ b/arch/microblaze/boot/dts/vc707_fmcomms2-3.dts @@ -32,19 +32,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: dma@7c420000 { #dma-cells = <1>; @@ -53,19 +40,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <2>; - }; - }; }; cf-ad9361-lpc@79020000 { compatible = "adi,axi-ad9361-6.00.a"; diff --git a/arch/microblaze/boot/dts/vc707_fmcomms4.dts b/arch/microblaze/boot/dts/vc707_fmcomms4.dts index 4b389c9ab47f34..104a8b42ffcb10 100644 --- a/arch/microblaze/boot/dts/vc707_fmcomms4.dts +++ b/arch/microblaze/boot/dts/vc707_fmcomms4.dts @@ -32,19 +32,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: dma@7c420000 { #dma-cells = <1>; @@ -53,19 +40,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <2>; - }; - }; }; cf-ad9361-lpc@79020000 { compatible = "adi,axi-ad9361-6.00.a"; diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11.dts b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11.dts index 72416d4858333c..f5baef5cf8f040 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11.dts @@ -78,26 +78,6 @@ adi,out-clk-select = ; }; -&rx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-type = <2>; - adi,destination-bus-type = <0>; - }; - }; -}; - -&tx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-type = <0>; - adi,destination-bus-type = <2>; - }; - }; -}; - &hmc7044 { adi,pll2-output-frequency = <3000000000>; diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11_lr_24_75Gbps.dts b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11_lr_24_75Gbps.dts index 2c0360161129d2..8360cae4d0edb4 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11_lr_24_75Gbps.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_10_rxmode_11_lr_24_75Gbps.dts @@ -78,26 +78,6 @@ adi,out-clk-select = ; }; -&rx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-type = <2>; - adi,destination-bus-type = <0>; - }; - }; -}; - -&tx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-type = <0>; - adi,destination-bus-type = <2>; - }; - }; -}; - &hmc7044 { adi,pll2-output-frequency = <3000000000>; diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25.dts b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25.dts index a3bf93e70f05ee..5cb1df53332290 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25.dts @@ -27,26 +27,6 @@ adi,out-clk-select = ; }; -&rx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-type = <2>; - adi,destination-bus-type = <0>; - }; - }; -}; - -&tx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-type = <0>; - adi,destination-bus-type = <2>; - }; - }; -}; - &hmc7044 { adi,pll2-output-frequency = <3000000000>; diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps.dts b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps.dts index 4dc05550798cd2..9a04214d2f9469 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_23_rxmode_25_lr_24_75Gbps.dts @@ -27,26 +27,6 @@ adi,out-clk-select = ; }; -&rx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-type = <2>; - adi,destination-bus-type = <0>; - }; - }; -}; - -&tx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-type = <0>; - adi,destination-bus-type = <2>; - }; - }; -}; - &hmc7044 { adi,pll2-output-frequency = <3000000000>; diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_24_rxmode_26_lr_24_75Gbps.dts b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_24_rxmode_26_lr_24_75Gbps.dts index 4eb25d95234338..5ab9f4d1f2a7ad 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_24_rxmode_26_lr_24_75Gbps.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_204c_txmode_24_rxmode_26_lr_24_75Gbps.dts @@ -27,26 +27,6 @@ adi,out-clk-select = ; }; -&rx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-type = <2>; - adi,destination-bus-type = <0>; - }; - }; -}; - -&tx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-type = <0>; - adi,destination-bus-type = <2>; - }; - }; -}; - &hmc7044 { adi,pll2-output-frequency = <3000000000>; diff --git a/arch/microblaze/boot/dts/vcu118_ad9081_m8_l4.dts b/arch/microblaze/boot/dts/vcu118_ad9081_m8_l4.dts index 732842a2e10887..8047a0b75bca97 100644 --- a/arch/microblaze/boot/dts/vcu118_ad9081_m8_l4.dts +++ b/arch/microblaze/boot/dts/vcu118_ad9081_m8_l4.dts @@ -12,30 +12,6 @@ #include "vcu118_ad9081.dts" -&rx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <128>; /* Needs to be 32 * JESD_L */ - adi,source-bus-type = <2>; - adi,destination-bus-width = <128>; /* Needs to be 32 * JESD_L */ - adi,destination-bus-type = <0>; - }; - }; -}; - -&tx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <128>; /* Needs to be 32 * JESD_L */ - adi,source-bus-type = <0>; - adi,destination-bus-width = <128>; /* Needs to be 32 * JESD_L */ - adi,destination-bus-type = <2>; - }; - }; -}; - &axi_ad9081_adxcvr_rx { adi,sys-clk-select = ; }; diff --git a/arch/microblaze/boot/dts/vcu118_dual_ad9208.dts b/arch/microblaze/boot/dts/vcu118_dual_ad9208.dts index 988b3e2d074664..267c4244a3310e 100644 --- a/arch/microblaze/boot/dts/vcu118_dual_ad9208.dts +++ b/arch/microblaze/boot/dts/vcu118_dual_ad9208.dts @@ -31,19 +31,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <512>; - adi,source-bus-type = <1>; - adi,destination-bus-width = <512>; - adi,destination-bus-type = <0>; - }; - }; }; axi_ad9208_0_jesd_rx: axi-jesd204-rx@44a90000 { diff --git a/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts b/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts index 07a72c4132aaae..fa87294bebf052 100644 --- a/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts +++ b/arch/microblaze/boot/dts/vcu118_fmcdaq3.dts @@ -33,19 +33,6 @@ interrupt-parent = <&axi_intc>; interrupts = <12 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <64>; - adi,source-bus-type = <1>; - adi,destination-bus-width = <64>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: tx-dmac@7c420000 { #dma-cells = <1>; @@ -54,19 +41,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <128>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <128>; - adi,destination-bus-type = <1>; - }; - }; }; axi_ad9680_core: axi-ad9680-hpc@44a10000 { compatible = "adi,axi-ad9680-1.0"; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi b/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi index 85fe059bc9d739..d47791ad06f993 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081.dtsi @@ -71,21 +71,7 @@ #clock-cells = <0>; interrupt-parent = <&axi_intc>; interrupts = <12 4>; - clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <256>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <256>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: dma@7c430000 { @@ -96,19 +82,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 4>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <256>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <256>; - adi,destination-bus-type = <2>; - }; - }; }; axi_ad9081_core_rx: axi-ad9081-rx-3@44a10000 { diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts index 43d2e94742ab08..a51f0f8cea0d3f 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204b_txmode_9_rxmode_10.dts @@ -186,30 +186,6 @@ }; }; -&rx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <512>; /* Needs to be 32 * JESD_L */ - adi,source-bus-type = <2>; - adi,destination-bus-width = <512>; /* Needs to be 32 * JESD_L */ - adi,destination-bus-type = <0>; - }; - }; -}; - -&tx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <512>; /* Needs to be 32 * JESD_L */ - adi,source-bus-type = <0>; - adi,destination-bus-width = <512>; /* Needs to be 32 * JESD_L */ - adi,destination-bus-type = <2>; - }; - }; -}; - &adf4371_clk0 { channel@2 { reg = <2>; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts index c45c9eb9e489e8..1a4919c953ae96 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_10_rxmode_11.dts @@ -133,30 +133,6 @@ jesd204-inputs = <&hmc7043 0 DEFRAMER_LINK0_TX>; /* omit axi_ad9081_adxcvr_tx */ }; -&rx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <1024>; /* Needs to be 64 * JESD_L */ - adi,source-bus-type = <2>; - adi,destination-bus-width = <512>; /* fixed */ - adi,destination-bus-type = <0>; - }; - }; -}; - -&tx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <512>; /* fixed*/ - adi,source-bus-type = <0>; - adi,destination-bus-width = <1024>; /* Needs to be 64 * JESD_L */ - adi,destination-bus-type = <2>; - }; - }; -}; - &adf4371_clk0 { channel@2 { reg = <2>; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts index ce900ed7d45cc0..1cc46dc2f86f6e 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4.dts @@ -134,31 +134,6 @@ jesd204-inputs = <&hmc7043 0 DEFRAMER_LINK0_TX>; /* omit axi_ad9081_adxcvr_tx */ }; -&rx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <512>; /* Needs to be 64 * JESD_L (4 * MxFE_L) */ - adi,source-bus-type = <2>; - adi,destination-bus-width = <512>; /* Needs to be 64 * JESD_L (4 * MxFE_L) */ - adi,destination-bus-type = <0>; - }; - }; -}; - -&tx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <1024>; /* Needs to be 64 * JESD_L (4 * MxFE_L) */ - adi,source-bus-type = <0>; - adi,destination-bus-width = <1024>; /* Needs to be 64 * JESD_L (4 * MxFE_L) */ - adi,destination-bus-type = <2>; - }; - }; -}; - - &adf4371_clk0 { channel@2 { reg = <2>; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts index 7fbe8634adec53..93841b95ec6d42 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_11_rxmode_4_direct_6g.dts @@ -165,29 +165,6 @@ /delete-node/ &axi_ad9081_adxcvr_rx; /delete-node/ &axi_ad9081_adxcvr_tx; -&rx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <512>; /* Needs to be 32 * JESD_L */ - adi,source-bus-type = <2>; - adi,destination-bus-width = <512>; /* Needs to be 32 * JESD_L */ - adi,destination-bus-type = <0>; - }; - }; -}; - -&tx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <512>; /* Needs to be 32 * JESD_L */ - adi,source-bus-type = <0>; - adi,destination-bus-width = <512>; /* Needs to be 32 * JESD_L */ - adi,destination-bus-type = <2>; - }; - }; -}; &hmc7043 { hmc7043_c0: channel@0 { reg = <0>; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts index 2523234827cef7..0a82d76f53a96c 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_23_rxmode_25_revc.dts @@ -185,14 +185,6 @@ jesd204-inputs = <&hmc7043 0 DEFRAMER_LINK0_TX>; /* omit axi_ad9081_adxcvr_tx */ }; -&rx_dma { - /delete-node/ adi,channels; /* This comes from the synthesis paramtes */ -}; - -&tx_dma { - /delete-node/ adi,channels; /* This comes from the synthesis paramtes */ -}; - &adf4371_clk0 { channel@2 { reg = <2>; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts index becb6e6956df8e..bd1ad0a8cdf178 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9081_204c_txmode_29_rxmode_24_revc.dts @@ -185,14 +185,6 @@ jesd204-inputs = <&hmc7043 0 DEFRAMER_LINK0_TX>; /* omit axi_ad9081_adxcvr_tx */ }; -&rx_dma { - /delete-node/ adi,channels; /* This comes from the synthesis paramtes */ -}; - -&tx_dma { - /delete-node/ adi,channels; /* This comes from the synthesis paramtes */ -}; - &adf4371_clk0 { channel@2 { reg = <2>; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts index 54345de3fbdfa8..39b78b6c2e8b36 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_12_rxmode_13.dts @@ -158,14 +158,6 @@ jesd204-inputs = <&hmc7043 0 DEFRAMER_LINK0_TX>; /* omit axi_ad9081_adxcvr_tx */ }; -&rx_dma { - /delete-node/ adi,channels; /* This comes from the synthesis paramtes */ -}; - -&tx_dma { - /delete-node/ adi,channels; /* This comes from the synthesis paramtes */ -}; - &adf4371_clk0 { channel@2 { reg = <2>; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts index 4237af8c463163..707c7b6d6c88fe 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_23_rxmode_25.dts @@ -171,14 +171,6 @@ jesd204-inputs = <&hmc7043 0 DEFRAMER_LINK0_TX>; /* omit axi_ad9081_adxcvr_tx */ }; -&rx_dma { - /delete-node/ adi,channels; /* This comes from the synthesis paramtes */ -}; - -&tx_dma { - /delete-node/ adi,channels; /* This comes from the synthesis paramtes */ -}; - &adf4371_clk0 { channel@2 { reg = <2>; diff --git a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts index 76fe95e12bbae9..dde5ff61a1e368 100644 --- a/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts +++ b/arch/microblaze/boot/dts/vcu118_quad_ad9082_204c_txmode_3_rxmode_2.dts @@ -154,14 +154,6 @@ jesd204-inputs = <&hmc7043 0 DEFRAMER_LINK0_TX>; /* omit axi_ad9081_adxcvr_tx */ }; -&rx_dma { - /delete-node/ adi,channels; /* This comes from the synthesis paramtes */ -}; - -&tx_dma { - /delete-node/ adi,channels; /* This comes from the synthesis paramtes */ -}; - &adf4371_clk0 { channel@2 { reg = <2>; diff --git a/arch/microblaze/boot/dts/vcu128_ad9081.dts b/arch/microblaze/boot/dts/vcu128_ad9081.dts index 71d76e13dd1973..72dd02ad2839d8 100644 --- a/arch/microblaze/boot/dts/vcu128_ad9081.dts +++ b/arch/microblaze/boot/dts/vcu128_ad9081.dts @@ -39,21 +39,7 @@ #clock-cells = <0>; interrupt-parent = <&axi_intc>; interrupts = <12 2>; - clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <256>; - adi,source-bus-type = <2>; - adi,destination-bus-width = <256>; - adi,destination-bus-type = <0>; - }; - }; }; tx_dma: dma@7c430000 { @@ -64,19 +50,6 @@ interrupt-parent = <&axi_intc>; interrupts = <13 2>; clocks = <&clk_bus_0>; - - adi,channels { - #size-cells = <0>; - #address-cells = <1>; - - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <256>; - adi,source-bus-type = <0>; - adi,destination-bus-width = <256>; - adi,destination-bus-type = <2>; - }; - }; }; axi_ad9081_core_rx: axi-ad9081-rx-hpc@44a10000 { diff --git a/arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts b/arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts index d6487dc02c374c..7e9095ff250b01 100644 --- a/arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts +++ b/arch/microblaze/boot/dts/vcu128_ad9081_m8_l4.dts @@ -12,30 +12,6 @@ #include "vcu128_ad9081.dts" -&rx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <128>; /* Needs to be 32 * JESD_L */ - adi,source-bus-type = <2>; - adi,destination-bus-width = <128>; /* Needs to be 32 * JESD_L */ - adi,destination-bus-type = <0>; - }; - }; -}; - -&tx_dma { - adi,channels { - dma-channel@0 { - reg = <0>; - adi,source-bus-width = <128>; /* Needs to be 32 * JESD_L */ - adi,source-bus-type = <0>; - adi,destination-bus-width = <128>; /* Needs to be 32 * JESD_L */ - adi,destination-bus-type = <2>; - }; - }; -}; - &axi_ad9081_adxcvr_rx { adi,sys-clk-select = ; }; From 206620839dc3302e57861033f94c40c4f98eeead Mon Sep 17 00:00:00 2001 From: "stefan.raus" Date: Wed, 29 Jun 2022 10:13:45 +0100 Subject: [PATCH 376/407] arch: arm : boot: dts: set vcxo to 100 MHz Do not overwrite values of pll1 clkin and vcxo frequencies in zynq-zc706-adv7511-ad9081-np12.dts, but let them to 100 MHz as they are set in adi-ad9081-fmc-ebz.dtsi Signed-off-by: stefan.raus --- arch/arm/boot/dts/zynq-zc706-adv7511-ad9081-np12.dts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9081-np12.dts b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9081-np12.dts index 2140c61731becc..be243ec9f6a256 100644 --- a/arch/arm/boot/dts/zynq-zc706-adv7511-ad9081-np12.dts +++ b/arch/arm/boot/dts/zynq-zc706-adv7511-ad9081-np12.dts @@ -28,12 +28,8 @@ adi,jesd204-max-sysref-frequency-hz = <2000000>; /* 2 MHz */ - adi,pll1-clkin-frequencies = <122880000 30720000 0 0>; - adi,pll1-loop-bandwidth-hz = <200>; - adi,vcxo-frequency = <122880000>; - adi,pll2-output-frequency = <3000000000>; adi,sysref-timer-divider = <1024>; From 4a0de3c84c08600c660d87d2753fc20e1ce8baae Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 1 Jul 2022 15:26:16 +0200 Subject: [PATCH 377/407] iio: frequency: ad9528: Support for GPIO trigger SYSREF requests This feature allows one AD9528 to simultaneous request SYSREF pulses from potentially other AD9528, which share the SAME sysref-req-gpio. Signed-off-by: Michael Hennerich --- drivers/iio/frequency/ad9528.c | 37 +++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/iio/frequency/ad9528.c b/drivers/iio/frequency/ad9528.c index 5696cf191e354e..8cb2c33eeb91fe 100644 --- a/drivers/iio/frequency/ad9528.c +++ b/drivers/iio/frequency/ad9528.c @@ -275,6 +275,7 @@ struct ad9528_state { struct clk_onecell_data clk_data; struct clk *clks[AD9528_NUM_CHAN]; struct gpio_desc *reset_gpio; + struct gpio_desc *sysref_req_gpio; struct jesd204_dev *jdev; u32 jdev_lmfc_lemc_rate; u32 jdev_lmfc_lemc_gcd; @@ -1334,21 +1335,27 @@ static int ad9528_jesd204_sysref(struct jesd204_dev *jdev) mutex_lock(&st->lock); - val = ad9528_read(indio_dev, AD9528_SYSREF_CTRL); - if (val < 0) { - mutex_unlock(&st->lock); - return val; - } + if (st->sysref_req_gpio && st->pdata->sysref_req_en) { + gpiod_direction_output(st->sysref_req_gpio, 1); + mdelay(1); + ret = gpiod_direction_output(st->sysref_req_gpio, 0); + } else { + val = ad9528_read(indio_dev, AD9528_SYSREF_CTRL); + if (val < 0) { + mutex_unlock(&st->lock); + return val; + } - val &= ~AD9528_SYSREF_PATTERN_REQ; + val &= ~AD9528_SYSREF_PATTERN_REQ; - ad9528_write(indio_dev, AD9528_SYSREF_CTRL, val); + ad9528_write(indio_dev, AD9528_SYSREF_CTRL, val); - val |= AD9528_SYSREF_PATTERN_REQ; + val |= AD9528_SYSREF_PATTERN_REQ; - ret = ad9528_write(indio_dev, AD9528_SYSREF_CTRL, val); + ret = ad9528_write(indio_dev, AD9528_SYSREF_CTRL, val); - ad9528_io_update(indio_dev); + ad9528_io_update(indio_dev); + } mutex_unlock(&st->lock); @@ -1393,6 +1400,10 @@ static int ad9528_jesd204_link_pre_setup(struct jesd204_dev *jdev, ad9528_io_update(indio_dev); + if (st->sysref_req_gpio && st->pdata->sysref_req_en && + st->pdata->sysref_pattern_mode == SYSREF_PATTERN_CONTINUOUS) + gpiod_direction_output(st->sysref_req_gpio, 1); + return JESD204_STATE_CHANGE_DONE; } @@ -1682,6 +1693,12 @@ static int ad9528_probe(struct spi_device *spi) return ret; } + st->sysref_req_gpio = devm_gpiod_get_optional(&spi->dev, "sysref-req", + GPIOD_OUT_LOW); + if (IS_ERR(st->sysref_req_gpio)) + return dev_err_probe(&spi->dev, PTR_ERR(st->sysref_req_gpio), + "cannot get sysref request gpio\n"); + status0_gpio = devm_gpiod_get_optional(&spi->dev, "status0", GPIOD_OUT_LOW); status1_gpio = devm_gpiod_get_optional(&spi->dev, From bb582455d8220cd053401f24a2fa1d69fc17177a Mon Sep 17 00:00:00 2001 From: George Mois Date: Fri, 1 Jul 2022 15:15:25 +0300 Subject: [PATCH 378/407] iio: jesd204: xilinx_transceiver.c: Fix error handling Fix the error handling in function xilinx_xcvr_prbs_err_cnt_get(). The return value of a previous call was checked. Signed-off-by: George Mois --- drivers/iio/jesd204/xilinx_transceiver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/jesd204/xilinx_transceiver.c b/drivers/iio/jesd204/xilinx_transceiver.c index 1d75c30a44122b..65a6f35ddab2dc 100644 --- a/drivers/iio/jesd204/xilinx_transceiver.c +++ b/drivers/iio/jesd204/xilinx_transceiver.c @@ -1615,8 +1615,8 @@ int xilinx_xcvr_prbs_err_cnt_get(struct xilinx_xcvr *xcvr, if (xcvr->type != XILINX_XCVR_TYPE_S7_GTX2) { val2 = xilinx_xcvr_drp_read(xcvr, drp_port, addr + 1); - if (val < 0) - return val; + if (val2 < 0) + return val2; } *cnt = ((val2 & 0xFFFF) << 16) | (val & 0xFFFF); From c20fcbbc14e4b19749ff9c698fb198e91c21caa3 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 2 Jun 2022 16:33:01 +0200 Subject: [PATCH 379/407] iio: adc: ad9081: API Version 1.3.0 * Update missing JES204B lcpll values, adi_adxxxx_jesd_tx_pll_startup, Missing JES204B lcpll values leads to PLL startup issues * Added call to bitfield JRX_SYSREF_FOR_STARTUP_I NFO, adi_adxxxx_jesd_rx_link_config_set, JRX_SYSREF_FOR_STARTU P_INFO needs to be enabled when part is in Subclass 1 * Added call to bitfield BF_JTX_SYSREF_FOR_STARTU P_INFO, adi_adxxxx_jesd_tx_link_config_set, JTX_SYSREF_FOR_STARTU P_INFO needs to be enabled when part is in Subclass 1 * Modified oneshot sync procedure to include HAL callback that issues a single pulse SYSREF signal, adi_adxxxx_jesd_oneshot_sync, If in single pulse SYSREF mode, procedure requires the pulse to be issued once. * Updated sysref monitor mode phase get function to include write strobe and display phase value correctly, adi_adxxxx_jesd_sysref_monitor_p hase_get, Write strobe is needed for sysref phase to trigger a value update. The phase value needed to be correctly calculated from two bitfield reads. * Fixed incorrect use of "||" to "&&" in adi_adxxxx_jesd_sysref_irq_jitter_ mux_set(), Parameter check was always failing * Modified full bandwidth mode function to support AD9207 and AD9209, with adi_adxxxx_jesd_tx_fbw_sel_set, AD9207 and AD9209 support full bandwidth mode Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081/adi_ad9081.h | 244 +++++++++++++++++++- drivers/iio/adc/ad9081/adi_ad9081_adc.c | 185 +++++++++++++++ drivers/iio/adc/ad9081/adi_ad9081_config.h | 52 +++-- drivers/iio/adc/ad9081/adi_ad9081_device.c | 2 +- drivers/iio/adc/ad9081/adi_ad9081_jesd.c | 224 +++++++++++++++--- drivers/iio/adc/ad9081/adi_ad9081_sync.c | 172 +++++++++++++- drivers/iio/adc/ad9081/adi_cms_api_common.h | 45 +++- 7 files changed, 871 insertions(+), 53 deletions(-) diff --git a/drivers/iio/adc/ad9081/adi_ad9081.h b/drivers/iio/adc/ad9081/adi_ad9081.h index c78207c58df850..8938b009d22754 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081.h +++ b/drivers/iio/adc/ad9081/adi_ad9081.h @@ -851,8 +851,20 @@ typedef struct { uint64_t adc_freq_hz; /*!< ADC clock frequency in Hz */ uint8_t dev_rev; /*!< Device revision, 0:r0, 1:r1, 2:r1r, 3:r2 */ uint8_t prod_id; + uint64_t jesd_rx_lane_rate; /*!< jrx link lane rate */ } adi_ad9081_info_t; +/*! + * @brief Device Clock Structure + */ +typedef struct { + void *clk_src; /*!< Pointer to connect clk src related to sysref ctrl */ + adi_sysref_ctrl_t + sysref_ctrl; /*!< Function pointer to sysref control function */ + adi_cms_jesd_sysref_mode_e + sysref_mode; /*!< sysref synchronization mode configuration */ +} adi_ad9081_clk_t; + /*! * @brief Device Structure */ @@ -860,6 +872,7 @@ typedef struct { adi_ad9081_hal_t hal_info; adi_ad9081_info_t dev_info; adi_ad9081_serdes_settings_t serdes_info; + adi_ad9081_clk_t clk_info; } adi_ad9081_device_t; /*============= E X P O R T S ==============*/ @@ -2046,6 +2059,84 @@ int32_t adi_ad9081_adc_nyquist_zone_set(adi_ad9081_device_t *device, int32_t adi_ad9081_adc_ddc_fine_gain_set(adi_ad9081_device_t *device, uint8_t fddcs, uint8_t gain); +/** + * @ingroup rx_setup + * @brief System Top Level API. \n Set Data Inversion for each ADC + * Required for correct ADC background Cal operation. See SDUG for more information + * Call after adi_ad9081_device_startup_rx(). + * + * + * @param device Pointer to the device structure + * @param adc_sel Masked list of ADC, as defined by adi_ad9081_adc_sel_e to be enabled/disabled data inversion as described by enable parameter + * @param enable Enable/disable data inversion operation for the adcs specified by adc_sel parameter. + * + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t +adi_ad9081_adc_data_inversion_dc_coupling_set(adi_ad9081_device_t *device, + adi_ad9081_adc_select_e adc_sel, + uint8_t enable); + +/** + * @ingroup rx_setup + * @brief System Top Level API. \n Disable Timing Calibration for each ADC + * Required for correct ADC background Cal operation. See SDUG for more information + * Call after adi_ad9081_device_startup_rx(). + * + * + * @param device Pointer to the device structure + * @param adc_sel Masked list of ADC, as defined by adi_ad9081_adc_sel_e to be enabled/disabled timing calibration as described by enable parameter + * @param enable Enable/disable timing calibration operation for the adcs specified by adc_sel parameter. + * + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t +adi_ad9081_adc_offset_timing_calibration_set(adi_ad9081_device_t *device, + adi_ad9081_adc_select_e adc_sel, + uint8_t enable); + +/** + * @ingroup rx_setup + * @brief System Top Level API. \n Set Offset Calibration for each ADC + * Required for correct ADC background Cal operation. See SDUG for more information + * Call after adi_ad9081_device_startup_rx(). + * + * + * @param device Pointer to the device structure + * @param adc_sel Masked list of ADC, as defined by adi_ad9081_adc_sel_e to be enabled/disabled offset calibration as described by enable parameter + * @param enable Enable/disable offset calibration operation for the adcs specified by adc_sel parameter. + * + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_adc_offset_calibration_set(adi_ad9081_device_t *device, + adi_ad9081_adc_select_e adc_sel, + uint8_t enable); + +/** + * @ingroup rx_setup + * @brief System Top Level API. \n Set Gain Calibration for each ADC + * Required for correct ADC background Cal operation. See SDUG for more information + * Call after adi_ad9081_device_startup_rx(). + * + * + * @param device Pointer to the device structure + * @param adc_sel Masked list of ADC, as defined by adi_ad9081_adc_sel_e to be enabled/disabled gain calibration as described by enable parameter + * @param enable Enable/disable gain calibration operation for the adcs specified by adc_sel parameter. + * + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_adc_gain_calibration_set(adi_ad9081_device_t *device, + adi_ad9081_adc_select_e adc_sel, + uint8_t enable); + /*===== 3 . 1 R E C E I V E D A T A P A T H S E T U P =====*/ /** * @ingroup rx_dp_setup @@ -3454,6 +3545,34 @@ int32_t adi_ad9081_adc_ddc_coarse_sync_enable_set(adi_ad9081_device_t *device, uint8_t cddcs, uint8_t enable); +/** + * @ingroup rx_helper_api + * @brief Configure Coarse DDCs Syncronization + * + * @param device Pointer to the device structure + * @param cddcs Coarse DDCs selection, @see adi_ad9081_adc_coarse_ddc_select_e + * @param enable 0 to disable, 1 to enable + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_adc_ddc_coarse_sync_next_set(adi_ad9081_device_t *device, + uint8_t cddcs, uint8_t enable); + +/** + * @ingroup rx_helper_api + * @brief Configure Coarse DDCs NCO phase offset + * + * @param device Pointer to the device structure + * @param cddcs Coarse DDCs selection, @see adi_ad9081_adc_coarse_ddc_select_e + * @param enable 0 to disable, 1 to enable + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_adc_ddc_coarse_trig_nco_reset_enable_set( + adi_ad9081_device_t *device, uint8_t cddcs, uint8_t enable); + /** * @ingroup rx_helper_api * @brief Enable ADC Clock Out Driver @@ -4502,6 +4621,21 @@ adi_ad9081_jesd_tx_force_digital_reset_set(adi_ad9081_device_t *device, adi_ad9081_jesd_link_select_e links, uint8_t reset); +/** + * @ingroup adc_link_setup + * @brief Set LMFC delay + * + * @param device Pointer to the device structure + * @param links Target link + * @param delay Phase adjustment in conv_clk cycles. Maximum value is k*s/ns. + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_jesd_tx_lmfc_delay_set(adi_ad9081_device_t *device, + adi_ad9081_jesd_link_select_e links, + uint16_t delay); + /*===== A P P E N D I X =====*/ /** * @ingroup appendix @@ -5144,6 +5278,30 @@ adi_ad9081_jesd_sysref_monitor_lmfc_align_error_get(adi_ad9081_device_t *device, int32_t adi_ad9081_jesd_sysref_monitor_lmfc_align_threshold_set( adi_ad9081_device_t *device, uint8_t sysref_error_window); +/** + * @brief Enables the IRQ pin and sets the function of the IRQ_SYSREF_JITTER bit. + * + * @param device Pointer to the device structure + * @param enable 0: IRQ_SYSREF_JITTER shows current status, 1: IRQ_SYSREF_JITTER latches a SYSREF jitter error condition + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_jesd_sysref_irq_enable_set(adi_ad9081_device_t *device, + uint8_t enable); + +/** + * @brief Select IRQ_x pin that outputs SYSREF_JITTER_IRQB information + * + * @param device Pointer to the device structure + * @param pin 0: IRQB_0, 1: IRQB_1 + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_jesd_sysref_irq_jitter_mux_set(adi_ad9081_device_t *device, + uint8_t pin); + /** * @ingroup appdx_mcs * @brief Check oneshot sync mode flag if sync is done. @@ -5158,6 +5316,89 @@ int32_t adi_ad9081_jesd_sysref_oneshot_sync_done_get(adi_ad9081_device_t *device, uint8_t *sync_done); +/** + * @ingroup appdx_mcs + * @brief Calculates lmfc (Jesd204B) or lemc (Jesd204C) value for jesd receiver. + * + * @param dac_clk Variable that holds current dac clock freq in Hz + * @param main_interp Main interpolator + * @param ch_interp Channel interpolator + * @param jesd_param JTX JESD link settings + * @param lmfc_freq LMFC/LEMC value for jesd receiver + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_sync_calc_jrx_lmfc_lemc(uint64_t dac_clk, + uint8_t main_interp, + uint8_t ch_interp, + adi_cms_jesd_param_t *jesd_param, + uint64_t *lmfc_freq); + +/** + * @ingroup appdx_mcs + * @brief Calculates lmfc (Jesd204B) or lemc (Jesd204C) value for jesd transmitter. + * + * @param adc_clk Variable that holds current adc clock freq in Hz + * @param cddc_dcm Coarse DDC decimation value + * @param fddc_dcm Fine DDC decimation value + * @param links Target link + * @param jesd_param JRX JESD link settings + * @param lmfc_freq LMFC/LEMC value for jesd transmitter + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_sync_calc_jtx_lmfc_lemc(uint64_t adc_clk, + uint8_t cddc_dcm[4], + uint8_t fddc_dcm[8], + adi_ad9081_jesd_link_select_e links, + adi_cms_jesd_param_t jesd_param[2], + uint64_t *lmfc_freq); + +/** + * @ingroup appdx_mcs + * @brief Sets the sysref frequency as an integer sub-multiple of LMFC (JESD204B) / LEMC (JESD204C) + * + * @param device Pointer to device struct + * @param sysref_freq Pointer to variable that holds calculated lmfc/lemc (JESD204B/JESD204C) value + * @param dac_clk Variable that holds current dac clock freq in Hz + * @param adc_clk Variable that holds current adc clock freq in Hz + * @param main_interp Main interpolator + * @param ch_interp Channel interpolator + * @param cddc_dcm Coarse DDC decimation value + * @param fddc_dcm Fine DDC decimation value + * @param jtx_links Target link + * @param jrx_param JRX JESD link settings + * @param jtx_param JTX JESD link settings + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t adi_ad9081_sync_sysref_frequency_set( + adi_ad9081_device_t *device, uint64_t *sysref_freq, uint64_t dac_clk, + uint64_t adc_clk, uint8_t main_interp, uint8_t ch_interp, + uint8_t cddc_dcm[4], uint8_t fddc_dcm[8], + adi_ad9081_jesd_link_select_e jtx_links, + adi_cms_jesd_param_t *jrx_param, adi_cms_jesd_param_t jtx_param[2]); + +/** + * @ingroup appdx_mcs + * @brief Reads the time difference between the JESD204B/C receiver LMFC/LEMC boundary and the received data’s LMFC/LEMC boundary + * in JRX_SAMPLE_CLK cycles + * + * @param device Pointer to device struct + * @param links Target link + * @param jrx_phase_diff Pointer to phase diff value + * + * @return API_CMS_ERROR_OK API Completed Successfully + * @return <0 Failed. @see adi_cms_error_e for details. + */ +int32_t +adi_ad9081_sync_jrx_tpl_phase_diff_get(adi_ad9081_device_t *device, + adi_ad9081_jesd_link_select_e links, + uint8_t *jrx_phase_diff); + /*===== A 3 . 0 I R Q S =====*/ /*===== A 3 . 1 D A C D P I R Q S =====*/ @@ -5776,9 +6017,6 @@ int32_t adi_ad9081_jesd_rx_gen_2s_comp(adi_ad9081_device_t *device, int32_t adi_ad9081_jesd_rx_spo_set(adi_ad9081_device_t *device, uint8_t lane, uint8_t spo); -int32_t adi_ad9081_adc_ddc_coarse_sync_next_set(adi_ad9081_device_t *device, - uint8_t cddcs, uint8_t val); - int32_t adi_ad9081_adc_ddc_fine_sync_next_set(adi_ad9081_device_t *device, uint8_t fddcs, uint8_t val); diff --git a/drivers/iio/adc/ad9081/adi_ad9081_adc.c b/drivers/iio/adc/ad9081/adi_ad9081_adc.c index 86ce25a1723e8a..7772c176bf5736 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_adc.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_adc.c @@ -4213,4 +4213,189 @@ int32_t adi_ad9081_adc_smon_next_sync_mode_set(adi_ad9081_device_t *device, return API_CMS_ERROR_OK; } +int32_t +adi_ad9081_adc_data_inversion_dc_coupling_set(adi_ad9081_device_t *device, + adi_ad9081_adc_select_e adc_sel, + uint8_t enable) +{ + int32_t err; + uint32_t reg_customer_up_transfer_addr = 0x2100; + uint32_t reg_user_settings_adc_cal_addr = 0x2115; + uint32_t reg_data_inversion_dc_coupling_addr = 0x2111; + uint8_t data_inversion_setting = 0x0; + int i = 0; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + AD9081_INVALID_PARAM_RETURN(enable > 1); + + err = adi_ad9081_hal_reg_get(device, + reg_data_inversion_dc_coupling_addr, + &data_inversion_setting); + AD9081_ERROR_RETURN(err); + + if (enable) { + for (i = 0; i < 4; i++) { + if ((1 << i) & adc_sel) { + data_inversion_setting |= (0x1 << i); + } + } + } else { + for (i = 0; i < 4; i++) { + if ((1 << i) & adc_sel) { + data_inversion_setting &= ~(0x1 << i); + } + } + } + err = adi_ad9081_hal_reg_set(device, + reg_data_inversion_dc_coupling_addr, + data_inversion_setting); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_reg_set( + device, reg_user_settings_adc_cal_addr, + 1); /* Enable user-defined ADC calibration settings */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_reg_set(device, reg_customer_up_transfer_addr, + 1); /* Trigger Data Transfer */ + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t +adi_ad9081_adc_offset_timing_calibration_set(adi_ad9081_device_t *device, + adi_ad9081_adc_select_e adc_sel, + uint8_t enable) +{ + int32_t err; + uint32_t reg_customer_up_transfer_addr = 0x2100; + uint32_t reg_user_settings_adc_cal_addr = 0x2115; + uint32_t reg_offset_timing_calibration_addr = 0x2116; + uint8_t offset_timing_calibration_setting = 0x0; + int i = 0; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + AD9081_INVALID_PARAM_RETURN(enable > 1); + + err = adi_ad9081_hal_reg_get(device, reg_offset_timing_calibration_addr, + &offset_timing_calibration_setting); + AD9081_ERROR_RETURN(err); + + if (enable) { + for (i = 0; i < 4; i++) { + if ((1 << i) & adc_sel) { + offset_timing_calibration_setting |= (0x1 << i); + } + } + } else { + for (i = 0; i < 4; i++) { + if ((1 << i) & adc_sel) { + offset_timing_calibration_setting &= + ~(0x1 << i); + } + } + } + err = adi_ad9081_hal_reg_set(device, reg_offset_timing_calibration_addr, + offset_timing_calibration_setting); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_reg_set( + device, reg_user_settings_adc_cal_addr, + 1); /* Enable user-defined ADC calibration settings */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_reg_set(device, reg_customer_up_transfer_addr, + 1); /* Trigger Data Transfer */ + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_adc_gain_calibration_set(adi_ad9081_device_t *device, + adi_ad9081_adc_select_e adc_sel, + uint8_t enable) +{ + int32_t err; + uint32_t reg_customer_up_transfer_addr = 0x2100; + uint32_t reg_user_settings_adc_cal_addr = 0x2115; + uint32_t reg_gain_calibration_addr = 0x2117; + uint8_t gain_calibration_setting = 0x0; + int i = 0; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + AD9081_INVALID_PARAM_RETURN(enable > 1); + + err = adi_ad9081_hal_reg_get(device, reg_gain_calibration_addr, + &gain_calibration_setting); + AD9081_ERROR_RETURN(err); + + if (enable) { + for (i = 0; i < 4; i++) { + if ((1 << i) & adc_sel) { + gain_calibration_setting |= (0x1 << i); + } + } + } else { + for (i = 0; i < 4; i++) { + if ((1 << i) & adc_sel) { + gain_calibration_setting &= ~(0x1 << i); + } + } + } + err = adi_ad9081_hal_reg_set(device, reg_gain_calibration_addr, + gain_calibration_setting); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_reg_set( + device, reg_user_settings_adc_cal_addr, + 1); /* Enable user-defined ADC calibration settings */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_reg_set(device, reg_customer_up_transfer_addr, + 1); /* Trigger Data Transfer */ + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_adc_offset_calibration_set(adi_ad9081_device_t *device, + adi_ad9081_adc_select_e adc_sel, + uint8_t enable) +{ + int32_t err; + uint32_t reg_customer_up_transfer_addr = 0x2100; + uint32_t reg_user_settings_adc_cal_addr = 0x2115; + uint32_t reg_offset_calibration_addr = 0x2117; + uint8_t offset_calibration_setting = 0x0; + int i = 0; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + AD9081_INVALID_PARAM_RETURN(enable > 1); + + err = adi_ad9081_hal_reg_get(device, reg_offset_calibration_addr, + &offset_calibration_setting); + AD9081_ERROR_RETURN(err); + + if (enable) { + for (i = 0; i < 4; i++) { + if ((1 << i) & adc_sel) { + offset_calibration_setting |= (0x1 << (4 + i)); + } + } + } else { + for (i = 0; i < 4; i++) { + if ((1 << i) & adc_sel) { + offset_calibration_setting &= ~(0x1 << (4 + i)); + } + } + } + err = adi_ad9081_hal_reg_set(device, reg_offset_calibration_addr, + offset_calibration_setting); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_reg_set( + device, reg_user_settings_adc_cal_addr, + 1); /* Enable user-defined ADC calibration settings */ + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_reg_set(device, reg_customer_up_transfer_addr, + 1); /* Trigger Data Transfer */ + AD9081_ERROR_RETURN(err); + + return API_CMS_ERROR_OK; +} + /*! @} */ \ No newline at end of file diff --git a/drivers/iio/adc/ad9081/adi_ad9081_config.h b/drivers/iio/adc/ad9081/adi_ad9081_config.h index 9e91bef0eaaf96..299867dc9d606a 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_config.h +++ b/drivers/iio/adc/ad9081/adi_ad9081_config.h @@ -40,7 +40,7 @@ #define __FUNCTION_NAME__ __FUNCTION__ #endif -#define AD9081_API_REV 0x00010202 +#define AD9081_API_REV 0x00010300 #define AD9081_API_HW_RESET_LOW 600000 #define AD9081_API_RESET_WAIT 500000 #define AD9081_PLL_LOCK_TRY 75 @@ -636,23 +636,6 @@ int32_t adi_ad9081_adc_fdelay_cdelay_pfir_sel_to_gpio_mapping_set( int32_t adi_ad9081_adc_common_hop_en_set(adi_ad9081_device_t *device, uint8_t enable); -/** - * \brief Enables trig NCO reset for specified coarse DDCs. - * - * - * \param[in] device Pointer to device handler structure. - * \param[in] cddcs 0bXXXX, set X==1 to specify cddcs you wish to affect: - * Bit 3: cddc 3 (MSB) - * Bit 2: cddc 2 - * Bit 1: cddc 1 - * Bit 0: cddc 0 (LSB) - * \param[in] enable 1: enable, 0: disable. - * - * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. - */ -int32_t adi_ad9081_adc_ddc_coarse_trig_nco_reset_enable_set( - adi_ad9081_device_t *device, uint8_t cddcs, uint8_t enable); - /** * \brief Changes Profile Update Mode/ Phase Update Mode for specified coarse DDCs. * @@ -958,6 +941,39 @@ adi_ad9081_jesd_determine_common_nc(adi_ad9081_jesd_link_select_e links, int32_t adi_ad9081_jesd_sysref_d2acenter_enable_set(adi_ad9081_device_t *device, uint8_t enable); +/** + * \brief Set hardware sysref control + * + * \param[in] device Pointer to the device structure + * + * \return API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ +int32_t adi_ad9081_sync_sysref_ctrl(adi_ad9081_device_t *device); + +/** + * \brief Sets JTX_BR_LOG2_RATIO for specified links. + * + * \param[in] device Pointer to device handler structure. + * \param[in] chip_op_mode Chip operating mode, 1 : Tx Only, 2 : Rx Only, 3 : Tx + Rx Only. + * \param[in] jesd_param @see adi_cms_jesd_param_t, pass array with 2 elements for dual link. + * \param[in] links Choose AD9081 link(s) to set mask for: + * 0x1 - AD9081_LINK_0 + * 0x2 - AD9081_LINK_1 + * 0x3 - Both + * \param[in] jtx_lane_rate jtx_lane_rate[0] - lane rate in bps for AD9081_LINK_0. + * jtx_lane_rate[1] - lane rate in bps for AD9081_LINK_1. + * \param[out] jtx_brr jtx_brr[0] - JTX_BR_LOG2_RATIO value for AD9081_LINK_0. + * jtx_brr[1] - JTX_BR_LOG2_RATIO value for AD9081_LINK_1. + * + * \returns API_CMS_ERROR_OK is returned upon success. Otherwise, a failure code. + */ +int32_t adi_ad9081_jesd_tx_calc_br_ratio(adi_ad9081_device_t *device, + adi_cms_chip_op_mode_t chip_op_mode, + adi_cms_jesd_param_t *jesd_param, + adi_ad9081_jesd_link_select_e links, + uint64_t jtx_lane_rate[2], + uint8_t jtx_brr[2]); + #if AD9081_USE_FLOATING_TYPE > 0 int32_t adi_ad9081_hal_calc_nco_ftw_f(adi_ad9081_device_t *device, double freq, double nco_shift, uint64_t *ftw, diff --git a/drivers/iio/adc/ad9081/adi_ad9081_device.c b/drivers/iio/adc/ad9081/adi_ad9081_device.c index 1bf17a6f2dd5be..32ef01f265cd62 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_device.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_device.c @@ -856,7 +856,7 @@ int32_t adi_ad9081_device_init(adi_ad9081_device_t *device) "api v%d.%d.%d commit %s for ad%x ", (AD9081_API_REV & 0xff0000) >> 16, (AD9081_API_REV & 0xff00) >> 8, - (AD9081_API_REV & 0xff), "5b813df", + (AD9081_API_REV & 0xff), "9b8a574", AD9081_ID); AD9081_ERROR_RETURN(err); diff --git a/drivers/iio/adc/ad9081/adi_ad9081_jesd.c b/drivers/iio/adc/ad9081/adi_ad9081_jesd.c index 10398632723eaa..99a6c8fd9a8f51 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_jesd.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_jesd.c @@ -16,7 +16,9 @@ /*============= I N C L U D E S ============*/ #include "adi_ad9081_config.h" #include "adi_ad9081_hal.h" +#include "adi_utils.h" +#define NELEMS(x) (sizeof(x) / sizeof((x)[0])) /*============= C O D E ====================*/ int32_t adi_ad9081_jesd_rx_link_select_set(adi_ad9081_device_t *device, adi_ad9081_jesd_link_select_e links) @@ -351,6 +353,11 @@ int32_t adi_ad9081_jesd_rx_link_config_set(adi_ad9081_device_t *device, device, REG_JRX_TPL_1_ADDR, BF_JRX_TPL_BUF_PROTECTION_INFO, 0); AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set( + device, REG_JRX_CORE_1_ADDR, + BF_JRX_SYSREF_FOR_STARTUP_INFO, + jesd_param->jesd_subclass); + AD9081_ERROR_RETURN(err); } } @@ -999,6 +1006,9 @@ int32_t adi_ad9081_jesd_rx_bit_rate_get(adi_ad9081_device_t *device, bit_rate = bit_rate / (jesd_l * (jesd204b_en > 0 ? 8 : 64) * main_interp * ch_interp); #endif + + device->dev_info.jesd_rx_lane_rate = bit_rate; + err = adi_ad9081_hal_log_write(device, ADI_CMS_LOG_MSG, "jrx bit rate is %llu bps", bit_rate); AD9081_ERROR_RETURN(err); @@ -1893,8 +1903,8 @@ int32_t adi_ad9081_jesd_tx_pll_startup(adi_ad9081_device_t *device, { int32_t err; uint8_t i, b_lcpll, div_m, div_p, ref_in_div, sdsrefclk_ratio, - jesd_pll_locked; - uint8_t jesd204b_lcpll[] = { 5, 10, 20, 40 }; + jesd_pll_locked, lcpll_count; + uint8_t jesd204b_lcpll[] = { 5, 10, 15, 20, 30, 40 }; uint8_t jesd204c_lcpll[] = { 11, 22, 33, 44 }; uint8_t *jesd204_lcpll; uint64_t a, b; @@ -1923,9 +1933,11 @@ int32_t adi_ad9081_jesd_tx_pll_startup(adi_ad9081_device_t *device, 1; div_p = ((jesd204b_en > 0)) ? 0 : 1; jesd204_lcpll = (jesd204b_en > 0) ? jesd204b_lcpll : jesd204c_lcpll; - b_lcpll = jesd204_lcpll[0]; + lcpll_count = (jesd204b_en > 0) ? NELEMS(jesd204b_lcpll) : + NELEMS(jesd204c_lcpll); + sdsrefclk_ratio = 1; - for (i = 0; i < 4; i++) { + for (i = 0; i < lcpll_count; i++) { a = device->dev_info.dac_freq_hz * jesd204_lcpll[i] * (jesd204b_en > 0 ? 40 : 66); b = bit_rate * 4 * (jesd204b_en > 0 ? 5 : 11); @@ -1940,8 +1952,9 @@ int32_t adi_ad9081_jesd_tx_pll_startup(adi_ad9081_device_t *device, break; } } - if (i == 4) { + if (i == lcpll_count) { AD9081_LOG_ERR("SDSPLLREFCLK divider not found."); + return API_CMS_ERROR_JESD_PLL_NOT_LOCKED; } if (bit_rate > 4000000000ULL && bit_rate <= 8000000000ULL) { b_lcpll = b_lcpll * 2; @@ -2006,6 +2019,7 @@ int32_t adi_ad9081_jesd_tx_pll_startup(adi_ad9081_device_t *device, } if (jesd_pll_locked == 0) { AD9081_LOG_ERR("JESD PLL is not locked."); + return API_CMS_ERROR_JESD_PLL_NOT_LOCKED; } return API_CMS_ERROR_OK; @@ -2163,11 +2177,12 @@ int32_t adi_ad9081_jesd_tx_link_config_set(adi_ad9081_device_t *device, int32_t err; uint8_t i, j, link; uint8_t jesd_dcm[2], jesd_link_async[2], jesd204b_en, jesd_pll_locked, - jesd_bit_repeat_ratio, div_m, adc_div; + jesd_bit_repeat_ratio, div_m, adc_div, jesd_brr[2]; uint32_t rx_link_lmfc_periods[2], rx_link_lmfc_period, rx_tx_lmfc_lcm, lcm_remainder, lcm_gcd; uint32_t a, b, c; uint64_t bit_rate[2]; + adi_cms_chip_op_mode_t chip_mode; AD9081_NULL_POINTER_RETURN(device); AD9081_LOG_FUNC(); AD9081_NULL_POINTER_RETURN(jesd_param); @@ -2206,6 +2221,8 @@ int32_t adi_ad9081_jesd_tx_link_config_set(adi_ad9081_device_t *device, err = adi_ad9081_jesd_pll_lock_status_get(device, &jesd_pll_locked); AD9081_ERROR_RETURN(err); if (jesd_pll_locked == 0) { + /* Determine chip mode = (rx only) */ + chip_mode = RX_ONLY; /* _configurePll()@ad9081_rx_r1.py */ err = adi_ad9081_jesd_tx_pll_startup( device, @@ -2276,6 +2293,8 @@ int32_t adi_ad9081_jesd_tx_link_config_set(adi_ad9081_device_t *device, BF_LMFC_PERIOD_SPI_EN_INFO, 1); /* not paged */ AD9081_ERROR_RETURN(err); + } else { /* Determine chip mode = (tx + rx only) */ + chip_mode = TX_RX_ONLY; } /* power down all physical lanes, setupJtx()@ad9081_rx_r1.py, _enableJtxPhyLanes()@ad9081_rx_r1.py */ @@ -2310,6 +2329,11 @@ int32_t adi_ad9081_jesd_tx_link_config_set(adi_ad9081_device_t *device, device->serdes_info.ser_settings.lane_mapping[1]); AD9081_ERROR_RETURN(err); + /* _calcJtxLinkBitRepeatRatios()@ad9081_rx_r1.py */ + err = adi_ad9081_jesd_tx_calc_br_ratio(device, chip_mode, jesd_param, + links, bit_rate, jesd_brr); + AD9081_ERROR_RETURN(err); + /* configure jtx link framer, _configureJtxLinkFramer()@ad9081_rx_r1.py */ jesd_link_async[0] = 0; jesd_link_async[1] = 0; @@ -2399,28 +2423,14 @@ int32_t adi_ad9081_jesd_tx_link_config_set(adi_ad9081_device_t *device, BF_JTX_LINK_204C_SEL_INFO, (jesd204b_en > 0) ? 0 : 1); /* not paged */ AD9081_ERROR_RETURN(err); - /* _calcJtxLinkBitRepeatRatios()@ad9081_rx_r1.py */ - jesd_bit_repeat_ratio = 0; - if (bit_rate[i] > 4000000000ULL && - bit_rate[i] <= 8000000000ULL) { /* 4Gbps ~ 8Gbps */ - jesd_bit_repeat_ratio = 1; - } else if (bit_rate[i] > 2000000000ULL && - bit_rate[i] <= - 4000000000ULL) { /* 2Gbps ~ 4Gbps */ - jesd_bit_repeat_ratio = 2; - } else if (bit_rate[i] > 1000000000ULL && - bit_rate[i] <= - 2000000000ULL) { /* 1Gbps ~ 2Gbps */ - jesd_bit_repeat_ratio = 3; - } else if (bit_rate[i] > 500000000ULL && - bit_rate[i] <= - 1000000000ULL) { /* 0.5Gbps ~ 1Gbps */ - jesd_bit_repeat_ratio = 4; - } else if (bit_rate[i] > 250000000ULL && - bit_rate[i] <= - 500000000ULL) { /* 0.25Gbps ~ 0.5Gbps */ - jesd_bit_repeat_ratio = 5; - } + err = adi_ad9081_hal_bf_set( + device, REG_JTX_CORE_1_ADDR, + BF_JTX_SYSREF_FOR_STARTUP_INFO, + jesd_param->jesd_subclass); + AD9081_ERROR_RETURN(err); + + jesd_bit_repeat_ratio = jesd_brr[i]; + /* _configureJtxLinkBitRepeatLaneStates()@ad9081_rx_r1.py */ for (j = 0; j < 8; j++) { if (device->serdes_info.ser_settings @@ -2595,6 +2605,34 @@ int32_t adi_ad9081_jesd_tx_bring_up(adi_ad9081_device_t *device, return API_CMS_ERROR_OK; } +int32_t adi_ad9081_jesd_tx_lmfc_delay_set(adi_ad9081_device_t *device, + adi_ad9081_jesd_link_select_e links, + uint16_t delay) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + + if ((links & AD9081_LINK_0) > 0) { + err = adi_ad9081_jesd_tx_link_select_set(device, AD9081_LINK_0); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_JTX_TPL_2_ADDR, + BF_JTX_TPL_PHASE_ADJUST_INFO, + delay); + AD9081_ERROR_RETURN(err); + } + if ((links & AD9081_LINK_1) > 0) { + err = adi_ad9081_jesd_tx_link_select_set(device, AD9081_LINK_1); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_set(device, REG_JTX_TPL_3_ADDR, + BF_JTX_TPL_PHASE_ADJUST_INFO, + delay); + AD9081_ERROR_RETURN(err); + } + + return API_CMS_ERROR_OK; +} + int32_t adi_ad9081_jesd_tx_link_enable_set(adi_ad9081_device_t *device, adi_ad9081_jesd_link_select_e links, uint8_t link_en) @@ -4199,4 +4237,134 @@ adi_ad9081_jesd_determine_common_nc(adi_ad9081_jesd_link_select_e links, return nc; } +int32_t adi_ad9081_jesd_tx_calc_br_ratio(adi_ad9081_device_t *device, + adi_cms_chip_op_mode_t chip_op_mode, + adi_cms_jesd_param_t *jesd_param, + adi_ad9081_jesd_link_select_e links, + uint64_t jtx_lane_rate[2], + uint8_t jtx_brr[2]) +{ + uint8_t i, link, max_jtx_brr, min_jtx_brr, jtx_link_lane_rate_spread, + jtx_link_brr_spread, jtx_brr_adjust, quotient, jtx_br_ratio; + uint64_t jrx_lane_rate, max_jtx_lane_rate, min_jtx_lane_rate; + uint32_t jrx_jtx_ratio; + AD9081_NULL_POINTER_RETURN(device); + AD9081_LOG_FUNC(); + AD9081_NULL_POINTER_RETURN(jesd_param); + + jrx_lane_rate = device->dev_info.jesd_rx_lane_rate; + if (chip_op_mode == TX_RX_ONLY) { /* Determine chip mode = (tx + rx) */ + for (i = 0; i < 2; i++) { + link = (uint8_t)(links & (AD9081_LINK_0 << i)); + if (link > 0) { +#ifdef __KERNEL__ + jrx_jtx_ratio = div64_u64(jrx_lane_rate, + jtx_lane_rate[i]); +#else + jrx_jtx_ratio = + jrx_lane_rate / jtx_lane_rate[i]; +#endif + if (jtx_lane_rate[i] > 8000000000ULL) { + jtx_brr[i] = adi_api_utils_log2( + jrx_jtx_ratio); + } else if (jtx_lane_rate[i] <= 8000000000ULL) { +#ifdef __KERNEL__ + quotient = div64_u64(8000000000ULL, + jtx_lane_rate[i]) + + 1; +#else + quotient = ((8000000000ULL / + jtx_lane_rate[i]) + + 1); +#endif + jtx_br_ratio = + adi_api_utils_is_power_of_two( + quotient) ? + quotient : + ((quotient & + (quotient - 1)) + << 1); + + if (jtx_br_ratio > jrx_jtx_ratio) { + jtx_brr[i] = adi_api_utils_log2( + jtx_br_ratio); + } else { + jtx_brr[i] = adi_api_utils_log2( + jrx_jtx_ratio); + } + } + } + } + } + if (chip_op_mode == RX_ONLY) { /* Determine chip mode = (rx only) */ + for (i = 0; i < 2; i++) { + link = (uint8_t)(links & (AD9081_LINK_0 << i)); + if (link > 0) { + jtx_brr[i] = 0; + if (jtx_lane_rate[i] > 4000000000ULL && + jtx_lane_rate[i] <= + 8000000000ULL) { /* 4Gbps ~ 8Gbps */ + jtx_brr[i] = 1; + } else if (jtx_lane_rate[i] > 2000000000ULL && + jtx_lane_rate[i] <= + 4000000000ULL) { /* 2Gbps ~ 4Gbps */ + jtx_brr[i] = 2; + } else if (jtx_lane_rate[i] > 1000000000ULL && + jtx_lane_rate[i] <= + 2000000000ULL) { /* 1Gbps ~ 2Gbps */ + jtx_brr[i] = 3; + } else if (jtx_lane_rate[i] > 500000000ULL && + jtx_lane_rate[i] <= + 1000000000ULL) { /* 0.5Gbps ~ 1Gbps */ + jtx_brr[i] = 4; + } else if (jtx_lane_rate[i] > 250000000ULL && + jtx_lane_rate[i] <= + 500000000ULL) { /* 0.25Gbps ~ 0.5Gbps */ + jtx_brr[i] = 5; + } + } + } + + if ((jesd_param->jesd_duallink == 1) && + (jtx_lane_rate[0] != jtx_lane_rate[1])) { + max_jtx_lane_rate = + (jtx_lane_rate[0] > jtx_lane_rate[1]) ? + jtx_lane_rate[0] : + jtx_lane_rate[1]; + min_jtx_lane_rate = + (jtx_lane_rate[0] < jtx_lane_rate[1]) ? + jtx_lane_rate[0] : + jtx_lane_rate[1]; + + max_jtx_brr = (jtx_brr[0] > jtx_brr[1]) ? jtx_brr[0] : + jtx_brr[1]; + min_jtx_brr = (jtx_brr[0] < jtx_brr[1]) ? jtx_brr[0] : + jtx_brr[1]; + +#ifdef __KERNEL__ + jtx_link_lane_rate_spread = + div64_u64(max_jtx_lane_rate, min_jtx_lane_rate); +#else + jtx_link_lane_rate_spread = + max_jtx_lane_rate / min_jtx_lane_rate; +#endif + jtx_link_brr_spread = + (1 << max_jtx_brr) / (1 << min_jtx_brr); + + if (jtx_link_lane_rate_spread != jtx_link_brr_spread) { + jtx_brr_adjust = adi_api_utils_log2( + jtx_link_lane_rate_spread / + jtx_link_brr_spread); + ((jtx_brr[0] == min_jtx_brr)) ? + (jtx_brr[0] = + max_jtx_brr + jtx_brr_adjust) : + (jtx_brr[1] = + max_jtx_brr + jtx_brr_adjust); + } + } + } + + return API_CMS_ERROR_OK; +} + /*! @} */ \ No newline at end of file diff --git a/drivers/iio/adc/ad9081/adi_ad9081_sync.c b/drivers/iio/adc/ad9081/adi_ad9081_sync.c index d6398788a78b10..e211067e41ef84 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_sync.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_sync.c @@ -16,6 +16,7 @@ /*============= I N C L U D E S ============*/ #include "adi_ad9081_config.h" #include "adi_ad9081_hal.h" +#include "adi_utils.h" /*============= C O D E ====================*/ @@ -84,6 +85,20 @@ int32_t adi_ad9081_jesd_sysref_input_mode_set( return API_CMS_ERROR_OK; } +int32_t adi_ad9081_sync_sysref_ctrl(adi_ad9081_device_t *device) +{ + AD9081_NULL_POINTER_RETURN(device); + AD9081_NULL_POINTER_RETURN(device->clk_info.clk_src); + AD9081_NULL_POINTER_RETURN(device->clk_info.sysref_ctrl); + + if (API_CMS_ERROR_OK != + device->clk_info.sysref_ctrl(device->clk_info.clk_src)) { + return API_CMS_ERROR_SYSREF_CTRL; + } + + return API_CMS_ERROR_OK; +} + int32_t adi_ad9081_jesd_oneshot_sync(adi_ad9081_device_t *device, adi_cms_jesd_subclass_e subclass) { @@ -130,6 +145,12 @@ int32_t adi_ad9081_jesd_oneshot_sync(adi_ad9081_device_t *device, BF_SYSREF_MODE_ONESHOT_INFO, 1); /* not paged */ AD9081_ERROR_RETURN(err); + + if (device->clk_info.sysref_mode == SYSREF_ONESHOT) { + err = adi_ad9081_sync_sysref_ctrl(device); + AD9081_ERROR_RETURN(err); + } + if (err = adi_ad9081_hal_bf_wait_to_clear( device, REG_SYSREF_MODE_ADDR, BF_SYSREF_MODE_ONESHOT_INFO), /* not paged */ @@ -289,12 +310,16 @@ int32_t adi_ad9081_jesd_sysref_monitor_phase_get(adi_ad9081_device_t *device, AD9081_NULL_POINTER_RETURN(sysref_phase); AD9081_LOG_FUNC(); + /* Write strobe to trigger a value update */ + err = adi_ad9081_hal_bf_set(device, REG_SYSREF_PHASE0_ADDR, 0x800, + 0x00); + err = adi_ad9081_hal_bf_get(device, REG_SYSREF_PHASE0_ADDR, 0x800, &phase0_val, sizeof(uint8_t)); err = adi_ad9081_hal_bf_get(device, REG_SYSREF_PHASE1_ADDR, 0x400, &phase1_val, sizeof(uint8_t)); - *sysref_phase = (phase0_val << 8) + phase1_val; + *sysref_phase = (phase1_val << 8) + phase0_val; AD9081_ERROR_RETURN(err); @@ -360,7 +385,7 @@ int32_t adi_ad9081_jesd_sysref_irq_jitter_mux_set(adi_ad9081_device_t *device, AD9081_NULL_POINTER_RETURN(device); AD9081_LOG_FUNC(); - if (pin != 0 || pin != 1) { + if (pin != 0 && pin != 1) { return API_CMS_ERROR_INVALID_PARAM; } @@ -389,5 +414,148 @@ adi_ad9081_jesd_sysref_oneshot_sync_done_get(adi_ad9081_device_t *device, AD9081_LOG_ERR("oneshot sync not finished."); } + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_sync_calc_jrx_lmfc_lemc(uint64_t dac_clk, + uint8_t main_interp, + uint8_t ch_interp, + adi_cms_jesd_param_t *jesd_param, + uint64_t *lmfc_freq) +{ + if (lmfc_freq == NULL) { + return API_CMS_ERROR_NULL_PARAM; + } + +#ifdef __KERNEL__ + *lmfc_freq = + div64_u64(dac_clk, jesd_param->jesd_s * jesd_param->jesd_k * + main_interp * ch_interp); +#else + *lmfc_freq = (dac_clk) / (jesd_param->jesd_s * jesd_param->jesd_k * + main_interp * ch_interp); +#endif + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_sync_calc_jtx_lmfc_lemc(uint64_t adc_clk, + uint8_t cddc_dcm[4], + uint8_t fddc_dcm[8], + adi_ad9081_jesd_link_select_e links, + adi_cms_jesd_param_t jesd_param[2], + uint64_t *lmfc_freq) +{ + uint64_t lmfc_link0, lmfc_link1, gcd, min_link, max_link, lmfc_gcd; + uint8_t cdcm, fdcm; + if (lmfc_freq == NULL) { + return API_CMS_ERROR_NULL_PARAM; + } + + cdcm = adi_ad9081_adc_ddc_coarse_dcm_decode(cddc_dcm[0]); + fdcm = adi_ad9081_adc_ddc_fine_dcm_decode(fddc_dcm[0]); + + if (jesd_param->jesd_duallink > 0) { +#ifdef __KERNEL__ + /* link 0 */ + lmfc_link0 = div64_u64(adc_clk, jesd_param[0].jesd_s * + jesd_param[0].jesd_k * + cdcm * fdcm); + + /* link 1 */ + lmfc_link1 = div64_u64(adc_clk, jesd_param[1].jesd_s * + jesd_param[1].jesd_k * + cdcm * fdcm); +#else + /* link 0 */ + lmfc_link0 = (adc_clk) / (jesd_param[0].jesd_s * + jesd_param[0].jesd_k * cdcm * fdcm); + + /* link 1 */ + lmfc_link1 = (adc_clk) / (jesd_param[1].jesd_s * + jesd_param[1].jesd_k * cdcm * fdcm); +#endif + + /* gcd between links */ + max_link = (lmfc_link0 >= lmfc_link1) ? lmfc_link0 : lmfc_link1; + min_link = (lmfc_link0 >= lmfc_link1) ? lmfc_link1 : lmfc_link0; + gcd = adi_api_utils_gcd(min_link, max_link); + lmfc_gcd = gcd; + } else { + /* link 0 */ +#ifdef __KERNEL__ + lmfc_link0 = div64_u64(adc_clk, jesd_param[0].jesd_s * + jesd_param[0].jesd_k * + cdcm * fdcm); +#else + lmfc_link0 = (adc_clk) / (jesd_param[0].jesd_s * + jesd_param[0].jesd_k * cdcm * fdcm); +#endif + lmfc_gcd = lmfc_link0; + } + + *lmfc_freq = lmfc_gcd; + return API_CMS_ERROR_OK; +} + +int32_t adi_ad9081_sync_sysref_frequency_set( + adi_ad9081_device_t *device, uint64_t *sysref_freq, uint64_t dac_clk, + uint64_t adc_clk, uint8_t main_interp, uint8_t ch_interp, + uint8_t cddc_dcm[4], uint8_t fddc_dcm[8], + adi_ad9081_jesd_link_select_e jtx_links, + adi_cms_jesd_param_t *jrx_param, adi_cms_jesd_param_t jtx_param[2]) +{ + uint64_t jrx_lmfc, jtx_lmfc, max_lmfc, min_lmfc, gcd = 0; + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_NULL_POINTER_RETURN(sysref_freq); + AD9081_NULL_POINTER_RETURN(jrx_param); + AD9081_LOG_FUNC(); + + /* jrx */ + err = adi_ad9081_sync_calc_jrx_lmfc_lemc( + dac_clk, main_interp, ch_interp, jrx_param, &jrx_lmfc); + AD9081_ERROR_RETURN(err); + + /* jtx */ + err = adi_ad9081_sync_calc_jtx_lmfc_lemc( + adc_clk, cddc_dcm, fddc_dcm, jtx_links, jtx_param, &jtx_lmfc); + AD9081_ERROR_RETURN(err); + + /* gcd */ + max_lmfc = (jrx_lmfc >= jtx_lmfc) ? jrx_lmfc : jtx_lmfc; + min_lmfc = (jrx_lmfc >= jtx_lmfc) ? jtx_lmfc : jrx_lmfc; + gcd = adi_api_utils_gcd(min_lmfc, max_lmfc); + *sysref_freq = gcd; + + return API_CMS_ERROR_OK; +} + +int32_t +adi_ad9081_sync_jrx_tpl_phase_diff_get(adi_ad9081_device_t *device, + adi_ad9081_jesd_link_select_e links, + uint8_t *jrx_phase_diff) +{ + int32_t err; + AD9081_NULL_POINTER_RETURN(device); + AD9081_NULL_POINTER_RETURN(jrx_phase_diff); + AD9081_LOG_FUNC(); + + if ((links & AD9081_LINK_0) > 0) { + err = adi_ad9081_jesd_rx_link_select_set(device, AD9081_LINK_0); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_get(device, REG_JRX_TPL_5_ADDR, + BF_JRX_TPL_PHASE_DIFF_INFO, + jrx_phase_diff, 1); + AD9081_ERROR_RETURN(err); + } + if ((links & AD9081_LINK_1) > 0) { + err = adi_ad9081_jesd_rx_link_select_set(device, AD9081_LINK_1); + AD9081_ERROR_RETURN(err); + err = adi_ad9081_hal_bf_get(device, REG_JRX_TPL_5_ADDR, + BF_JRX_TPL_PHASE_DIFF_INFO, + jrx_phase_diff, 1); + AD9081_ERROR_RETURN(err); + } + return API_CMS_ERROR_OK; } \ No newline at end of file diff --git a/drivers/iio/adc/ad9081/adi_cms_api_common.h b/drivers/iio/adc/ad9081/adi_cms_api_common.h index 88a7bfb9cc0500..02c659bd37c5d1 100644 --- a/drivers/iio/adc/ad9081/adi_cms_api_common.h +++ b/drivers/iio/adc/ad9081/adi_cms_api_common.h @@ -21,6 +21,28 @@ #include #include #include +#include + +static inline int32_t adi_api_utils_is_power_of_two(uint64_t x) +{ + return (u32) is_power_of_2(x); +} + +static inline int32_t adi_api_utils_gcd(int32_t u, int32_t v) +{ + return (u32) gcd(u, v); +} + +static inline uint32_t adi_api_utils_log2(uint32_t a) +{ + uint8_t b = 0; + + while (a >>= 1) + b++; + + return b; /* log2(a) , only for power of 2 numbers */ +} + #else #include #include @@ -70,7 +92,8 @@ typedef enum { API_CMS_ERROR_LOG_WRITE = -68, /*!< Log write error */ API_CMS_ERROR_LOG_CLOSE = -69, /*!< Log close error */ API_CMS_ERROR_DELAY_US = -70, /*!< Delay error */ - API_CMS_ERROR_PD_STBY_PIN_CTRL = -71 /*!< PD STBY function error */ + API_CMS_ERROR_PD_STBY_PIN_CTRL = -71, /*!< PD STBY function error */ + API_CMS_ERROR_SYSREF_CTRL = -72 /*!< SYSREF enable function error */ } adi_cms_error_e; @@ -247,6 +270,15 @@ typedef struct { uint8_t jesd_mode_s_sel; /*!< JESD mode S value */ } adi_cms_jesd_param_t; +/*! + * @brief Enumerate ADI Device Operating Mode + */ +typedef enum { + TX_ONLY = 1, /*!< Chip using Tx path only */ + RX_ONLY = 2, /*!< Chip using Rx path only */ + TX_RX_ONLY = 3 /*!< Chip using Tx + Rx both paths */ +} adi_cms_chip_op_mode_t; + /** * @brief Platform dependent SPI access functions. * @@ -401,6 +433,17 @@ typedef int32_t (*adi_pd_stby_pin_ctrl_t)(void *user_data, uint8_t enable); */ typedef int32_t (*adi_reset_pin_ctrl_t)(void *user_data, uint8_t enable); +/** + * @brief sysref control function + * + * @param clk_src A void pointer to a structure containing the clock source + * required by the function to control the hardware sysref control. + * + * @return 0 for success + * @return Any non-zero value indicates an error + */ +typedef int32_t (*adi_sysref_ctrl_t)(void *clk_src); + /** * @brief Control function for GPIO write. * From 2e7fb617cc96fd64a2a56aeaade9a2fb9903e9d7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 1 Jul 2022 13:24:24 +0200 Subject: [PATCH 380/407] iio: adc: ad9081: Updates for API v1.3.0 * Use sysref requets callback * Remove adi_ad9081_jesd_sysref_oneshot_sync_done_get() Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index 1d3949cd618b35..d2cb9bde61c53e 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -480,9 +480,11 @@ static int ad9081_reset_pin_ctrl(void *user_data, u8 enable) return gpiod_direction_output(conv->reset_gpio, enable); } -static int ad9081_sysref_ctrl(struct ad9081_phy *phy, u8 enable) +static int ad9081_sysref_ctrl(void *clk_src) { - if (phy->jdev && enable) + struct ad9081_phy *phy = clk_src; + + if (phy->jdev) return jesd204_sysref_async_force(phy->jdev); return 0; @@ -4465,10 +4467,13 @@ static int ad9081_jesd204_link_init(struct jesd204_dev *jdev, if (ret) return ret; - if (phy->sysref_continuous_dis) + if (phy->sysref_continuous_dis) { lnk->sysref.mode = JESD204_SYSREF_ONESHOT; - else + phy->ad9081.clk_info.sysref_mode = SYSREF_ONESHOT; + } else { lnk->sysref.mode = JESD204_SYSREF_CONTINUOUS; + phy->ad9081.clk_info.sysref_mode = SYSREF_CONT; + } return JESD204_STATE_CHANGE_DONE; } @@ -4667,20 +4672,6 @@ static int ad9081_jesd204_setup_stage1(struct jesd204_dev *jdev, if (ret != 0) return ret; - if (phy->sysref_continuous_dis) { - u8 sync_done; - - ad9081_sysref_ctrl(phy, 1); - - ret = adi_ad9081_jesd_sysref_oneshot_sync_done_get(&phy->ad9081, - &sync_done); - if (ret != 0) - return ret; - - if (sync_done != 1) - return JESD204_STATE_CHANGE_ERROR; - } - ret = adi_ad9081_hal_bf_set(&phy->ad9081, REG_SYNC_DEBUG0_ADDR, BF_AVRG_FLOW_EN_INFO, 0); if (ret != 0) @@ -4859,6 +4850,9 @@ static int ad9081_probe(struct spi_device *spi) phy->ad9081.hal_info.user_data = conv; phy->ad9081.hal_info.log_write = ad9081_log_write; + phy->ad9081.clk_info.sysref_ctrl = ad9081_sysref_ctrl; + phy->ad9081.clk_info.clk_src = phy; + phy->ad9081.serdes_info = (adi_ad9081_serdes_settings_t) { .ser_settings = { /* txfe jtx */ .lane_settings = { From 5ec13a594e81a28690ba61d11387b61bb7daab85 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Mon, 4 Jul 2022 17:16:37 +0300 Subject: [PATCH 381/407] iio: adc: ad9081: Remove "adi_utils.h" include Not available but not used either. Fixes: fatal error: adi_utils.h: No such file or directory Signed-off-by: Dragos Bogdan --- drivers/iio/adc/ad9081/adi_ad9081_jesd.c | 1 - drivers/iio/adc/ad9081/adi_ad9081_sync.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/iio/adc/ad9081/adi_ad9081_jesd.c b/drivers/iio/adc/ad9081/adi_ad9081_jesd.c index 99a6c8fd9a8f51..49e3d6ee74bbc7 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_jesd.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_jesd.c @@ -16,7 +16,6 @@ /*============= I N C L U D E S ============*/ #include "adi_ad9081_config.h" #include "adi_ad9081_hal.h" -#include "adi_utils.h" #define NELEMS(x) (sizeof(x) / sizeof((x)[0])) /*============= C O D E ====================*/ diff --git a/drivers/iio/adc/ad9081/adi_ad9081_sync.c b/drivers/iio/adc/ad9081/adi_ad9081_sync.c index e211067e41ef84..281d4640ccdfee 100644 --- a/drivers/iio/adc/ad9081/adi_ad9081_sync.c +++ b/drivers/iio/adc/ad9081/adi_ad9081_sync.c @@ -16,7 +16,6 @@ /*============= I N C L U D E S ============*/ #include "adi_ad9081_config.h" #include "adi_ad9081_hal.h" -#include "adi_utils.h" /*============= C O D E ====================*/ From bed09d7225b8c51fe4b45649c855e5f7a3f476f5 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 17 Feb 2021 11:06:08 +0300 Subject: [PATCH 382/407] Revert "serial: max310x: rework RX interrupt handling" commit 2334de198fed3da72e9785ecdd691d101aa96e77 upstream. This reverts commit fce3c5c1a2d9cd888f2987662ce17c0c651916b2. FIFO is triggered 4 intervals after receiving a byte, it's good when we don't care about the time of reception, but are only interested in the presence of any activity on the line. Unfortunately, this method is not suitable for all tasks, for example, the RS-485 protocol will not work properly, since the state machine must track the request-response time and after the timeout expires, a decision is made that the device on the line is not responding. Signed-off-by: Alexander Shiyan Link: https://lore.kernel.org/r/20210217080608.31192-1-shc_work@mail.ru Fixes: fce3c5c1a2d9 ("serial: max310x: rework RX interrupt handling") Cc: Thomas Petazzoni Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 21130af106bb66..8434bd5a8ec78e 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1056,9 +1056,9 @@ static int max310x_startup(struct uart_port *port) max310x_port_update(port, MAX310X_MODE1_REG, MAX310X_MODE1_TRNSCVCTRL_BIT, 0); - /* Reset FIFOs */ - max310x_port_write(port, MAX310X_MODE2_REG, - MAX310X_MODE2_FIFORST_BIT); + /* Configure MODE2 register & Reset FIFOs*/ + val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT; + max310x_port_write(port, MAX310X_MODE2_REG, val); max310x_port_update(port, MAX310X_MODE2_REG, MAX310X_MODE2_FIFORST_BIT, 0); @@ -1086,27 +1086,8 @@ static int max310x_startup(struct uart_port *port) /* Clear IRQ status register */ max310x_port_read(port, MAX310X_IRQSTS_REG); - /* - * Let's ask for an interrupt after a timeout equivalent to - * the receiving time of 4 characters after the last character - * has been received. - */ - max310x_port_write(port, MAX310X_RXTO_REG, 4); - - /* - * Make sure we also get RX interrupts when the RX FIFO is - * filling up quickly, so get an interrupt when half of the RX - * FIFO has been filled in. - */ - max310x_port_write(port, MAX310X_FIFOTRIGLVL_REG, - MAX310X_FIFOTRIGLVL_RX(MAX310X_FIFO_SIZE / 2)); - - /* Enable RX timeout interrupt in LSR */ - max310x_port_write(port, MAX310X_LSR_IRQEN_REG, - MAX310X_LSR_RXTO_BIT); - - /* Enable LSR, RX FIFO trigger, CTS change interrupts */ - val = MAX310X_IRQ_LSR_BIT | MAX310X_IRQ_RXFIFO_BIT | MAX310X_IRQ_TXEMPTY_BIT; + /* Enable RX, TX, CTS change interrupts */ + val = MAX310X_IRQ_RXEMPTY_BIT | MAX310X_IRQ_TXEMPTY_BIT; max310x_port_write(port, MAX310X_IRQEN_REG, val | MAX310X_IRQ_CTS_BIT); return 0; From 32271b65c00162508f88f38720e8f0c4fb3e0c4a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 3 May 2021 13:56:37 +0200 Subject: [PATCH 383/407] Revert "serial: max310x: pass return value of spi_register_driver" [ Upstream commit b0a85abbe92e1a6f3e8580a4590fa7245de7090b ] This reverts commit 51f689cc11333944c7a457f25ec75fcb41e99410. Because of recent interactions with developers from @umn.edu, all commits from them have been recently re-reviewed to ensure if they were correct or not. Upon review, this commit was found to be incorrect for the reasons below, so it must be reverted. It will be fixed up "correctly" in a later kernel change. This change did not properly unwind from the error condition, so it was not correct. Cc: Kangjie Lu Acked-by: Jiri Slaby Link: https://lore.kernel.org/r/20210503115736.2104747-11-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/max310x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 8434bd5a8ec78e..f60b7b86d0991e 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1527,10 +1527,10 @@ static int __init max310x_uart_init(void) return ret; #ifdef CONFIG_SPI_MASTER - ret = spi_register_driver(&max310x_spi_driver); + spi_register_driver(&max310x_spi_driver); #endif - return ret; + return 0; } module_init(max310x_uart_init); From b9e2e4a59cbe2002ec29f00b76fd89fa2b7c2c1f Mon Sep 17 00:00:00 2001 From: Atul Gopinathan Date: Mon, 3 May 2021 13:56:38 +0200 Subject: [PATCH 384/407] serial: max310x: unregister uart driver in case of failure and abort [ Upstream commit 3890e3dea315f1a257d1b940a2a4e2fa16a7b095 ] The macro "spi_register_driver" invokes the function "__spi_register_driver()" which has a return type of int and can fail, returning a negative value in such a case. This is currently ignored and the init() function yields success even if the spi driver failed to register. Fix this by collecting the return value of "__spi_register_driver()" and also unregister the uart driver in case of failure. Cc: Jiri Slaby Signed-off-by: Atul Gopinathan Link: https://lore.kernel.org/r/20210503115736.2104747-12-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/max310x.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index f60b7b86d0991e..5bf8dd6198bbd3 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1527,10 +1527,12 @@ static int __init max310x_uart_init(void) return ret; #ifdef CONFIG_SPI_MASTER - spi_register_driver(&max310x_spi_driver); + ret = spi_register_driver(&max310x_spi_driver); + if (ret) + uart_unregister_driver(&max310x_uart); #endif - return 0; + return ret; } module_init(max310x_uart_init); From d55ce9f23dae3fe02c291f0dadf62551cf7f58fa Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 7 Oct 2020 11:46:34 +0300 Subject: [PATCH 385/407] serial: max310x: Make use of device properties Device property API allows to gather device resources from different sources, such as ACPI. Convert the drivers to unleash the power of device property API. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20201007084635.594991-1-andy.shevchenko@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 5bf8dd6198bbd3..138e938aca7368 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -267,7 +267,7 @@ struct max310x_one { container_of(_port, struct max310x_one, port) struct max310x_port { - struct max310x_devtype *devtype; + const struct max310x_devtype *devtype; struct regmap *regmap; struct clk *clk; #ifdef CONFIG_GPIOLIB @@ -1250,7 +1250,7 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, } #endif -static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, +static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype, struct regmap *regmap, int irq) { int i, ret, fmin, fmax, freq, uartclk; @@ -1459,7 +1459,7 @@ static struct regmap_config regcfg = { #ifdef CONFIG_SPI_MASTER static int max310x_spi_probe(struct spi_device *spi) { - struct max310x_devtype *devtype; + const struct max310x_devtype *devtype; struct regmap *regmap; int ret; @@ -1471,18 +1471,9 @@ static int max310x_spi_probe(struct spi_device *spi) if (ret) return ret; - if (spi->dev.of_node) { - const struct of_device_id *of_id = - of_match_device(max310x_dt_ids, &spi->dev); - if (!of_id) - return -ENODEV; - - devtype = (struct max310x_devtype *)of_id->data; - } else { - const struct spi_device_id *id_entry = spi_get_device_id(spi); - - devtype = (struct max310x_devtype *)id_entry->driver_data; - } + devtype = device_get_match_data(&spi->dev); + if (!devtype) + devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data; regcfg.max_register = devtype->nr * 0x20 - 1; regmap = devm_regmap_init_spi(spi, ®cfg); @@ -1507,7 +1498,7 @@ MODULE_DEVICE_TABLE(spi, max310x_id_table); static struct spi_driver max310x_spi_driver = { .driver = { .name = MAX310X_NAME, - .of_match_table = of_match_ptr(max310x_dt_ids), + .of_match_table = max310x_dt_ids, .pm = &max310x_pm_ops, }, .probe = max310x_spi_probe, From cadb5747a7d9fbd5d4287911d9ad1e7bd96fc3fc Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Wed, 11 May 2022 10:22:21 +0300 Subject: [PATCH 386/407] serial: max310x: use regmap methods for SPI batch operations The SPI batch read/write operations can be implemented as simple regmap raw read and write, which will also try to do a gather write just as it is done here. Use the regmap raw read and write methods. Signed-off-by: Cosmin Tanislav --- drivers/tty/serial/max310x.c | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 138e938aca7368..39cf647c17bf9b 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -259,8 +259,6 @@ struct max310x_one { struct work_struct md_work; struct work_struct rs_work; - u8 wr_header; - u8 rd_header; u8 rx_buf[MAX310X_FIFO_SIZE]; }; #define to_max310x_port(_port) \ @@ -623,32 +621,18 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len) { - struct max310x_one *one = to_max310x_port(port); - struct spi_transfer xfer[] = { - { - .tx_buf = &one->wr_header, - .len = sizeof(one->wr_header), - }, { - .tx_buf = txbuf, - .len = len, - } - }; - spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); + struct max310x_port *s = dev_get_drvdata(port->dev); + u8 reg = port->iobase + MAX310X_THR_REG; + + regmap_raw_write(s->regmap, reg, txbuf, len); } static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len) { - struct max310x_one *one = to_max310x_port(port); - struct spi_transfer xfer[] = { - { - .tx_buf = &one->rd_header, - .len = sizeof(one->rd_header), - }, { - .rx_buf = rxbuf, - .len = len, - } - }; - spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); + struct max310x_port *s = dev_get_drvdata(port->dev); + u8 reg = port->iobase + MAX310X_RHR_REG; + + regmap_raw_read(s->regmap, reg, rxbuf, len); } static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) @@ -1361,10 +1345,6 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty INIT_WORK(&s->p[i].md_work, max310x_md_proc); /* Initialize queue for changing RS485 mode */ INIT_WORK(&s->p[i].rs_work, max310x_rs_proc); - /* Initialize SPI-transfer buffers */ - s->p[i].wr_header = (s->p[i].port.iobase + MAX310X_THR_REG) | - MAX310X_WRITE_BIT; - s->p[i].rd_header = (s->p[i].port.iobase + MAX310X_RHR_REG); /* Register port */ ret = uart_add_one_port(&max310x_uart, &s->p[i].port); From b5bee70170cc2d6aeeb6c65b4baf70fbc203f2d3 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 16 May 2022 20:54:39 +0300 Subject: [PATCH 387/407] serial: max310x: use a separate regmap for each port The driver currently does manual register manipulation in multiple places to talk to a specific UART port. In order to talk to a specific UART port over SPI, the bits U1 and U0 of the register address can be set, as explained in the Command byte configuration section of the datasheet. Make this more elegant by creating regmaps for each UART port and setting the read_flag_mask and write_flag_mask accordingly. All communcations regarding global registers are done on UART port 0, so replace the global regmap entirely with the port 0 regmap. Also, remove the 0x1f masks from reg_writeable(), reg_volatile() and reg_precious() methods, since setting the U1 and U0 bits of the register address happens inside the regmap core now. Signed-off-by: Cosmin Tanislav --- drivers/tty/serial/max310x.c | 68 +++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 39cf647c17bf9b..606489aead070a 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -258,6 +258,7 @@ struct max310x_one { struct work_struct tx_work; struct work_struct md_work; struct work_struct rs_work; + struct regmap *regmap; u8 rx_buf[MAX310X_FIFO_SIZE]; }; @@ -287,26 +288,26 @@ static DECLARE_BITMAP(max310x_lines, MAX310X_UART_NRMAX); static u8 max310x_port_read(struct uart_port *port, u8 reg) { - struct max310x_port *s = dev_get_drvdata(port->dev); + struct max310x_one *one = to_max310x_port(port); unsigned int val = 0; - regmap_read(s->regmap, port->iobase + reg, &val); + regmap_read(one->regmap, reg, &val); return val; } static void max310x_port_write(struct uart_port *port, u8 reg, u8 val) { - struct max310x_port *s = dev_get_drvdata(port->dev); + struct max310x_one *one = to_max310x_port(port); - regmap_write(s->regmap, port->iobase + reg, val); + regmap_write(one->regmap, reg, val); } static void max310x_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val) { - struct max310x_port *s = dev_get_drvdata(port->dev); + struct max310x_one *one = to_max310x_port(port); - regmap_update_bits(s->regmap, port->iobase + reg, mask, val); + regmap_update_bits(one->regmap, reg, mask, val); } static int max3107_detect(struct device *dev) @@ -445,7 +446,7 @@ static const struct max310x_devtype max14830_devtype = { static bool max310x_reg_writeable(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_IRQSTS_REG: case MAX310X_LSR_IRQSTS_REG: case MAX310X_SPCHR_IRQSTS_REG: @@ -462,7 +463,7 @@ static bool max310x_reg_writeable(struct device *dev, unsigned int reg) static bool max310x_reg_volatile(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_RHR_REG: case MAX310X_IRQSTS_REG: case MAX310X_LSR_IRQSTS_REG: @@ -484,7 +485,7 @@ static bool max310x_reg_volatile(struct device *dev, unsigned int reg) static bool max310x_reg_precious(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_RHR_REG: case MAX310X_IRQSTS_REG: case MAX310X_SPCHR_IRQSTS_REG: @@ -621,18 +622,16 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len) { - struct max310x_port *s = dev_get_drvdata(port->dev); - u8 reg = port->iobase + MAX310X_THR_REG; + struct max310x_one *one = to_max310x_port(port); - regmap_raw_write(s->regmap, reg, txbuf, len); + regmap_raw_write(one->regmap, MAX310X_THR_REG, txbuf, len); } static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len) { - struct max310x_port *s = dev_get_drvdata(port->dev); - u8 reg = port->iobase + MAX310X_RHR_REG; + struct max310x_one *one = to_max310x_port(port); - regmap_raw_read(s->regmap, reg, rxbuf, len); + regmap_raw_read(one->regmap, MAX310X_RHR_REG, rxbuf, len); } static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) @@ -1235,15 +1234,16 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, #endif static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype, - struct regmap *regmap, int irq) + struct regmap *regmaps[], int irq) { int i, ret, fmin, fmax, freq, uartclk; struct clk *clk_osc, *clk_xtal; struct max310x_port *s; bool xtal = false; - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + for (i = 0; i < devtype->nr; i++) + if (IS_ERR(regmaps[i])) + return PTR_ERR(regmaps[i]); /* Alloc port structure */ s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL); @@ -1282,7 +1282,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty goto out_clk; } - s->regmap = regmap; + s->regmap = regmaps[0]; s->devtype = devtype; dev_set_drvdata(dev, s); @@ -1292,22 +1292,18 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty goto out_clk; for (i = 0; i < devtype->nr; i++) { - unsigned int offs = i << 5; - /* Reset port */ - regmap_write(s->regmap, MAX310X_MODE2_REG + offs, + regmap_write(regmaps[i], MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT); /* Clear port reset */ - regmap_write(s->regmap, MAX310X_MODE2_REG + offs, 0); + regmap_write(regmaps[i], MAX310X_MODE2_REG, 0); /* Wait for port startup */ do { - regmap_read(s->regmap, - MAX310X_BRGDIVLSB_REG + offs, &ret); + regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &ret); } while (ret != 0x01); - regmap_write(s->regmap, MAX310X_MODE1_REG + offs, - devtype->mode1); + regmap_write(regmaps[i], MAX310X_MODE1_REG, devtype->mode1); } uartclk = max310x_set_ref_clk(dev, s, freq, xtal); @@ -1330,11 +1326,13 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty s->p[i].port.fifosize = MAX310X_FIFO_SIZE; s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; s->p[i].port.iotype = UPIO_PORT; - s->p[i].port.iobase = i * 0x20; + s->p[i].port.iobase = i; s->p[i].port.membase = (void __iomem *)~0; s->p[i].port.uartclk = uartclk; s->p[i].port.rs485_config = max310x_rs485_config; s->p[i].port.ops = &max310x_ops; + s->p[i].regmap = regmaps[i]; + /* Disable all interrupts */ max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0); /* Clear IRQ status register */ @@ -1431,6 +1429,7 @@ static struct regmap_config regcfg = { .val_bits = 8, .write_flag_mask = MAX310X_WRITE_BIT, .cache_type = REGCACHE_RBTREE, + .max_register = MAX310X_REG_1F, .writeable_reg = max310x_reg_writeable, .volatile_reg = max310x_reg_volatile, .precious_reg = max310x_reg_precious, @@ -1440,7 +1439,8 @@ static struct regmap_config regcfg = { static int max310x_spi_probe(struct spi_device *spi) { const struct max310x_devtype *devtype; - struct regmap *regmap; + struct regmap *regmaps[4]; + unsigned int i; int ret; /* Setup SPI bus */ @@ -1455,10 +1455,14 @@ static int max310x_spi_probe(struct spi_device *spi) if (!devtype) devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data; - regcfg.max_register = devtype->nr * 0x20 - 1; - regmap = devm_regmap_init_spi(spi, ®cfg); + for (i = 0; i < devtype->nr; i++) { + u8 port_mask = i * 0x20; + regcfg.read_flag_mask = port_mask; + regcfg.write_flag_mask = port_mask | MAX310X_WRITE_BIT; + regmaps[i] = devm_regmap_init_spi(spi, ®cfg); + } - return max310x_probe(&spi->dev, devtype, regmap, spi->irq); + return max310x_probe(&spi->dev, devtype, regmaps, spi->irq); } static int max310x_spi_remove(struct spi_device *spi) From a133c9a0a4bdd1afce7e4f70282da6a9e303a6ce Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Wed, 11 May 2022 10:22:20 +0300 Subject: [PATCH 388/407] serial: max310x: make accessing revision id interface-agnostic SPI can only use 5 address bits, since one bit is reserved for specifying R/W and 2 bits are used to specify the UART port. To access registers that have addresses past 0x1F, an extended register space can be enabled by writing to the GlobalCommand register (address 0x1F). I2C uses 8 address bits. The R/W bit is placed in the slave address, and so is the UART port. Because of this, registers that have addresses higher than 0x1F can be accessed normally. To access the RevID register, on SPI, 0xCE must be written to the 0x1F address to enable the extended register space, after which the RevID register is accessible at address 0x5. 0xCD must be written to the 0x1F address to disable the extended register space. On I2C, the RevID register is accessible at address 0x25. Create an interface config struct, and add a method for toggling the extended register space and a member for the RevId register address. Implement these for SPI. Signed-off-by: Cosmin Tanislav --- drivers/tty/serial/max310x.c | 40 +++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 606489aead070a..3c27a23a8b1893 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -72,7 +72,7 @@ #define MAX310X_GLOBALCMD_REG MAX310X_REG_1F /* Global Command (WO) */ /* Extended registers */ -#define MAX310X_REVID_EXTREG MAX310X_REG_05 /* Revision ID */ +#define MAX310X_SPI_REVID_EXTREG MAX310X_REG_05 /* Revision ID */ /* IRQ register bits */ #define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ @@ -245,6 +245,12 @@ #define MAX14830_BRGCFG_CLKDIS_BIT (1 << 6) /* Clock Disable */ #define MAX14830_REV_ID (0xb0) +struct max310x_if_cfg { + int (*extended_reg_enable)(struct device *dev, bool enable); + + unsigned int rev_id_reg; +}; + struct max310x_devtype { char name[9]; int nr; @@ -267,6 +273,7 @@ struct max310x_one { struct max310x_port { const struct max310x_devtype *devtype; + const struct max310x_if_cfg *if_cfg; struct regmap *regmap; struct clk *clk; #ifdef CONFIG_GPIOLIB @@ -356,13 +363,12 @@ static int max3109_detect(struct device *dev) unsigned int val = 0; int ret; - ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, - MAX310X_EXTREG_ENBL); + ret = s->if_cfg->extended_reg_enable(dev, true); if (ret) return ret; - regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val); - regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL); + regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val); + s->if_cfg->extended_reg_enable(dev, false); if (((val & MAX310x_REV_MASK) != MAX3109_REV_ID)) { dev_err(dev, "%s ID 0x%02x does not match\n", s->devtype->name, val); @@ -387,13 +393,12 @@ static int max14830_detect(struct device *dev) unsigned int val = 0; int ret; - ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, - MAX310X_EXTREG_ENBL); + ret = s->if_cfg->extended_reg_enable(dev, true); if (ret) return ret; - regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val); - regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL); + regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val); + s->if_cfg->extended_reg_enable(dev, false); if (((val & MAX310x_REV_MASK) != MAX14830_REV_ID)) { dev_err(dev, "%s ID 0x%02x does not match\n", s->devtype->name, val); @@ -1234,6 +1239,7 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, #endif static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype, + const struct max310x_if_cfg *if_cfg, struct regmap *regmaps[], int irq) { int i, ret, fmin, fmax, freq, uartclk; @@ -1284,6 +1290,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty s->regmap = regmaps[0]; s->devtype = devtype; + s->if_cfg = if_cfg; dev_set_drvdata(dev, s); /* Check device to ensure we are talking to what we expect */ @@ -1436,6 +1443,19 @@ static struct regmap_config regcfg = { }; #ifdef CONFIG_SPI_MASTER +static int max310x_spi_extended_reg_enable(struct device *dev, bool enable) +{ + struct max310x_port *s = dev_get_drvdata(dev); + + return regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, + enable ? MAX310X_EXTREG_ENBL : MAX310X_EXTREG_DSBL); +} + +static const struct max310x_if_cfg __maybe_unused max310x_spi_if_cfg = { + .extended_reg_enable = max310x_spi_extended_reg_enable, + .rev_id_reg = MAX310X_SPI_REVID_EXTREG, +}; + static int max310x_spi_probe(struct spi_device *spi) { const struct max310x_devtype *devtype; @@ -1462,7 +1482,7 @@ static int max310x_spi_probe(struct spi_device *spi) regmaps[i] = devm_regmap_init_spi(spi, ®cfg); } - return max310x_probe(&spi->dev, devtype, regmaps, spi->irq); + return max310x_probe(&spi->dev, devtype, &max310x_spi_if_cfg, regmaps, spi->irq); } static int max310x_spi_remove(struct spi_device *spi) From de610d988cb373a8462d955ed9e0be69902b3857 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Wed, 11 May 2022 10:22:21 +0300 Subject: [PATCH 389/407] serial: max310x: implement I2C support I2C implementation on this chip has a few key differences compared to SPI, as described in previous patches. * extended register space access needs no extra logic * slave address is used to select which UART to communicate with To accommodate these differences, add an I2C interface config, set the RevID register address and implement an empty method for setting the GlobalCommand register, since no special handling is needed for the extended register space. To handle the port-specific slave address, create an I2C dummy device for each port, except the base one (UART0), which is expected to be the one specified in firmware, and create a regmap for each I2C device. Add minimum and maximum slave addresses to each devtype for sanity checking. Also, use a separate regmap config with no write_flag_mask, since I2C has a R/W bit in its slave address, and set the max register to the address of the RevID register, since the extended register space needs no extra logic. Finally, add the I2C driver. Signed-off-by: Cosmin Tanislav --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/max310x.c | 134 ++++++++++++++++++++++++++++++++++- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 28f22e58639c6c..bd30ae9751bf50 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -343,6 +343,7 @@ config SERIAL_MAX310X depends on SPI_MASTER select SERIAL_CORE select REGMAP_SPI if SPI_MASTER + select REGMAP_I2C if I2C help This selects support for an advanced UART from Maxim (Dallas). Supported ICs are MAX3107, MAX3108, MAX3109, MAX14830. diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 3c27a23a8b1893..03a8284e21c245 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +74,7 @@ /* Extended registers */ #define MAX310X_SPI_REVID_EXTREG MAX310X_REG_05 /* Revision ID */ +#define MAX310X_I2C_REVID_EXTREG (0x25) /* Revision ID */ /* IRQ register bits */ #define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ @@ -252,6 +254,10 @@ struct max310x_if_cfg { }; struct max310x_devtype { + struct { + unsigned short min; + unsigned short max; + } slave_addr; char name[9]; int nr; u8 mode1; @@ -423,6 +429,10 @@ static const struct max310x_devtype max3107_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT, .detect = max3107_detect, .power = max310x_power, + .slave_addr = { + .min = 0x2c, + .max = 0x2f, + }, }; static const struct max310x_devtype max3108_devtype = { @@ -431,6 +441,10 @@ static const struct max310x_devtype max3108_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .detect = max3108_detect, .power = max310x_power, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static const struct max310x_devtype max3109_devtype = { @@ -439,6 +453,10 @@ static const struct max310x_devtype max3109_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .detect = max3109_detect, .power = max310x_power, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static const struct max310x_devtype max14830_devtype = { @@ -447,6 +465,10 @@ static const struct max310x_devtype max14830_devtype = { .mode1 = MAX310X_MODE1_IRQSEL_BIT, .detect = max14830_detect, .power = max14830_power, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static bool max310x_reg_writeable(struct device *dev, unsigned int reg) @@ -1511,6 +1533,96 @@ static struct spi_driver max310x_spi_driver = { }; #endif +#ifdef CONFIG_I2C +static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable) +{ + return 0; +} + +static struct regmap_config regcfg_i2c = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .writeable_reg = max310x_reg_writeable, + .volatile_reg = max310x_reg_volatile, + .precious_reg = max310x_reg_precious, + .max_register = MAX310X_I2C_REVID_EXTREG, +}; + +static const struct max310x_if_cfg max310x_i2c_if_cfg = { + .extended_reg_enable = max310x_i2c_extended_reg_enable, + .rev_id_reg = MAX310X_I2C_REVID_EXTREG, +}; + +static unsigned short max310x_i2c_slave_addr(unsigned short addr, + unsigned int nr) +{ + /* + * For MAX14830 and MAX3109, the slave address depends on what the + * A0 and A1 pins are tied to. + * See Table I2C Address Map of the datasheet. + * Based on that table, the following formulas were determined. + * UART1 - UART0 = 0x10 + * UART2 - UART1 = 0x20 + 0x10 + * UART3 - UART2 = 0x10 + */ + + addr -= nr * 0x10; + + if (nr >= 2) + addr -= 0x20; + + return addr; +} + +static int max310x_i2c_probe(struct i2c_client *client) +{ + const struct max310x_devtype *devtype = + device_get_match_data(&client->dev); + struct i2c_client *port_client; + struct regmap *regmaps[4]; + unsigned int i; + u8 port_addr; + + if (client->addr < devtype->slave_addr.min || + client->addr > devtype->slave_addr.max) + return dev_err_probe(&client->dev, -EINVAL, + "Slave addr 0x%x outside of range [0x%x, 0x%x]\n", + client->addr, devtype->slave_addr.min, + devtype->slave_addr.max); + + regmaps[0] = devm_regmap_init_i2c(client, ®cfg_i2c); + + for (i = 1; i < devtype->nr; i++) { + port_addr = max310x_i2c_slave_addr(client->addr, i); + port_client = devm_i2c_new_dummy_device(&client->dev, + client->adapter, + port_addr); + + regmaps[i] = devm_regmap_init_i2c(port_client, ®cfg_i2c); + } + + return max310x_probe(&client->dev, devtype, &max310x_i2c_if_cfg, + regmaps, client->irq); +} + +static int max310x_i2c_remove(struct i2c_client *client) +{ + /* I2C client remove callback returns int before 5.15. */ + return max310x_remove(&client->dev); +} + +static struct i2c_driver max310x_i2c_driver = { + .driver = { + .name = MAX310X_NAME, + .of_match_table = max310x_dt_ids, + .pm = &max310x_pm_ops, + }, + .probe_new = max310x_i2c_probe, + .remove = max310x_i2c_remove, +}; +#endif + static int __init max310x_uart_init(void) { int ret; @@ -1524,15 +1636,35 @@ static int __init max310x_uart_init(void) #ifdef CONFIG_SPI_MASTER ret = spi_register_driver(&max310x_spi_driver); if (ret) - uart_unregister_driver(&max310x_uart); + goto err_spi_register; +#endif + +#ifdef CONFIG_I2C + ret = i2c_add_driver(&max310x_i2c_driver); + if (ret) + goto err_i2c_register; #endif + return 0; + +#ifdef CONFIG_I2C +err_i2c_register: + spi_unregister_driver(&max310x_spi_driver); +#endif + +err_spi_register: + uart_unregister_driver(&max310x_uart); + return ret; } module_init(max310x_uart_init); static void __exit max310x_uart_exit(void) { +#ifdef CONFIG_I2C + i2c_del_driver(&max310x_i2c_driver); +#endif + #ifdef CONFIG_SPI_MASTER spi_unregister_driver(&max310x_spi_driver); #endif From 3539755d3cec30559d5811fc7a3f338aa76a1317 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 8 Jul 2022 16:26:08 +0200 Subject: [PATCH 390/407] iio: adc: talise: Fix corner case in reference clock handling This fixes a corner case where 160MHz or 80MHz reference clock would return error. Include up and equal to 80MHz as supported scaled range. Signed-off-by: Michael Hennerich --- drivers/iio/adc/talise/talise.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/talise/talise.c b/drivers/iio/adc/talise/talise.c index c48689035e9e9a..75307364e3c2d9 100644 --- a/drivers/iio/adc/talise/talise.c +++ b/drivers/iio/adc/talise/talise.c @@ -2770,7 +2770,7 @@ uint32_t TALISE_initDigitalClocks(taliseDevice_t *device, taliseDigClocks_t *clo loopFilterR1C3 = 0xC5; loopFilterR3 = (vcoIndex <= 2 || (vcoIndex > 6 && vcoIndex <= 8) || vcoIndex == 14) ? 14 : 13 ; } - else if (scaledRefClk_kHz >= 69120 && scaledRefClk_kHz < 80000) + else if (scaledRefClk_kHz >= 69120 && scaledRefClk_kHz <= 80000) { /* scaledRefClkMhz = 76.8 MHz */ vcoCalOffset = (vcoIndex == 11 || (vcoIndex > 35 && vcoIndex <= 37) || (vcoIndex > 29 && vcoIndex <= 34)|| vcoIndex == 40 || vcoIndex == 44) ? 14 :(vcoIndex <= 10 || vcoIndex > 44) ? From eaf1feef60facd24b314bc1e71c86a8f059beffc Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 8 Jul 2022 16:28:05 +0200 Subject: [PATCH 391/407] iio: adc: adrv9009: Provide InitCal status upon error This provides some additional debug information. Signed-off-by: Michael Hennerich --- drivers/iio/adc/adrv9009.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/iio/adc/adrv9009.c b/drivers/iio/adc/adrv9009.c index ae1c28717097c8..42d981c0c69cec 100644 --- a/drivers/iio/adc/adrv9009.c +++ b/drivers/iio/adc/adrv9009.c @@ -6083,9 +6083,21 @@ static int adrv9009_jesd204_setup_stage5(struct jesd204_dev *jdev, } if ((ret != TALACT_NO_ACTION) || errorFlag) { + uint32_t calsSincePowerUp = 0, calsLastRun = 0, calsMinimum = 0; + uint8_t initErrCal = 0, initErrCode = 0; + dev_err(&phy->spi->dev, "%s:%d (ret %d): Init Cal errorFlag (0x%X)", __func__, __LINE__, ret, errorFlag); + + ret = TALISE_getInitCalStatus(phy->talDevice, &calsSincePowerUp, + &calsLastRun, &calsMinimum, &initErrCal, &initErrCode); + + dev_err(&phy->spi->dev, + "%s:%d (ret %d): Init Cal calsSincePowerUp (0x%X) calsLastRun (0x%X) calsMinimum (0x%X) initErrCal (0x%X) initErrCode (0x%X)\n", + __func__, __LINE__, ret, calsSincePowerUp, calsLastRun, + calsMinimum, initErrCal, initErrCode); + return -EFAULT; } From 6a679e3f32ba6a4d90a9cf8e71f9aa4de98cd3d9 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Wed, 15 Jun 2022 09:40:58 +0300 Subject: [PATCH 392/407] arch: arm: boot: dts: Remove unused usb-phy The "ulpi-phy" compatible string is a part of Xilinx's fix for the USB controller not being able to change the VBUS state commit 340f285d9322 ("usb: phy: Add platform driver support for ULPI phys") wich we are not using anymore. Signed-off-by: Sergiu Cuciurean --- arch/arm/boot/dts/zynq-coraz7s.dtsi | 9 --------- arch/arm/boot/dts/zynq-m2k.dtsi | 10 ---------- arch/arm/boot/dts/zynq-pluto-sdr.dtsi | 9 --------- arch/arm/boot/dts/zynq-zc702.dts | 9 --------- arch/arm/boot/dts/zynq-zc706.dts | 9 --------- arch/arm/boot/dts/zynq-zed.dts | 9 --------- 6 files changed, 55 deletions(-) diff --git a/arch/arm/boot/dts/zynq-coraz7s.dtsi b/arch/arm/boot/dts/zynq-coraz7s.dtsi index 7257bf30bfee48..b079648d2b07bc 100644 --- a/arch/arm/boot/dts/zynq-coraz7s.dtsi +++ b/arch/arm/boot/dts/zynq-coraz7s.dtsi @@ -28,14 +28,6 @@ stdout-path = "serial0:115200n8"; }; - usb_phy0: phy0@e0002000 { - compatible = "ulpi-phy"; - #phy-cells = <0>; - reg = <0xe0002000 0x1000>; - view-port = <0x0170>; - drv-vbus; - }; - fpga_axi: fpga-axi@0 { compatible = "simple-bus"; #address-cells = <0x1>; @@ -81,6 +73,5 @@ &usb0 { status = "okay"; dr_mode = "host"; - usb-phy = <&usb_phy0>; }; diff --git a/arch/arm/boot/dts/zynq-m2k.dtsi b/arch/arm/boot/dts/zynq-m2k.dtsi index e92c093501b905..b82bf5a256419b 100644 --- a/arch/arm/boot/dts/zynq-m2k.dtsi +++ b/arch/arm/boot/dts/zynq-m2k.dtsi @@ -19,15 +19,6 @@ chosen { stdout-path = "/amba@0/uart@E0001000"; }; - - usb_phy0: phy0 { - compatible = "ulpi-phy"; - #phy-cells = <0>; - reg = <0xe0002000 0x1000>; - view-port = <0x0170>; - drv-vbus; - }; - }; &cpu0 { @@ -55,7 +46,6 @@ xlnx,phy-reset-gpio = <&gpio0 52 0>; dr_mode = "otg"; status = "okay"; - usb-phy = <&usb_phy0>; }; &clkc { diff --git a/arch/arm/boot/dts/zynq-pluto-sdr.dtsi b/arch/arm/boot/dts/zynq-pluto-sdr.dtsi index cfb7cb3733403b..d8feecb8a059ea 100644 --- a/arch/arm/boot/dts/zynq-pluto-sdr.dtsi +++ b/arch/arm/boot/dts/zynq-pluto-sdr.dtsi @@ -30,14 +30,6 @@ }; }; - usb_phy0: phy0 { - compatible = "ulpi-phy"; - #phy-cells = <0>; - reg = <0xe0002000 0x1000>; - view-port = <0x0170>; - drv-vbus; - }; - }; &sdhci0 { @@ -53,7 +45,6 @@ xlnx,phy-reset-gpio = <&gpio0 52 0>; dr_mode = "otg"; status = "okay"; - usb-phy = <&usb_phy0>; }; &qspi { diff --git a/arch/arm/boot/dts/zynq-zc702.dts b/arch/arm/boot/dts/zynq-zc702.dts index b82747df3e2519..d2c4a5472cc44e 100644 --- a/arch/arm/boot/dts/zynq-zc702.dts +++ b/arch/arm/boot/dts/zynq-zc702.dts @@ -57,14 +57,6 @@ linux,default-trigger = "heartbeat"; }; }; - - usb_phy0: phy0@e0002000 { - compatible = "ulpi-phy"; - #phy-cells = <0>; - reg = <0xe0002000 0x1000>; - view-port = <0x0170>; - drv-vbus; - }; }; &amba { @@ -462,7 +454,6 @@ &usb0 { status = "okay"; dr_mode = "host"; - usb-phy = <&usb_phy0>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usb0_default>; }; diff --git a/arch/arm/boot/dts/zynq-zc706.dts b/arch/arm/boot/dts/zynq-zc706.dts index 5c9f14d4dd4686..1c7818b8d9fbaa 100644 --- a/arch/arm/boot/dts/zynq-zc706.dts +++ b/arch/arm/boot/dts/zynq-zc706.dts @@ -27,14 +27,6 @@ bootargs = ""; stdout-path = "serial0:115200n8"; }; - - usb_phy0: phy0@e0002000 { - compatible = "ulpi-phy"; - #phy-cells = <0>; - reg = <0xe0002000 0x1000>; - view-port = <0x0170>; - drv-vbus; - }; }; &clkc { @@ -360,7 +352,6 @@ &usb0 { status = "okay"; dr_mode = "host"; - usb-phy = <&usb_phy0>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usb0_default>; }; diff --git a/arch/arm/boot/dts/zynq-zed.dts b/arch/arm/boot/dts/zynq-zed.dts index 2d531a6ea2caf0..60f73cd2601b86 100644 --- a/arch/arm/boot/dts/zynq-zed.dts +++ b/arch/arm/boot/dts/zynq-zed.dts @@ -26,14 +26,6 @@ bootargs = ""; stdout-path = "serial0:115200n8"; }; - - usb_phy0: phy0@e0002000 { - compatible = "ulpi-phy"; - #phy-cells = <0>; - reg = <0xe0002000 0x1000>; - view-port = <0x0170>; - drv-vbus; - }; }; &clkc { @@ -101,5 +93,4 @@ &usb0 { status = "okay"; dr_mode = "host"; - usb-phy = <&usb_phy0>; }; From 5ae8640d0d24a25a90e78e67314f687544e2e110 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Wed, 15 Jun 2022 09:48:36 +0300 Subject: [PATCH 393/407] drivers: usb: chipidea: Let the PHY set VBUS In the PHY datasheet, the typical application for Host or OTG implies a regulator controlled by the PHY's CPEN port. This change removes the Xilinx's fix leftovers and sets VBUS in the correct way. Signed-off-by: Sergiu Cuciurean --- drivers/usb/chipidea/ci_hdrc_usb2.c | 1 + drivers/usb/chipidea/host.c | 6 +++--- drivers/usb/chipidea/otg_fsm.c | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c index efa677598795cf..49d8588c002062 100644 --- a/drivers/usb/chipidea/ci_hdrc_usb2.c +++ b/drivers/usb/chipidea/ci_hdrc_usb2.c @@ -30,6 +30,7 @@ static const struct ci_hdrc_platform_data ci_default_pdata = { static const struct ci_hdrc_platform_data ci_zynq_pdata = { .capoffset = DEF_CAPOFFSET, + .flags = CI_HDRC_PHY_VBUS_CONTROL, }; static const struct ci_hdrc_platform_data ci_zevio_pdata = { diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index b49edda341ea93..7b4d0f278e99b0 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -58,11 +58,11 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) } if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL && - ci->usb_phy && ci->usb_phy->set_vbus) { + ci->usb_phy) { if (enable) - ci->usb_phy->set_vbus(ci->usb_phy, 1); + ci->usb_phy->otg->set_vbus(ci->usb_phy->otg, 1); else - ci->usb_phy->set_vbus(ci->usb_phy, 0); + ci->usb_phy->otg->set_vbus(ci->usb_phy->otg, 0); } if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) { diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index ec02ea0ab20d1e..e35f2e3aed7f54 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -473,8 +473,8 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on) } if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL && - ci->usb_phy && ci->usb_phy->set_vbus) - ci->usb_phy->set_vbus(ci->usb_phy, 1); + ci->usb_phy) + ci->usb_phy->otg->set_vbus(ci->usb_phy->otg, 1); /* Disable data pulse irq */ hw_write_otgsc(ci, OTGSC_DPIE, 0); @@ -486,8 +486,8 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on) regulator_disable(ci->platdata->reg_vbus); if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL && - ci->usb_phy && ci->usb_phy->set_vbus) - ci->usb_phy->set_vbus(ci->usb_phy, 0); + ci->usb_phy) + ci->usb_phy->otg->set_vbus(ci->usb_phy->otg, 0); fsm->a_bus_drop = 1; fsm->a_bus_req = 0; From 0859fbf3f954cc71df3eacce24ada61a1700f22e Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Mon, 18 Apr 2022 22:04:42 +0300 Subject: [PATCH 394/407] include: linux: pwm.h: Rename offset Change the naming from offset to phase. Signed-off-by: Sergiu Cuciurean --- drivers/pwm/core.c | 2 +- include/linux/pwm.h | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index ea0a36876a9539..9541a2cbbfc478 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -584,7 +584,7 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) if (state->period == pwm->state.period && state->duty_cycle == pwm->state.duty_cycle && state->polarity == pwm->state.polarity && - state->offset == pwm->state.offset && + state->phase == pwm->state.phase && state->enabled == pwm->state.enabled) return 0; diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 09ed33a9fe481d..6e52de37805f4e 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -29,7 +29,7 @@ enum pwm_polarity { * struct pwm_args - board-dependent PWM arguments * @period: reference period * @polarity: reference polarity - * @offset: reference offset + * @phase: reference phase * * This structure describes board-dependent arguments attached to a PWM * device. These arguments are usually retrieved from the PWM lookup table or @@ -41,7 +41,7 @@ enum pwm_polarity { */ struct pwm_args { u64 period; - unsigned int offset; + unsigned int phase; enum pwm_polarity polarity; }; @@ -54,14 +54,14 @@ enum { * struct pwm_state - state of a PWM channel * @period: PWM period (in nanoseconds) * @duty_cycle: PWM duty cycle (in nanoseconds) - * @offset: PWM offset (in nanoseconds) + * @phase: PWM phase (in nanoseconds) * @polarity: PWM polarity * @enabled: PWM enabled status */ struct pwm_state { u64 period; u64 duty_cycle; - unsigned int offset; + unsigned int phase; enum pwm_polarity polarity; bool enabled; }; @@ -141,19 +141,19 @@ static inline u64 pwm_get_duty_cycle(const struct pwm_device *pwm) return state.duty_cycle; } -static inline void pwm_set_offset(struct pwm_device *pwm, unsigned int offset) +static inline void pwm_set_phase(struct pwm_device *pwm, unsigned int phase) { if (pwm) - pwm->state.offset = offset; + pwm->state.phase = phase; } -static inline unsigned int pwm_get_offset(const struct pwm_device *pwm) +static inline unsigned int pwm_get_phase(const struct pwm_device *pwm) { struct pwm_state state; pwm_get_state(pwm, &state); - return state.offset; + return state.phase; } static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm) @@ -202,7 +202,7 @@ static inline void pwm_init_state(const struct pwm_device *pwm, state->period = args.period; state->polarity = args.polarity; state->duty_cycle = 0; - state->offset = 0; + state->phase = 0; } /** @@ -329,7 +329,7 @@ struct pwm_chip { struct pwm_capture { unsigned int period; unsigned int duty_cycle; - unsigned int offset; + unsigned int phase; }; #if IS_ENABLED(CONFIG_PWM) From 8d99e3b356535dd8240709f4e9d2c54c4f5986a7 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Mon, 18 Apr 2022 22:05:59 +0300 Subject: [PATCH 395/407] drivers: pwm: axi-pwmgen: Rename offset Rename offset to phase. Signed-off-by: Sergiu Cuciurean --- drivers/pwm/pwm-axi-pwmgen.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/pwm/pwm-axi-pwmgen.c b/drivers/pwm/pwm-axi-pwmgen.c index 79d7a973e134ec..6b60468d657d9d 100644 --- a/drivers/pwm/pwm-axi-pwmgen.c +++ b/drivers/pwm/pwm-axi-pwmgen.c @@ -22,10 +22,10 @@ #define AXI_PWMGEN_REG_NPWM 0x14 #define AXI_PWMGEN_CH_PERIOD_BASE 0x40 #define AXI_PWMGEN_CH_DUTY_BASE 0x44 -#define AXI_PWMGEN_CH_OFFSET_BASE 0x48 +#define AXI_PWMGEN_CH_PHASE_BASE 0x48 #define AXI_PWMGEN_CHX_PERIOD(ch) (AXI_PWMGEN_CH_PERIOD_BASE + (12 * (ch))) #define AXI_PWMGEN_CHX_DUTY(ch) (AXI_PWMGEN_CH_DUTY_BASE + (12 * (ch))) -#define AXI_PWMGEN_CHX_OFFSET(ch) (AXI_PWMGEN_CH_OFFSET_BASE + (12 * (ch))) +#define AXI_PWMGEN_CHX_PHASE(ch) (AXI_PWMGEN_CH_PHASE_BASE + (12 * (ch))) #define AXI_PWMGEN_TEST_DATA 0x5A0F0081 #define AXI_PWMGEN_LOAD_CONIG BIT(1) #define AXI_PWMGEN_RESET BIT(0) @@ -71,7 +71,7 @@ static inline struct axi_pwmgen *to_axi_pwmgen(struct pwm_chip *chip) static int axi_pwmgen_apply(struct pwm_chip *chip, struct pwm_device *device, const struct pwm_state *state) { - unsigned long clk_rate, period_cnt, duty_cnt, offset_cnt; + unsigned long clk_rate, period_cnt, duty_cnt, phase_cnt; u64 tmp; unsigned int ch = device->hwpwm; struct axi_pwmgen *pwm; @@ -90,9 +90,9 @@ static int axi_pwmgen_apply(struct pwm_chip *chip, struct pwm_device *device, duty_cnt = DIV_ROUND_UP_ULL(tmp, NSEC_PER_SEC); axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_DUTY(ch), duty_cnt); - tmp = (u64)clk_rate * state->offset; - offset_cnt = DIV_ROUND_UP_ULL(tmp, NSEC_PER_SEC); - axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_OFFSET(ch), state->offset ? offset_cnt : 0); + tmp = (u64)clk_rate * state->phase; + phase_cnt = DIV_ROUND_UP_ULL(tmp, NSEC_PER_SEC); + axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_PHASE(ch), state->phase ? phase_cnt : 0); /* Apply the new config */ axi_pwmgen_write(pwm, AXI_PWMGEN_REG_CONFIG, AXI_PWMGEN_LOAD_CONIG); @@ -157,7 +157,7 @@ static int axi_pwmgen_setup(struct pwm_chip *chip) for (idx = 0; idx < pwm->chip.npwm; idx++) { axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_PERIOD(idx), 0); axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_DUTY(idx), 0); - axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_OFFSET(idx), 0); + axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_PHASE(idx), 0); } /* Enable the core */ From 2a1b16e2639a2522cbc90c4bf7e8aaf0f00cc12f Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Tue, 22 Mar 2022 11:32:19 +0200 Subject: [PATCH 396/407] pwm: Convert period and duty cycle to u64 With the changes from commit a9d887dc1c60 ("pwm: Convert period and duty cycle to u64"), the pwm_capture members were left unmodified. This commit adds the missing changes. Signed-off-by: Sergiu Cuciurean --- drivers/pwm/sysfs.c | 2 +- include/linux/pwm.h | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index 9903c3a7ecedc8..15a07bf6e65b31 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -212,7 +212,7 @@ static ssize_t capture_show(struct device *child, if (ret) return ret; - return sprintf(buf, "%u %u\n", result.period, result.duty_cycle); + return sprintf(buf, "%llu %llu\n", result.period, result.duty_cycle); } static DEVICE_ATTR_RW(period); diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 6e52de37805f4e..5a666e245c26d6 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -327,8 +327,8 @@ struct pwm_chip { * @duty_cycle: duty cycle of the PWM signal (in nanoseconds) */ struct pwm_capture { - unsigned int period; - unsigned int duty_cycle; + u64 period; + u64 duty_cycle; unsigned int phase; }; @@ -347,8 +347,8 @@ int pwm_adjust_config(struct pwm_device *pwm); * * Returns: 0 on success or a negative error code on failure. */ -static inline int pwm_config(struct pwm_device *pwm, int duty_ns, - int period_ns) +static inline int pwm_config(struct pwm_device *pwm, u64 duty_ns, + u64 period_ns) { struct pwm_state state; @@ -457,8 +457,8 @@ static inline int pwm_adjust_config(struct pwm_device *pwm) return -ENOTSUPP; } -static inline int pwm_config(struct pwm_device *pwm, int duty_ns, - int period_ns) +static inline int pwm_config(struct pwm_device *pwm, u64 duty_ns, + u64 period_ns) { return -EINVAL; } From 53239d5626c906917634f961facd4fbf14ecf060 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Mon, 18 Apr 2022 22:11:31 +0300 Subject: [PATCH 397/407] include: linux: pwm: Convert phase to u64 This change is a follow-up to commit 4fa760fa62a9 ("pwm: Convert period and duty cycle to u64"), converting the remaining parameters to u64. Signed-off-by: Sergiu Cuciurean --- include/linux/pwm.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 5a666e245c26d6..75ba87ca2b8d31 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -41,7 +41,7 @@ enum pwm_polarity { */ struct pwm_args { u64 period; - unsigned int phase; + u64 phase; enum pwm_polarity polarity; }; @@ -61,7 +61,7 @@ enum { struct pwm_state { u64 period; u64 duty_cycle; - unsigned int phase; + u64 phase; enum pwm_polarity polarity; bool enabled; }; @@ -141,13 +141,13 @@ static inline u64 pwm_get_duty_cycle(const struct pwm_device *pwm) return state.duty_cycle; } -static inline void pwm_set_phase(struct pwm_device *pwm, unsigned int phase) +static inline void pwm_set_phase(struct pwm_device *pwm, u64 phase) { if (pwm) pwm->state.phase = phase; } -static inline unsigned int pwm_get_phase(const struct pwm_device *pwm) +static inline u64 pwm_get_phase(const struct pwm_device *pwm) { struct pwm_state state; @@ -329,7 +329,7 @@ struct pwm_chip { struct pwm_capture { u64 period; u64 duty_cycle; - unsigned int phase; + u64 phase; }; #if IS_ENABLED(CONFIG_PWM) From a349b3967caa12397ff38eaafbeefcb2f6e90a0b Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Tue, 22 Mar 2022 14:56:03 +0200 Subject: [PATCH 398/407] drivers: pwm: sysfs: Add phase sysfs Add sysfs interface for PWM phase. Signed-off-by: Sergiu Cuciurean --- drivers/pwm/core.c | 1 + drivers/pwm/sysfs.c | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 9541a2cbbfc478..0ebc97d74e23ec 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -1287,6 +1287,7 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) seq_printf(s, " period: %llu ns", state.period); seq_printf(s, " duty: %llu ns", state.duty_cycle); + seq_printf(s, " phase: %llu ns", state.phase); seq_printf(s, " polarity: %s", state.polarity ? "inverse" : "normal"); diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index 15a07bf6e65b31..d056cb7c6c5cdf 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -103,6 +103,41 @@ static ssize_t duty_cycle_store(struct device *child, return ret ? : size; } +static ssize_t phase_show(struct device *child, + struct device_attribute *attr, + char *buf) +{ + const struct pwm_device *pwm = child_to_pwm_device(child); + struct pwm_state state; + + pwm_get_state(pwm, &state); + + return sprintf(buf, "%llu\n", state.phase); +} + +static ssize_t phase_store(struct device *child, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct pwm_export *export = child_to_pwm_export(child); + struct pwm_device *pwm = export->pwm; + struct pwm_state state; + u64 val; + int ret; + + ret = kstrtou64(buf, 0, &val); + if (ret) + return ret; + + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.phase = val; + ret = pwm_apply_state(pwm, &state); + mutex_unlock(&export->lock); + + return ret ? : size; +} + static ssize_t enable_show(struct device *child, struct device_attribute *attr, char *buf) @@ -212,11 +247,13 @@ static ssize_t capture_show(struct device *child, if (ret) return ret; - return sprintf(buf, "%llu %llu\n", result.period, result.duty_cycle); + return sprintf(buf, "%llu %llu %llu\n", result.period, + result.duty_cycle, result.phase); } static DEVICE_ATTR_RW(period); static DEVICE_ATTR_RW(duty_cycle); +static DEVICE_ATTR_RW(phase); static DEVICE_ATTR_RW(enable); static DEVICE_ATTR_RW(polarity); static DEVICE_ATTR_RO(capture); @@ -224,6 +261,7 @@ static DEVICE_ATTR_RO(capture); static struct attribute *pwm_attrs[] = { &dev_attr_period.attr, &dev_attr_duty_cycle.attr, + &dev_attr_phase.attr, &dev_attr_enable.attr, &dev_attr_polarity.attr, &dev_attr_capture.attr, From d6dd33dad405ebd21bc00ba908cd9db2c1613c6a Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Mon, 18 Apr 2022 22:26:05 +0300 Subject: [PATCH 399/407] Documentation: pwm: Add phase documentation Add documentation for the PWM signal phase. Signed-off-by: Sergiu Cuciurean --- Documentation/ABI/testing/sysfs-class-pwm | 7 +++++++ Documentation/driver-api/pwm.rst | 8 ++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-pwm b/Documentation/ABI/testing/sysfs-class-pwm index c20e61354561db..ece8e9c666c334 100644 --- a/Documentation/ABI/testing/sysfs-class-pwm +++ b/Documentation/ABI/testing/sysfs-class-pwm @@ -86,3 +86,10 @@ Description: Capture information about a PWM signal. The output format is a pair unsigned integers (period and duty cycle), separated by a single space. + +What: /sys/class/pwm/pwmchipN/pwmX/phase +Date: Apr 2022 +KernelVersion: 5.10 +Contact: Sergiu Cuciurean +Description: + Sets the PWM signal phase in nanoseconds. diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst index ab62f1bb0366e7..09a11edde14366 100644 --- a/Documentation/driver-api/pwm.rst +++ b/Documentation/driver-api/pwm.rst @@ -46,8 +46,8 @@ After being requested, a PWM has to be configured using:: int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state); -This API controls both the PWM period/duty_cycle config and the -enable/disable state. +This API controls the PWM period, duty_cycle and phase config together with +the enable/disable state. The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers around pwm_apply_state() and should not be used if the user wants to change @@ -102,6 +102,10 @@ channel that was exported. The following properties will then be available: The active time of the PWM signal (read/write). Value is in nanoseconds and must be less than the period. + phase + The phase difference between the actual PWM signal and the reference one. + The value is expressed in nanoseconds and must be lower than period. + polarity Changes the polarity of the PWM signal (read/write). Writes to this property only work if the PWM chip supports changing From 6dda68a3579578eb2666fa22965cdd6f20705602 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Mon, 18 Apr 2022 22:27:28 +0300 Subject: [PATCH 400/407] include: linux: pwm.h: Fix pwm_apply_args This commit appends the phase specification to pwm_apply_args(). Fixes: b2c4ca6bf594 ("drivers: pwm: core: Add offset support"). Signed-off-by: Sergiu Cuciurean --- include/linux/pwm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 75ba87ca2b8d31..de24486410be75 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -581,6 +581,7 @@ static inline void pwm_apply_args(struct pwm_device *pwm) state.enabled = false; state.polarity = pwm->args.polarity; state.period = pwm->args.period; + state.phase = pwm->args.phase; pwm_apply_state(pwm, &state); } From 36b81df9d2ac6631a23b755bd7018319ec30d08c Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Tue, 22 Mar 2022 15:05:11 +0200 Subject: [PATCH 401/407] drivers: pwm: core: Add PWM time unit This commit adds a new member to the pwm_state structure representing the time unit used to express the other arguments. This change increases the granularity of the PWM arguments, giving a wide range of inputs starting from 1 picosecond. Signed-off-by: Sergiu Cuciurean --- drivers/pwm/core.c | 24 ++++++++++++++--- drivers/pwm/sysfs.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/pwm.h | 54 ++++++++++++++++++++++++++++++++++--- 3 files changed, 136 insertions(+), 7 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 0ebc97d74e23ec..182ad32830cdec 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -585,7 +585,8 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) state->duty_cycle == pwm->state.duty_cycle && state->polarity == pwm->state.polarity && state->phase == pwm->state.phase && - state->enabled == pwm->state.enabled) + state->enabled == pwm->state.enabled && + state->time_unit == pwm->state.time_unit) return 0; if (chip->ops->apply) { @@ -712,6 +713,7 @@ int pwm_adjust_config(struct pwm_device *pwm) state.duty_cycle = 0; state.period = pargs.period; state.polarity = pargs.polarity; + state.time_unit = pargs.time_unit; return pwm_apply_state(pwm, &state); } @@ -1267,6 +1269,15 @@ void devm_pwm_put(struct device *dev, struct pwm_device *pwm) EXPORT_SYMBOL_GPL(devm_pwm_put); #ifdef CONFIG_DEBUG_FS + +const char *pwm_time_unit_strings[] = { + [PWM_UNIT_SEC] = "s", + [PWM_UNIT_MSEC] = "ms", + [PWM_UNIT_USEC] = "us", + [PWM_UNIT_NSEC] = "ns", + [PWM_UNIT_PSEC] = "ps", +}; + static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) { unsigned int i; @@ -1276,6 +1287,8 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) struct pwm_state state; pwm_get_state(pwm, &state); + if (!state.time_unit) + state.time_unit = PWM_UNIT_NSEC; seq_printf(s, " pwm-%-3d (%-20.20s):", i, pwm->label); @@ -1285,9 +1298,12 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) if (state.enabled) seq_puts(s, " enabled"); - seq_printf(s, " period: %llu ns", state.period); - seq_printf(s, " duty: %llu ns", state.duty_cycle); - seq_printf(s, " phase: %llu ns", state.phase); + seq_printf(s, " period: %llu %s", state.period, + pwm_time_unit_strings[state.time_unit]); + seq_printf(s, " duty: %llu %s", state.duty_cycle, + pwm_time_unit_strings[state.time_unit]); + seq_printf(s, " phase: %llu %s", state.phase, + pwm_time_unit_strings[state.time_unit]); seq_printf(s, " polarity: %s", state.polarity ? "inverse" : "normal"); diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index d056cb7c6c5cdf..6d720ccee7fadc 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -235,6 +235,69 @@ static ssize_t polarity_store(struct device *child, return ret ? : size; } +static ssize_t time_unit_show(struct device *child, + struct device_attribute *attr, + char *buf) +{ + const struct pwm_device *pwm = child_to_pwm_device(child); + const char *unit = "unknown"; + struct pwm_state state; + + pwm_get_state(pwm, &state); + + switch (state.time_unit) { + case PWM_UNIT_SEC: + unit = "second"; + break; + case PWM_UNIT_MSEC: + unit = "milisecond"; + break; + case PWM_UNIT_USEC: + unit = "microsecond"; + break; + case PWM_UNIT_NSEC: + unit = "nanosecond"; + break; + case PWM_UNIT_PSEC: + unit = "picosecond"; + break; + } + + return sprintf(buf, "%s\n", unit); +} + +static ssize_t time_unit_store(struct device *child, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct pwm_export *export = child_to_pwm_export(child); + struct pwm_device *pwm = export->pwm; + enum pwm_time_unit unit; + struct pwm_state state; + int ret; + + if (sysfs_streq(buf, "second")) + unit = PWM_UNIT_SEC; + else if (sysfs_streq(buf, "milisecond")) + unit = PWM_UNIT_MSEC; + else if (sysfs_streq(buf, "microsecond")) + unit = PWM_UNIT_USEC; + else if (sysfs_streq(buf, "nanosecond")) + unit = PWM_UNIT_NSEC; + else if (sysfs_streq(buf, "picosecond")) + unit = PWM_UNIT_PSEC; + else + return -EINVAL; + + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.time_unit = unit; + ret = pwm_apply_state(pwm, &state); + mutex_unlock(&export->lock); + + return ret ? : size; +} + static ssize_t capture_show(struct device *child, struct device_attribute *attr, char *buf) @@ -256,6 +319,7 @@ static DEVICE_ATTR_RW(duty_cycle); static DEVICE_ATTR_RW(phase); static DEVICE_ATTR_RW(enable); static DEVICE_ATTR_RW(polarity); +static DEVICE_ATTR_RW(time_unit); static DEVICE_ATTR_RO(capture); static struct attribute *pwm_attrs[] = { @@ -264,6 +328,7 @@ static struct attribute *pwm_attrs[] = { &dev_attr_phase.attr, &dev_attr_enable.attr, &dev_attr_polarity.attr, + &dev_attr_time_unit.attr, &dev_attr_capture.attr, NULL }; diff --git a/include/linux/pwm.h b/include/linux/pwm.h index de24486410be75..12afcb7465ee50 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -11,6 +11,23 @@ struct seq_file; struct pwm_chip; +/** + * enum pwm_unit - the time unit in wich the pwm arguments are expressed. + * @PWM_UNIT_SEC: the pwm_args members are specified in seconds + * @PWM_UNIT_MSEC: the pwm_args members are specified in miliseconds + * @PWM_UNIT_USEC: the pwm_args members are specified in microseconds + * @PWM_UNIT_NSEC: the pwm_args members are specified in nanoseconds + * @PWM_UNIT_PSEC: the pwm_args members are specified in picoseconds + */ + +enum pwm_time_unit { + PWM_UNIT_SEC = 1, + PWM_UNIT_MSEC, + PWM_UNIT_USEC, + PWM_UNIT_NSEC, + PWM_UNIT_PSEC, +}; + /** * enum pwm_polarity - polarity of a PWM signal * @PWM_POLARITY_NORMAL: a high signal for the duration of the duty- @@ -30,6 +47,7 @@ enum pwm_polarity { * @period: reference period * @polarity: reference polarity * @phase: reference phase + * @time_unit: refference time unit * * This structure describes board-dependent arguments attached to a PWM * device. These arguments are usually retrieved from the PWM lookup table or @@ -43,6 +61,7 @@ struct pwm_args { u64 period; u64 phase; enum pwm_polarity polarity; + enum pwm_time_unit time_unit; }; enum { @@ -52,10 +71,11 @@ enum { /* * struct pwm_state - state of a PWM channel - * @period: PWM period (in nanoseconds) - * @duty_cycle: PWM duty cycle (in nanoseconds) - * @phase: PWM phase (in nanoseconds) + * @period: PWM period (with the time unit expressed in ->time_unit) + * @duty_cycle: PWM duty cycle (with the time unit expressed in ->time_unit) + * @phase: PWM phase (with the time unit expressed in ->time_unit) * @polarity: PWM polarity + * @time_unit: PWM time unit * @enabled: PWM enabled status */ struct pwm_state { @@ -63,6 +83,7 @@ struct pwm_state { u64 duty_cycle; u64 phase; enum pwm_polarity polarity; + enum pwm_time_unit time_unit; bool enabled; }; @@ -156,6 +177,26 @@ static inline u64 pwm_get_phase(const struct pwm_device *pwm) return state.phase; } +static inline int pwm_set_time_unit(struct pwm_device *pwm, + enum pwm_time_unit time_unit) +{ + if (!pwm || time_unit < PWM_UNIT_SEC || time_unit > PWM_UNIT_PSEC) + return -EINVAL; + + pwm->state.time_unit = time_unit; + + return 0; +} + +static inline enum pwm_time_unit pwm_get_time_unit(const struct pwm_device *pwm) +{ + struct pwm_state state; + + pwm_get_state(pwm, &state); + + return state.time_unit; +} + static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm) { struct pwm_state state; @@ -187,6 +228,8 @@ static inline void pwm_get_args(const struct pwm_device *pwm, * ->duty_cycle value exceed the pwm_args->period one, which would trigger * an error if the user calls pwm_apply_state() without adjusting ->duty_cycle * first. + * ->time_unit is initially set to PWM_UNIT_NSEC to align all the previous + * drivers that presume the pwm_state arguments time unit is nanoseconds. */ static inline void pwm_init_state(const struct pwm_device *pwm, struct pwm_state *state) @@ -203,6 +246,8 @@ static inline void pwm_init_state(const struct pwm_device *pwm, state->polarity = args.polarity; state->duty_cycle = 0; state->phase = 0; + /* Set the default time unit to nsec ensuring backward compatibility */ + state->time_unit = PWM_UNIT_NSEC; } /** @@ -330,6 +375,7 @@ struct pwm_capture { u64 period; u64 duty_cycle; u64 phase; + enum pwm_time_unit time_unit; }; #if IS_ENABLED(CONFIG_PWM) @@ -364,6 +410,7 @@ static inline int pwm_config(struct pwm_device *pwm, u64 duty_ns, state.duty_cycle = duty_ns; state.period = period_ns; + state.time_unit = PWM_UNIT_NSEC; return pwm_apply_state(pwm, &state); } @@ -582,6 +629,7 @@ static inline void pwm_apply_args(struct pwm_device *pwm) state.polarity = pwm->args.polarity; state.period = pwm->args.period; state.phase = pwm->args.phase; + state.time_unit = pwm->args.time_unit; pwm_apply_state(pwm, &state); } From 469df667b780347a035b3145f5d0069662b3b4a7 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Mon, 18 Apr 2022 22:37:47 +0300 Subject: [PATCH 402/407] Documentation: driver-api: pwm.rst: Add time_unit Add the documentation for time_unit. Signed-off-by: Sergiu Cuciurean --- Documentation/driver-api/pwm.rst | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst index 09a11edde14366..462ba8778139d5 100644 --- a/Documentation/driver-api/pwm.rst +++ b/Documentation/driver-api/pwm.rst @@ -95,16 +95,18 @@ channel that was exported. The following properties will then be available: period The total period of the PWM signal (read/write). - Value is in nanoseconds and is the sum of the active and inactive - time of the PWM. + Value the sum of the active and inactive time of the PWM, using the + time_unit property as a measurment unit. duty_cycle The active time of the PWM signal (read/write). - Value is in nanoseconds and must be less than the period. + Value must be less than the period and uses the time_unit property as + a measurment unit. phase The phase difference between the actual PWM signal and the reference one. - The value is expressed in nanoseconds and must be lower than period. + The value must be lower than period and uses the time_unit property as a + measurment unit. polarity Changes the polarity of the PWM signal (read/write). @@ -112,6 +114,15 @@ channel that was exported. The following properties will then be available: the polarity. The polarity can only be changed if the PWM is not enabled. Value is the string "normal" or "inversed". + time_unit + The time unit used to measure the pwm period, duty_cycle and phase. + + - 1 - seconds + - 2 - miliseconds + - 3 - microseconds + - 4 - nanoseconds + - 5 - picoseconds + enable Enable/disable the PWM signal (read/write). From ed2e704646627fd7a5b4f8ce4178aac8d808b33c Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Tue, 22 Mar 2022 15:32:58 +0200 Subject: [PATCH 403/407] drivers: pwm: axi-pwmgen: Add time unit support Add time unit support for axi-pwmgen. Signed-off-by: Sergiu Cuciurean --- drivers/pwm/pwm-axi-pwmgen.c | 38 +++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/pwm/pwm-axi-pwmgen.c b/drivers/pwm/pwm-axi-pwmgen.c index 6b60468d657d9d..bcc5ff61021774 100644 --- a/drivers/pwm/pwm-axi-pwmgen.c +++ b/drivers/pwm/pwm-axi-pwmgen.c @@ -30,6 +30,16 @@ #define AXI_PWMGEN_LOAD_CONIG BIT(1) #define AXI_PWMGEN_RESET BIT(0) +#define AXI_PWMGEN_PSEC_PER_SEC 1000000000000ULL + +static const unsigned long long axi_pwmgen_scales[] = { + [PWM_UNIT_SEC] = 1000000000000ULL, + [PWM_UNIT_MSEC] = 1000000000ULL, + [PWM_UNIT_USEC] = 1000000ULL, + [PWM_UNIT_NSEC] = 1000ULL, + [PWM_UNIT_PSEC] = 1ULL, +}; + struct axi_pwmgen { struct pwm_chip chip; struct clk *clk; @@ -71,31 +81,31 @@ static inline struct axi_pwmgen *to_axi_pwmgen(struct pwm_chip *chip) static int axi_pwmgen_apply(struct pwm_chip *chip, struct pwm_device *device, const struct pwm_state *state) { - unsigned long clk_rate, period_cnt, duty_cnt, phase_cnt; - u64 tmp; + unsigned long long rate, clk_period_ps, target, cnt; unsigned int ch = device->hwpwm; struct axi_pwmgen *pwm; pwm = to_axi_pwmgen(chip); - clk_rate = clk_get_rate(pwm->clk); + rate = clk_get_rate(pwm->clk); + clk_period_ps = DIV_ROUND_CLOSEST_ULL(AXI_PWMGEN_PSEC_PER_SEC, rate); - tmp = (u64)clk_rate * state->period; - period_cnt = DIV_ROUND_UP_ULL(tmp, NSEC_PER_SEC); - pwm->ch_period[ch] = period_cnt; - /* The register is 0 based */ + target = state->period * axi_pwmgen_scales[state->time_unit]; + cnt = target ? DIV_ROUND_CLOSEST_ULL(target, clk_period_ps) : 0; + pwm->ch_period[ch] = cnt; axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_PERIOD(ch), - state->enabled ? (pwm->ch_period[ch] - 1) : 0); + state->enabled ? pwm->ch_period[ch] : 0); - tmp = (u64)clk_rate * state->duty_cycle; - duty_cnt = DIV_ROUND_UP_ULL(tmp, NSEC_PER_SEC); - axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_DUTY(ch), duty_cnt); + target = state->duty_cycle * axi_pwmgen_scales[state->time_unit]; + cnt = target ? DIV_ROUND_CLOSEST_ULL(target, clk_period_ps) : 0; + axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_DUTY(ch), cnt); - tmp = (u64)clk_rate * state->phase; - phase_cnt = DIV_ROUND_UP_ULL(tmp, NSEC_PER_SEC); - axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_PHASE(ch), state->phase ? phase_cnt : 0); + target = state->phase * axi_pwmgen_scales[state->time_unit]; + cnt = target ? DIV_ROUND_CLOSEST_ULL(target, clk_period_ps) : 0; + axi_pwmgen_write(pwm, AXI_PWMGEN_CHX_PHASE(ch), cnt); /* Apply the new config */ axi_pwmgen_write(pwm, AXI_PWMGEN_REG_CONFIG, AXI_PWMGEN_LOAD_CONIG); + device->state.time_unit = state->time_unit; return 0; } From 595250eb7bec25c7bdf61853ac582fe7d7696c2d Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Mon, 18 Apr 2022 22:53:30 +0300 Subject: [PATCH 404/407] Documentation: ABI: testing: pwm: Add time_unit Add documentation for PWM signal time_unit. Signed-off-by: Sergiu Cuciurean --- Documentation/ABI/testing/sysfs-class-pwm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-pwm b/Documentation/ABI/testing/sysfs-class-pwm index ece8e9c666c334..d5e5010f3ff664 100644 --- a/Documentation/ABI/testing/sysfs-class-pwm +++ b/Documentation/ABI/testing/sysfs-class-pwm @@ -93,3 +93,15 @@ KernelVersion: 5.10 Contact: Sergiu Cuciurean Description: Sets the PWM signal phase in nanoseconds. + +What: /sys/class/pwm/pwmchipN/pwmX/time_unit +Date: Apr 2022 +KernelVersion: 5.10 +Contact: Sergiu Cuciurean +Description: + Sets the PWM signal period, duty_cycle and phase time unit. + 1 is seconds + 2 is miliseconds + 3 is microseconds + 4 is nanoseconds + 5 is picoseconds From 3061864518489062acc37a4eb07f5acba3b64e9b Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Tue, 22 Mar 2022 15:38:44 +0200 Subject: [PATCH 405/407] drivers: pwm: axi-pwmgen: Add PWM ops Add capture() and get_state() ops. Signed-off-by: Sergiu Cuciurean --- drivers/pwm/pwm-axi-pwmgen.c | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/drivers/pwm/pwm-axi-pwmgen.c b/drivers/pwm/pwm-axi-pwmgen.c index bcc5ff61021774..6c4db893a4dcf4 100644 --- a/drivers/pwm/pwm-axi-pwmgen.c +++ b/drivers/pwm/pwm-axi-pwmgen.c @@ -110,6 +110,62 @@ static int axi_pwmgen_apply(struct pwm_chip *chip, struct pwm_device *device, return 0; } +static int axi_pwmgen_capture(struct pwm_chip *chip, struct pwm_device *device, + struct pwm_capture *capture, + unsigned long timeout __always_unused) +{ + struct axi_pwmgen *pwmgen = to_axi_pwmgen(chip); + unsigned long long rate, cnt, clk_period_ps; + unsigned int ch = device->hwpwm; + + rate = clk_get_rate(pwmgen->clk); + if (!rate) + return -EINVAL; + + clk_period_ps = DIV_ROUND_CLOSEST_ULL(AXI_PWMGEN_PSEC_PER_SEC, rate); + cnt = axi_pwmgen_read(pwmgen, AXI_PWMGEN_CHX_PERIOD(ch)); + cnt *= clk_period_ps; + if (cnt) + capture->period = DIV_ROUND_CLOSEST_ULL(cnt, + axi_pwmgen_scales[device->state.time_unit]); + else + capture->period = 0; + cnt = axi_pwmgen_read(pwmgen, AXI_PWMGEN_CHX_DUTY(ch)); + cnt *= clk_period_ps; + if (cnt) + capture->duty_cycle = DIV_ROUND_CLOSEST_ULL(cnt, + axi_pwmgen_scales[device->state.time_unit]); + else + capture->duty_cycle = 0; + cnt = axi_pwmgen_read(pwmgen, AXI_PWMGEN_CHX_PHASE(ch)); + cnt *= clk_period_ps; + if (cnt) + capture->phase = DIV_ROUND_CLOSEST_ULL(cnt, + axi_pwmgen_scales[device->state.time_unit]); + else + capture->phase = 0; + capture->time_unit = device->state.time_unit; + + return 0; +} + +static void axi_pwmgen_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct pwm_capture capture; + int ret; + + ret = axi_pwmgen_capture(chip, pwm, &capture, 0); + if (ret < 0) + return; + + state->enabled = state; + state->period = capture.period; + state->duty_cycle = capture.duty_cycle; + state->phase = capture.phase; + state->time_unit = capture.time_unit; +} + static void axi_pwmgen_disable(struct pwm_chip *chip, struct pwm_device *pwm) { unsigned int ch = pwm->hwpwm; @@ -134,6 +190,8 @@ static const struct pwm_ops axi_pwmgen_pwm_ops = { .apply = axi_pwmgen_apply, .disable = axi_pwmgen_disable, .enable = axi_pwmgen_enable, + .capture = axi_pwmgen_capture, + .get_state = axi_pwmgen_get_state, .owner = THIS_MODULE, }; From ccc632e1e8ef64bb7e20ca6d562f19eeb7445b8a Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 14 Jul 2022 10:04:00 +0200 Subject: [PATCH 406/407] iio: adc :ad9081: Dual link support for bist_prbs_error_counters_jrx This patch adds support for printing the error counters on the second link. In JRX dual link mode the results for the second link will be separated by an additional ':'. Signed-off-by: Michael Hennerich --- drivers/iio/adc/ad9081.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/iio/adc/ad9081.c b/drivers/iio/adc/ad9081.c index d2cb9bde61c53e..b106d2cb886adb 100644 --- a/drivers/iio/adc/ad9081.c +++ b/drivers/iio/adc/ad9081.c @@ -3514,6 +3514,24 @@ static ssize_t ad9081_debugfs_read(struct file *file, char __user *userbuf, prbs_rx_result.phy_prbs_pass); } } + + if (ad9081_link_is_dual(phy->jrx_link_tx)) { + len += snprintf(buf + len, sizeof(buf), ": "); + for (i = 0; i < phy->jrx_link_tx[1].jesd_param.jesd_l; i++) { + adi_ad9081_prbs_test_t prbs_rx_result; + + for (j = 0; j < 8; j++) + if (phy->jrx_link_tx[1].logiclane_mapping[j] == i) { + ret = adi_ad9081_jesd_rx_phy_prbs_test_result_get(&phy->ad9081, + j, &prbs_rx_result); + + len += snprintf(buf + len, sizeof(buf), "%u/%u ", + prbs_rx_result.phy_prbs_err_cnt, + prbs_rx_result.phy_prbs_pass); + } + } + } + mutex_unlock(&indio_dev->mlock); len += snprintf(buf + len, sizeof(buf), "\n"); break; From 53a180041a316da8c88eb27535c3087aaff87536 Mon Sep 17 00:00:00 2001 From: Bjoern Kerler Date: Tue, 19 Jul 2022 16:56:14 +0200 Subject: [PATCH 407/407] Add rf switch control --- arch/arm/boot/dts/zynq-ant-sdr.dtsi | 70 +++++++++++++++++++++++++---- arch/arm/configs/zynq_ant_defconfig | 3 +- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/zynq-ant-sdr.dtsi b/arch/arm/boot/dts/zynq-ant-sdr.dtsi index 4e2e6bca85b890..4ae57b1e9435af 100644 --- a/arch/arm/boot/dts/zynq-ant-sdr.dtsi +++ b/arch/arm/boot/dts/zynq-ant-sdr.dtsi @@ -6,9 +6,13 @@ * Licensed under the GPL-2. */ #include "zynq.dtsi" - +#include +#include #include +#define AD9361_EXT_BAND_CTL_SHORTHANDS +#include + / { model = "Analog Devices PlutoSDR Rev.A (Z7010/AD9363)"; memory { @@ -436,13 +440,61 @@ en_agc-gpios = <&gpio0 66 0>; reset-gpios = <&gpio0 67 0>; - VCRX1_1-gpios = <&gpio0 71 0>;/* RX1 3~6G */ - VCRX1_2-gpios = <&gpio0 72 0>;/* RX1 4.5M~3G */ - VCTX1_2-gpios = <&gpio0 73 0>;/* TX1 3~6G */ - VCTX1_1-gpios = <&gpio0 74 0>;/* TX1 4.5M~3G */ - VCRX2_1-gpios = <&gpio0 75 0>;/* RX2 4.5M~3G */ - VCRX2_2-gpios = <&gpio0 76 0>;/* RX2 3~6G */ - VCTX2_1-gpios = <&gpio0 77 0>;/* TX2 3~6G */ - VCTX2_2-gpios = <&gpio0 78 0>;/* TX2 4.5M~3G */ + adi,band-ctl-0-gpio = <&gpio0 71 0>;/* RX1 3~6G */ + adi,band-ctl-1-gpio = <&gpio0 72 0>;/* RX1 4.5M~3G */ + adi,band-ctl-2-gpio = <&gpio0 73 0>;/* TX1 3~6G */ + adi,band-ctl-3-gpio = <&gpio0 74 0>;/* TX1 4.5M~3G */ + adi,band-ctl-4-gpio = <&gpio0 75 0>;/* RX2 3~6G */ + adi,band-ctl-5-gpio = <&gpio0 76 0>;/* RX2 4.5M~3G */ + adi,band-ctl-6-gpio = <&gpio0 77 0>;/* TX2 3~6G */ + adi,band-ctl-7-gpio = <&gpio0 78 0>;/* TX2 4.5M~3G */ + + + ad9361_rx_ant_port_a: ad9361_rx_ant_port_a { + adi,rx-rf-port-input-select = <0>; /* (RX1A_N & RX1A_P) and (RX2A_N & RX2A_P) enabled; balanced */ + }; + + ad9361_rx_ant_port_b: ad9361_rx_ant_port_b { + adi,rx-rf-port-input-select = <1>; /* (RX1B_N & RX1B_P) and (RX2B_N & RX2B_P) enabled; balanced */ + }; + + ad9361_tx_ant_port_a: ad9361_tx_ant_port_a { + adi,tx-rf-port-input-select = <0>; /* TX1A, TX2A */ + }; + + ad9361_tx_ant_port_b: ad9361_tx_ant_port_b { + adi,tx-rf-port-input-select = <1>; /* TX1B, TX2B */ + }; + + + adi_rx_band_setting_0 { + adi,lo-freq-min = /bits/ 64 <0>; + adi,lo-freq-max = /bits/ 64 <3000000000>; + adi,gpio-settings = <0 1 _ _ 0 1 _ _>; + adi,band-ctl-post = <&ad9361_rx_ant_port_b 0>; + }; + + adi_rx_band_setting_1 { + adi,lo-freq-min = /bits/ 64 <3000000000>; + adi,lo-freq-max = /bits/ 64 <6000000000>; + adi,gpio-settings = <1 0 _ _ 1 0 _ _>; + adi,band-ctl-post = <&ad9361_rx_ant_port_a 0>; + }; + + adi_tx_band_setting_0 { + adi,lo-freq-min = /bits/ 64 <0>; + adi,lo-freq-max = /bits/ 64 <3000000000>; + adi,gpio-settings = <_ _ 0 1 _ _ 0 1>; + adi,band-ctl-post = <&ad9361_tx_ant_port_b 0>; + }; + + adi_tx_band_setting_1 { + adi,lo-freq-min = /bits/ 64 <3000000000>; + adi,lo-freq-max = /bits/ 64 <6000000000>; + + adi,gpio-settings = <_ _ 1 0 _ _ 1 0>; + adi,band-ctl-post = <&ad9361_tx_ant_port_a 0>; + }; }; }; + diff --git a/arch/arm/configs/zynq_ant_defconfig b/arch/arm/configs/zynq_ant_defconfig index ec4dc278c3c8cf..79bef8c8c9dc26 100644 --- a/arch/arm/configs/zynq_ant_defconfig +++ b/arch/arm/configs/zynq_ant_defconfig @@ -252,6 +252,7 @@ CONFIG_MEMORY=y CONFIG_IIO=y CONFIG_ADM1177=y CONFIG_AD9361=y +CONFIG_AD9361_EXT_BAND_CONTROL=y CONFIG_ADMC=y CONFIG_XILINX_XADC=y CONFIG_CF_AXI_DDS=y @@ -282,4 +283,4 @@ CONFIG_RCU_CPU_STALL_TIMEOUT=60 # CONFIG_FTRACE is not set CONFIG_DEBUG_LL=y CONFIG_DEBUG_ZYNQ_UART1=y -CONFIG_EARLY_PRINTK=y \ No newline at end of file +CONFIG_EARLY_PRINTK=y