Skip to content

Commit 5547b3a

Browse files
committed
iio: adc: adrv9002: support RX port switching
RX port switching is a feature where we can either manually switch between RXA and RXB or we can define a set of carrier ranges (one for RXA and another for RXB) and whenever the configured carrier falls in one range, the port configured for that range will be used. For automatic mode (where we define frequency ranges), one cannot configure a carrier that does not fall in any of the specified ranges. For manual mode, a new userspace interface is exposed so that one can select the desired port to use. Similar to the already existing TX interface (when available), the interface is in_voltageX_port_select in_voltageX_port_select_available and the available values are rx_a and rx_b. To enable Port Switching new DT properties are introduced: * adi,rx-port-switch - string property that can be "auto" or "manual"; * adi,min-carrier-port-a-hz * adi,max-carrier-port-a-hz * adi,min-carrier-port-b-hz * adi,max-carrier-port-b-hz The above 4 properties accept the full range of frequencies for carrier configuration. Note that in manual mode, the carrier properties are ignored and the full range will be used since we still need to provide the frequencies to the device driver API (for initial calibration purposes). Also to note that depending on the configured ranges, initial calibrations can take a lot of time to run (the wider the intervals, the worst). Therefore we need to increase the timeout to 120 seconds (yes, seconds!). Lastly, a small note was added for the initial calibrations userspace interface as it does not make much sense to run them again when port switching is enabled (because we do run them on all the frequencies that matter). Signed-off-by: Nuno Sá <nuno.sa@analog.com>
1 parent 7425432 commit 5547b3a

File tree

3 files changed

+266
-9
lines changed

3 files changed

+266
-9
lines changed

drivers/iio/adc/navassa/adrv9002.c

Lines changed: 188 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,11 @@
110110
/* Frequency hopping */
111111
#define ADRV9002_FH_TABLE_COL_SZ 7
112112

113-
#define ADRV9002_INIT_CALS_TIMEOUT_MS (60 * MILLI)
113+
#define ADRV9002_INIT_CALS_TIMEOUT_MS (120 * MILLI)
114+
115+
#define ADRV9002_PORT_SWITCH_IN_RANGE(port, carrier) ( \
116+
((carrier) >= (port)->minFreqPortB_Hz && (carrier) <= (port)->maxFreqPortB_Hz) || \
117+
((carrier) >= (port)->minFreqPortA_Hz && (carrier) <= (port)->maxFreqPortA_Hz))
114118

115119
/* IRQ Masks */
116120
#define ADRV9002_GP_MASK_RX_DP_RECEIVE_ERROR 0x08000000
@@ -704,6 +708,14 @@ static int adrv9002_phy_rerun_cals(struct adrv9002_rf_phy *phy,
704708
return adrv9002_phy_rerun_cals_setup(phy, port_mask, true);
705709
}
706710

711+
/*
712+
* !\Note that this interface does not make much sense with RX port switch enabled. The reason
713+
* is that when in auto mode, the calibrations will run for the range of configured carriers and
714+
* we cannot configure any frequency outside of that range. And for manual mode, we will calibrate
715+
* the full range of frequencies. Hence, in theory, re-running the calibrations should not bring
716+
* any additional value and can take a lot of time... However, it also does not harm so that we are
717+
* keeping the interface (for simplicity) but take care as it can really take a lot of time.
718+
*/
707719
static int adrv9002_init_cals_set(struct adrv9002_rf_phy *phy, const char *buf)
708720
{
709721
struct adi_adrv9001_InitCals cals = {0};
@@ -892,6 +904,27 @@ static int adrv9002_phy_lo_set(struct adrv9002_rf_phy *phy, struct adrv9002_chan
892904
if (ret)
893905
return ret;
894906

907+
if (c->port == ADI_RX && phy->port_switch.enable) {
908+
if (phy->port_switch.manualRxPortSwitch) {
909+
/*
910+
* Respect manual port selection in case we have it. The reason for doing
911+
* this is that adi_adrv9001_Radio_Carrier_Inspect() always returns RXA.
912+
*/
913+
lo_freq.manualRxport = chan_to_rx(c)->manual_port;
914+
} else if (!ADRV9002_PORT_SWITCH_IN_RANGE(&phy->port_switch, freq)) {
915+
/*
916+
* !note the API would also refuse to configure an out of range frequency
917+
* but the error message is not really helpful...
918+
*/
919+
dev_err(&phy->spi->dev,
920+
"RX%u Carrier(%llu) out of range for port switch: RXA[%llu %llu], RXB[%llu %llu]\n",
921+
c->idx + 1, freq, phy->port_switch.minFreqPortA_Hz,
922+
phy->port_switch.maxFreqPortA_Hz, phy->port_switch.minFreqPortB_Hz,
923+
phy->port_switch.maxFreqPortB_Hz);
924+
return -EINVAL;
925+
}
926+
}
927+
895928
ret = adrv9002_set_ext_lo(c, freq);
896929
if (ret)
897930
return ret;
@@ -1318,6 +1351,55 @@ static int adrv9002_set_intf_gain(struct iio_dev *indio_dev,
13181351
return api_call(phy, adi_adrv9001_Rx_InterfaceGain_Set, rx->channel.number, mode);
13191352
}
13201353

1354+
static int adrv9002_get_rx_port_select(struct iio_dev *indio_dev, const struct iio_chan_spec *chan)
1355+
{
1356+
struct adrv9002_rf_phy *phy = iio_priv(indio_dev);
1357+
unsigned int c = ADRV_ADDRESS_CHAN(chan->address);
1358+
struct adrv9002_rx_chan *rx = &phy->rx_channels[c];
1359+
1360+
guard(mutex)(&phy->lock);
1361+
/*
1362+
* In theory we would use adi_adrv9001_Radio_Carrier_Inspect() but it always returns
1363+
* RXA.
1364+
*/
1365+
return rx->manual_port;
1366+
}
1367+
1368+
static int adrv9002_set_rx_port_select(struct iio_dev *indio_dev,
1369+
const struct iio_chan_spec *chan, u32 mode)
1370+
{
1371+
struct adrv9002_rf_phy *phy = iio_priv(indio_dev);
1372+
unsigned int c = ADRV_ADDRESS_CHAN(chan->address);
1373+
struct adrv9002_rx_chan *rx = &phy->rx_channels[c];
1374+
struct adi_adrv9001_Carrier carrier;
1375+
int ret;
1376+
1377+
guard(mutex)(&phy->lock);
1378+
1379+
ret = api_call(phy, adi_adrv9001_Radio_Carrier_Inspect, rx->channel.port,
1380+
rx->channel.number, &carrier);
1381+
if (ret)
1382+
return ret;
1383+
1384+
if (mode)
1385+
carrier.manualRxport = ADI_ADRV9001_RX_B;
1386+
else
1387+
carrier.manualRxport = ADI_ADRV9001_RX_A;
1388+
1389+
ret = adrv9002_channel_to_state(phy, &rx->channel, ADI_ADRV9001_CHANNEL_CALIBRATED, true);
1390+
if (ret)
1391+
return ret;
1392+
1393+
ret = api_call(phy, adi_adrv9001_Radio_Carrier_Configure, rx->channel.port,
1394+
rx->channel.number, &carrier);
1395+
if (ret)
1396+
return ret;
1397+
1398+
rx->manual_port = carrier.manualRxport;
1399+
1400+
return adrv9002_channel_to_state(phy, &rx->channel, rx->channel.cached_state, false);
1401+
}
1402+
13211403
static int adrv9002_get_port_en_mode(struct iio_dev *indio_dev,
13221404
const struct iio_chan_spec *chan)
13231405
{
@@ -1951,6 +2033,17 @@ static const struct iio_enum adrv9002_intf_gain_available = {
19512033
.set = adrv9002_set_intf_gain,
19522034
};
19532035

2036+
static const char *const adrv9002_rx_port_select[] = {
2037+
"rx_a", "rx_b"
2038+
};
2039+
2040+
static const struct iio_enum adrv9002_rx_port_select_available = {
2041+
.items = adrv9002_rx_port_select,
2042+
.num_items = ARRAY_SIZE(adrv9002_rx_port_select),
2043+
.get = adrv9002_get_rx_port_select,
2044+
.set = adrv9002_set_rx_port_select,
2045+
};
2046+
19542047
static const char *const adrv9002_port_en_mode[] = {
19552048
"spi", "pin"
19562049
};
@@ -2025,6 +2118,43 @@ static const struct iio_chan_spec_ext_info adrv9002_phy_orx_ext_info[] = {
20252118
{ },
20262119
};
20272120

2121+
static const struct iio_chan_spec_ext_info adrv9002_phy_rx_mux_ext_info[] = {
2122+
/* Ideally we use IIO_CHAN_INFO_FREQUENCY, but there are
2123+
* values > 2^32 in order to support the entire frequency range
2124+
* in Hz. Using scale is a bit ugly.
2125+
*/
2126+
IIO_ENUM_AVAILABLE("ensm_mode", IIO_SEPARATE, &adrv9002_ensm_modes_available),
2127+
IIO_ENUM("ensm_mode", 0, &adrv9002_ensm_modes_available),
2128+
IIO_ENUM_AVAILABLE("gain_control_mode", IIO_SEPARATE, &adrv9002_agc_modes_available),
2129+
IIO_ENUM("gain_control_mode", 0, &adrv9002_agc_modes_available),
2130+
IIO_ENUM_AVAILABLE("digital_gain_control_mode", IIO_SEPARATE,
2131+
&adrv9002_digital_gain_ctl_modes_available),
2132+
IIO_ENUM("digital_gain_control_mode", 0,
2133+
&adrv9002_digital_gain_ctl_modes_available),
2134+
_ADRV9002_EXT_RX_INFO("interface_gain_available", RX_INTERFACE_GAIN_AVAIL),
2135+
IIO_ENUM("interface_gain", 0,
2136+
&adrv9002_intf_gain_available),
2137+
IIO_ENUM_AVAILABLE("port_en_mode", IIO_SEPARATE, &adrv9002_port_en_modes_available),
2138+
IIO_ENUM("port_en_mode", 0, &adrv9002_port_en_modes_available),
2139+
IIO_ENUM("port_select", IIO_SEPARATE, &adrv9002_rx_port_select_available),
2140+
IIO_ENUM_AVAILABLE("port_select", IIO_SEPARATE, &adrv9002_rx_port_select_available),
2141+
_ADRV9002_EXT_RX_INFO("rssi", RX_RSSI),
2142+
_ADRV9002_EXT_RX_INFO("decimated_power", RX_DECIMATION_POWER),
2143+
_ADRV9002_EXT_RX_INFO("rf_bandwidth", RX_RF_BANDWIDTH),
2144+
_ADRV9002_EXT_RX_INFO("nco_frequency", RX_NCO_FREQUENCY),
2145+
_ADRV9002_EXT_RX_INFO("quadrature_fic_tracking_en", RX_QEC_FIC),
2146+
_ADRV9002_EXT_RX_INFO("quadrature_w_poly_tracking_en", RX_QEC_W_POLY),
2147+
_ADRV9002_EXT_RX_INFO("agc_tracking_en", RX_AGC),
2148+
_ADRV9002_EXT_RX_INFO("bbdc_rejection_tracking_en", RX_TRACK_BBDC),
2149+
_ADRV9002_EXT_RX_INFO("hd_tracking_en", RX_HD2),
2150+
_ADRV9002_EXT_RX_INFO("rssi_tracking_en", RX_RSSI_CAL),
2151+
_ADRV9002_EXT_RX_INFO("rfdc_tracking_en", RX_RFDC),
2152+
_ADRV9002_EXT_RX_INFO("dynamic_adc_switch_en", RX_ADC_SWITCH),
2153+
_ADRV9002_EXT_RX_INFO("bbdc_rejection_en", RX_BBDC),
2154+
_ADRV9002_EXT_RX_INFO("bbdc_loop_gain_raw", RX_BBDC_LOOP_GAIN),
2155+
{ },
2156+
};
2157+
20282158
static const struct iio_chan_spec_ext_info adrv9002_phy_tx_mux_ext_info[] = {
20292159
IIO_ENUM_AVAILABLE("ensm_mode", IIO_SEPARATE, &adrv9002_ensm_modes_available),
20302160
IIO_ENUM("ensm_mode", IIO_SEPARATE, &adrv9002_ensm_modes_available),
@@ -3135,6 +3265,12 @@ static int adrv9002_validate_profile(struct adrv9002_rf_phy *phy)
31353265
dev_dbg(&phy->spi->dev, "TX%d enabled\n", i + 1);
31363266
/* orx actually depends on whether or not TX is enabled and not RX */
31373267
rx->orx_en = test_bit(ADRV9002_ORX_BIT_START + i, &rx_mask);
3268+
if (rx->orx_en && phy->port_switch.enable) {
3269+
dev_err(&phy->spi->dev,
3270+
"ORx%d and RX%d Port Switch cannot be both enabled\n",
3271+
i + 1, i + 1);
3272+
return -EINVAL;
3273+
}
31383274
tx->channel.power = true;
31393275
tx->channel.enabled = true;
31403276
tx->channel.nco_freq = 0;
@@ -3267,21 +3403,50 @@ static int adrv9002_digital_init(const struct adrv9002_rf_phy *phy)
32673403

32683404
static u64 adrv9002_get_init_carrier(const struct adrv9002_chan *c)
32693405
{
3406+
const struct adrv9002_rf_phy *phy = chan_to_phy(c);
32703407
u64 lo_freq;
32713408

32723409
if (!c->ext_lo) {
3410+
/* If no external LO, keep the same values as before */
3411+
if (c->port == ADI_RX) {
3412+
/*
3413+
* For RX, port switch needs to be taken into account. If in auto
3414+
* mode, the carrier needs to be in the given range.
3415+
*/
3416+
if (c->carrier)
3417+
lo_freq = c->carrier;
3418+
else
3419+
lo_freq = 2400000000ULL;
3420+
3421+
if (!phy->port_switch.enable || phy->port_switch.manualRxPortSwitch)
3422+
return lo_freq;
3423+
3424+
if (ADRV9002_PORT_SWITCH_IN_RANGE(&phy->port_switch, lo_freq))
3425+
return lo_freq;
3426+
3427+
dev_dbg(&phy->spi->dev, "RX%u LO(%llu) not in allowed range, Using(%llu)\n",
3428+
c->number, lo_freq, phy->port_switch.maxFreqPortA_Hz);
3429+
/* just choose one valid value */
3430+
return phy->port_switch.maxFreqPortA_Hz;
3431+
}
3432+
32733433
if (c->carrier)
32743434
return c->carrier;
32753435

3276-
/* If no external LO, keep the same values as before */
3277-
if (c->port == ADI_RX)
3278-
return 2400000000ULL;
3279-
32803436
return 2450000000ULL;
32813437
}
32823438

3283-
lo_freq = clk_get_rate_scaled(c->ext_lo->clk, &c->ext_lo->scale);
3284-
return DIV_ROUND_CLOSEST_ULL(lo_freq, c->ext_lo->divider);
3439+
lo_freq = DIV_ROUND_CLOSEST_ULL(clk_get_rate_scaled(c->ext_lo->clk, &c->ext_lo->scale),
3440+
c->ext_lo->divider);
3441+
/* if we have an external LO which does not fit in the port switch ranges just error out */
3442+
if (!phy->port_switch.enable || phy->port_switch.manualRxPortSwitch ||
3443+
ADRV9002_PORT_SWITCH_IN_RANGE(&phy->port_switch, lo_freq))
3444+
return lo_freq;
3445+
3446+
dev_err(&phy->spi->dev, "Port Switch enabled and RX%u LO(%llu) not in allowed range\n",
3447+
c->number, lo_freq);
3448+
3449+
return -EINVAL;
32853450
}
32863451

32873452
static int adrv9002_ext_lna_set(const struct adrv9002_rf_phy *phy,
@@ -3321,7 +3486,7 @@ static int adrv9002_init_dpd(const struct adrv9002_rf_phy *phy, const struct adr
33213486
* All of these structures are taken from TES when exporting the default profile to C code. Consider
33223487
* about having all of these configurable through devicetree.
33233488
*/
3324-
static int adrv9002_radio_init(const struct adrv9002_rf_phy *phy)
3489+
static int adrv9002_radio_init(struct adrv9002_rf_phy *phy)
33253490
{
33263491
int ret;
33273492
int chan;
@@ -3350,6 +3515,12 @@ static int adrv9002_radio_init(const struct adrv9002_rf_phy *phy)
33503515
if (ret)
33513516
return ret;
33523517

3518+
if (phy->port_switch.enable) {
3519+
ret = api_call(phy, adi_adrv9001_Rx_PortSwitch_Configure, &phy->port_switch);
3520+
if (ret)
3521+
return ret;
3522+
}
3523+
33533524
for (chan = 0; chan < ARRAY_SIZE(phy->channels); chan++) {
33543525
struct adrv9002_chan *c = phy->channels[chan];
33553526
struct adi_adrv9001_ChannelEnablementDelays en_delays;
@@ -4579,7 +4750,7 @@ static int adrv9002_iio_channels_get(struct adrv9002_rf_phy *phy)
45794750
* be added in between but that should be easy enough to maintain!
45804751
*/
45814752
unsigned int off = ADRV9002_CHANN_MAX + phy->chip->n_tx;
4582-
unsigned int tx;
4753+
unsigned int tx, rx;
45834754

45844755
phy->iio_chan = devm_kmemdup(&phy->spi->dev, phy->chip->channels,
45854756
sizeof(*phy->chip->channels) * phy->chip->num_channels,
@@ -4597,6 +4768,14 @@ static int adrv9002_iio_channels_get(struct adrv9002_rf_phy *phy)
45974768
phy->iio_chan[off + tx].ext_info = adrv9002_phy_tx_mux_ext_info;
45984769
}
45994770

4771+
if (!phy->port_switch.manualRxPortSwitch)
4772+
return 0;
4773+
4774+
/* For RX's we need to account for the actual TX's plus 4 AUXDAC channels */
4775+
off += phy->chip->n_tx + 4;
4776+
for (rx = 0; rx < ARRAY_SIZE(phy->rx_channels); rx++)
4777+
phy->iio_chan[off + rx].ext_info = adrv9002_phy_rx_mux_ext_info;
4778+
46004779
return 0;
46014780
}
46024781

drivers/iio/adc/navassa/adrv9002.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ struct adrv9002_rx_chan {
186186
struct adi_adrv9001_RxGainControlPinCfg *pin_cfg;
187187
struct clk *tdd_clk;
188188
struct gpio_desc *orx_gpio;
189+
enum adi_adrv9001_RxRfInputSel manual_port;
189190
u8 orx_en;
190191
#ifdef CONFIG_DEBUG_FS
191192
struct adi_adrv9001_RxSsiTestModeCfg ssi_test;
@@ -276,6 +277,7 @@ struct adrv9002_rf_phy {
276277
struct adi_adrv9001_Init *curr_profile;
277278
struct adi_adrv9001_Init profile;
278279
struct adi_adrv9001_InitCals init_cals;
280+
struct adi_adrv9001_RxPortSwitchCfg port_switch;
279281
bool run_cals;
280282
u32 n_clks;
281283
u32 dev_clkout_div;

0 commit comments

Comments
 (0)