diff --git a/drivers/iio/adc/adrv902x/adrv9025.c b/drivers/iio/adc/adrv902x/adrv9025.c index 5af638b2dbb45..c400d3d7ee276 100644 --- a/drivers/iio/adc/adrv902x/adrv9025.c +++ b/drivers/iio/adc/adrv902x/adrv9025.c @@ -1088,23 +1088,22 @@ static const char * const adrv9025_obs2_rx_port[] = { "ORX3_ON_ORX4_OFF", "ORX3_OFF_ORX4_ON", }; -static const u8 ad9371_obs_rx_port_lut[] = { +static const u8 adrv9025_obs_rx_port_lut[] = { BIT(4), BIT(5) }; /* - * True when the device is configured for dual-channel 4-pin ORx mode - * (orxEnableMode=4) AND the ORX_CTRL pins are wired in the device tree. In - * this mode ORx enable/select is driven by the ORX_CTRL pins (A/C = side-A/ - * side-B enable, B/D = side-A/side-B channel select), not the 0x106 SPI - * enable. The enable mode comes from the init profile cached at probe. + * Return the configured ORx enable mode (orxEnableMode) cached from the init + * profile at probe. In dual-channel 4-pin mode (ADI_ADRV9025_ORX_EN_DUAL_CH_4PIN_MODE) + * ORx enable/select is driven by the ORX_CTRL pins (A/C = side-A/side-B enable, + * B/D = side-A/side-B channel select) rather than the 0x106 SPI enable; in SPI + * mode the 0x106 enable is used instead. */ -static bool adrv9025_orx_dual_4pin(struct adrv9025_rf_phy *phy) +static adi_adrv9025_ORxEnableMode_e +adrv9025_orx_get_mode(struct adrv9025_rf_phy *phy) { - return phy->orx_ctrl_a_gpio && phy->orx_ctrl_c_gpio && - phy->adrv9025PostMcsInitInst.radioCtrlInit.radioCtrlModeCfg - .orxRadioCtrlModeCfg.orxEnableMode == - ADI_ADRV9025_ORX_EN_DUAL_CH_4PIN_MODE; + return phy->adrv9025PostMcsInitInst.radioCtrlInit.radioCtrlModeCfg + .orxRadioCtrlModeCfg.orxEnableMode; } /* @@ -1142,7 +1141,7 @@ static int adrv9025_orx_xbar_reassert(struct adrv9025_rf_phy *phy) * side-B) to pick which ORx of the pair is observed. It does NOT enable the * side - enable is owned by the _en attribute (write_raw). mode is the enum * index: 0 = first ORx of the pair (sel low), 1 = second ORx (sel high). - * On boards without the ORX_CTRL pins it falls back to legacy SPI selection. + * Every other mode does channel select through SPI registers. */ static int adrv9025_set_obs_rx_path(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, u32 mode) @@ -1153,40 +1152,53 @@ static int adrv9025_set_obs_rx_path(struct iio_dev *indio_dev, u32 val = 0; int ret; - if (adrv9025_orx_dual_4pin(phy)) { - struct gpio_desc *sel_gpio = (chan->channel > CHAN_OBS_RX1) ? - phy->orx_ctrl_d_gpio : - phy->orx_ctrl_b_gpio; + switch (adrv9025_orx_get_mode(phy)) { + case ADI_ADRV9025_ORX_EN_DUAL_CH_4PIN_MODE: { + struct gpio_desc *sel_gpio = NULL; + + if (chan) + sel_gpio = (chan->channel > CHAN_OBS_RX1) ? + phy->orx_ctrl_d_gpio : phy->orx_ctrl_b_gpio; + + if (!sel_gpio) + return -ENODEV; /* select line: mode 1 = second ORx of the pair => assert */ - if (sel_gpio) - gpiod_set_value_cansleep(sel_gpio, mode ? 1 : 0); + gpiod_set_value_cansleep(sel_gpio, mode ? 1 : 0); /* selecting changes routing; re-assert the split crossbar */ ret = adrv9025_orx_xbar_reassert(phy); if (ret) return adrv9025_dev_err(phy); - return 0; + break; } - /* Legacy SPI-mode select+enable (boards without ORX_CTRL pins). */ - ret = adi_adrv9025_RxTxEnableGet(phy->madDevice, &rxchan, - &txchan); - if (ret) - return adrv9025_dev_err(phy); + case ADI_ADRV9025_ORX_EN_SPI_MODE: + ret = adi_adrv9025_RxTxEnableGet(phy->madDevice, &rxchan, + &txchan); + if (ret) + return adrv9025_dev_err(phy); - val = ad9371_obs_rx_port_lut[mode]; - if (chan->channel > CHAN_OBS_RX1) { - mask = mask << 2 | 0xF; - val <<= 2; - } + val = adrv9025_obs_rx_port_lut[mode]; + if (chan->channel > CHAN_OBS_RX1) { + mask = mask << 2 | 0xF; + val <<= 2; + } - rxchan = (rxchan & mask) | val; + rxchan = (rxchan & mask) | val; - ret = adi_adrv9025_RxTxEnableSet(phy->madDevice, rxchan, txchan); - if (ret) - return adrv9025_dev_err(phy); + ret = adi_adrv9025_RxTxEnableSet(phy->madDevice, rxchan, txchan); + if (ret) + return adrv9025_dev_err(phy); + + break; + + case ADI_ADRV9025_ORX_EN_INVALID_MODE: + default: + ret = -EINVAL; + break; + } return ret; } @@ -1200,37 +1212,55 @@ static int adrv9025_get_obs_rx_path(struct iio_dev *indio_dev, int pair; int ret; - /* - * In dual-4-pin mode selection is held by the channel-select pin, so - * read it back directly. The output gpio returns the last value set. - * 0 = first ORx of the pair, 1 = second ORx (matches the 2-item enum). - */ - if (adrv9025_orx_dual_4pin(phy)) { - struct gpio_desc *sel_gpio = (chan->channel > CHAN_OBS_RX1) ? - phy->orx_ctrl_d_gpio : - phy->orx_ctrl_b_gpio; + switch (adrv9025_orx_get_mode(phy)) { + case ADI_ADRV9025_ORX_EN_DUAL_CH_4PIN_MODE: { + struct gpio_desc *sel_gpio = NULL; + + if (chan) + sel_gpio = (chan->channel > CHAN_OBS_RX1) ? + phy->orx_ctrl_d_gpio : phy->orx_ctrl_b_gpio; + + if (!sel_gpio) + return -ENODEV; + + ret = gpiod_get_value_cansleep(sel_gpio); + if (ret < 0) + return ret; /* gpiolib errno, not a MADAPI error */ - return (sel_gpio && gpiod_get_value_cansleep(sel_gpio)) ? 1 : 0; + ret = !!ret; + break; } - ret = adi_adrv9025_RxTxEnableGet(phy->madDevice, &rxchan, - &txchan); - if (ret) - return adrv9025_dev_err(phy); + case ADI_ADRV9025_ORX_EN_SPI_MODE: + /* Legacy SPI-mode readback. */ + ret = adi_adrv9025_RxTxEnableGet(phy->madDevice, &rxchan, + &txchan); + if (ret) + return adrv9025_dev_err(phy); - if (chan->channel > CHAN_OBS_RX1) - shift_right = CHAN_OBS_RX3; + if (chan->channel > CHAN_OBS_RX1) + shift_right = CHAN_OBS_RX3; - /* - * Each ORx pair occupies two adjacent enable bits (lower/upper). The - * rf_port_select enum is now SELECT-only with two items: index 0 = - * lower ORx, index 1 = upper ORx. Map the upper enable bit to index 1 - * and everything else (lower-on or disabled) to index 0 so the read - * always lands on a valid enum item. - */ - pair = rxchan >> shift_right & 0x3; + /* + * Each ORx pair occupies two adjacent enable bits (lower/ + * upper). The rf_port_select enum is SELECT-only with two + * items: index 0 = lower ORx, index 1 = upper ORx. Map the + * upper enable bit to index 1 and everything else (lower-on or + * disabled) to index 0 so the read always lands on a valid + * enum item. + */ + pair = rxchan >> shift_right & 0x3; + + ret = (pair & 0x2) ? 1 : 0; + break; + + case ADI_ADRV9025_ORX_EN_INVALID_MODE: + default: + ret = -EINVAL; + break; + } - return (pair & 0x2) ? 1 : 0; + return ret; } static const struct iio_enum adrv9025_rf_obs1_rx_port_available = { @@ -1336,6 +1366,79 @@ static int adrv9025_gain_to_gainindex(struct adrv9025_rf_phy *phy, int channel, return 0; } +/* + * Resolve an OBS channel to the physical ORx the gain attributes apply to. + * In dual-channel 4-pin mode the selection is held by the channel-select pin + * and is read back through adrv9025_get_obs_rx_path() (0 = lower ORx of the + * pair, 1 = upper). A gain access must never drive that pin, so the pin is + * only read here. In SPI mode the selection is derived from the 0x106 enable + * bits, which must have exactly one ORx of the pair enabled. + * + * Channels that are not OBS channels are passed through unchanged. On success + * the physical channel is stored in @out_chan_no and 0 is returned, otherwise + * a negative errno. + */ +static int adrv9025_resolve_obs_channel(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *out_chan_no) +{ + struct adrv9025_rf_phy *phy = iio_priv(indio_dev); + int chan_no = chan->channel; + u32 rxchan, txchan; + int sel, ret; + + if (chan_no <= CHAN_RX4) + goto done; + + switch (adrv9025_orx_get_mode(phy)) { + case ADI_ADRV9025_ORX_EN_DUAL_CH_4PIN_MODE: + sel = adrv9025_get_obs_rx_path(indio_dev, chan); + if (sel < 0) + return sel; + + if (chan_no == CHAN_OBS_RX1) + chan_no = sel ? CHAN_OBS_RX2 : CHAN_OBS_RX1; + else if (chan_no == CHAN_OBS_RX2) + chan_no = sel ? CHAN_OBS_RX4 : CHAN_OBS_RX3; + break; + + case ADI_ADRV9025_ORX_EN_SPI_MODE: + ret = adi_adrv9025_RxTxEnableGet(phy->madDevice, &rxchan, + &txchan); + if (ret) + return adrv9025_dev_err(phy); + + if (chan_no == CHAN_OBS_RX1) { + if ((rxchan & ADI_ADRV9025_ORX1) && + !(rxchan & ADI_ADRV9025_ORX2)) + chan_no = CHAN_OBS_RX1; + else if (!(rxchan & ADI_ADRV9025_ORX1) && + (rxchan & ADI_ADRV9025_ORX2)) + chan_no = CHAN_OBS_RX2; + else + return -EINVAL; + } else if (chan_no == CHAN_OBS_RX2) { + if ((rxchan & ADI_ADRV9025_ORX3) && + !(rxchan & ADI_ADRV9025_ORX4)) + chan_no = CHAN_OBS_RX3; + else if (!(rxchan & ADI_ADRV9025_ORX3) && + (rxchan & ADI_ADRV9025_ORX4)) + chan_no = CHAN_OBS_RX4; + else + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + +done: + *out_chan_no = chan_no; + + return 0; +} + static int adrv9025_phy_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long m) @@ -1357,11 +1460,23 @@ static int adrv9025_phy_read_raw(struct iio_dev *indio_dev, break; } - if (chan->output) + if (chan->output) { *val = !!(txchan & (ADI_ADRV9025_TX1 << chan->channel)); - else - if (chan->channel >= CHAN_OBS_RX1 && - adrv9025_orx_dual_4pin(phy)) { + ret = IIO_VAL_INT; + break; + } + + /* Regular Rx channels always use the SPI enable state. */ + if (chan->channel < CHAN_OBS_RX1) { + *val = !!(rxchan & (ADI_ADRV9025_RX1 << chan->channel)); + ret = IIO_VAL_INT; + break; + } + + /* OBS channel: dispatch on the configured ORx enable mode. */ + if (chan->channel >= CHAN_OBS_RX1) { + switch (adrv9025_orx_get_mode(phy)) { + case ADI_ADRV9025_ORX_EN_DUAL_CH_4PIN_MODE: { /* enable is held by the side ENABLE pin (A/C) */ struct gpio_desc *en_gpio = (chan->channel > CHAN_OBS_RX1) ? @@ -1370,15 +1485,20 @@ static int adrv9025_phy_read_raw(struct iio_dev *indio_dev, *val = en_gpio ? !!gpiod_get_value_cansleep(en_gpio) : 0; - } else if (chan->channel >= CHAN_OBS_RX1) { + break; + } + case ADI_ADRV9025_ORX_EN_SPI_MODE: chan_no = chan->channel; if (chan_no == CHAN_OBS_RX2) chan_no += 1; *val = !!(rxchan & (ADI_ADRV9025_RX1 << chan_no) || rxchan & (ADI_ADRV9025_RX1 << (chan_no + 1))); - } else { - *val = !!(rxchan & (ADI_ADRV9025_RX1 << chan->channel)); + break; + default: + ret = -EINVAL; + goto out; } + } ret = IIO_VAL_INT; break; @@ -1400,36 +1520,11 @@ static int adrv9025_phy_read_raw(struct iio_dev *indio_dev, } else { adi_adrv9025_RxGain_t rxGain; - chan_no = chan->channel; - if (chan_no > CHAN_RX4) { - /* For OBS channels, determine which specific channel is enabled */ - ret = adi_adrv9025_RxTxEnableGet(phy->madDevice, &rxchan, &txchan); - if (ret) { - ret = adrv9025_dev_err(phy); - break; - } - - if (chan_no == CHAN_OBS_RX1) { - if ((rxchan & ADI_ADRV9025_ORX1) && !(rxchan & ADI_ADRV9025_ORX2)) { - chan_no = CHAN_OBS_RX1; - } else if (!(rxchan & ADI_ADRV9025_ORX1) && (rxchan & ADI_ADRV9025_ORX2)) { - chan_no = CHAN_OBS_RX2; - } else { - ret = -EINVAL; - break; - } - } else if (chan_no == CHAN_OBS_RX2) { - if ((rxchan & ADI_ADRV9025_ORX3) && !(rxchan & ADI_ADRV9025_ORX4)) { - chan_no = CHAN_OBS_RX3; - } else if (!(rxchan & ADI_ADRV9025_ORX3) && (rxchan & ADI_ADRV9025_ORX4)) { - chan_no = CHAN_OBS_RX4; - } else { - ret = -EINVAL; - break; - } - } - } + ret = adrv9025_resolve_obs_channel(indio_dev, chan, + &chan_no); + if (ret) + goto out; ret = adi_adrv9025_RxGainGet( phy->madDevice, 1 << chan_no, &rxGain); @@ -1474,6 +1569,7 @@ static int adrv9025_phy_read_raw(struct iio_dev *indio_dev, ret = -EINVAL; } +out: mutex_unlock(&phy->lock); return ret; @@ -1505,49 +1601,76 @@ static int adrv9025_phy_write_raw(struct iio_dev *indio_dev, txchan |= (ADI_ADRV9025_TX1 << chan->channel); else txchan &= ~(ADI_ADRV9025_TX1 << chan->channel); - } else if (chan->channel >= CHAN_OBS_RX1 && - adrv9025_orx_dual_4pin(phy)) { - /* - * Dual-channel 4-pin mode: the ORx side ENABLE is owned - * by the ORX_CTRL pin (A for side-A/obs1, C for side-B/ - * obs2), not the 0x106 SPI enable. _en drives the pin; - * which ORx of the pair is picked by rf_port_select (the - * select pin). Re-assert the split crossbar after the - * enable edge (the stream collapses it on that edge). - */ - struct gpio_desc *en_gpio = - (chan->channel > CHAN_OBS_RX1) ? - phy->orx_ctrl_c_gpio : phy->orx_ctrl_a_gpio; - - gpiod_set_value_cansleep(en_gpio, val ? 1 : 0); - - if (val) { - ret = adrv9025_orx_xbar_reassert(phy); - if (ret) - ret = adrv9025_dev_err(phy); - } + + ret = adi_adrv9025_RxTxEnableSet(phy->madDevice, rxchan, + txchan); + if (ret) + ret = adrv9025_dev_err(phy); break; - } else { - chan_no = chan->channel; - if (chan_no == CHAN_OBS_RX2) - chan_no += 1; - if (val) { - rxchan |= (ADI_ADRV9025_RX1 << chan_no); - if (chan_no >= CHAN_OBS_RX1) + } + + /* Regular Rx channels always use the SPI enable path. */ + if (chan->channel < CHAN_OBS_RX1) { + if (val) + rxchan |= (ADI_ADRV9025_RX1 << chan->channel); + else + rxchan &= ~(ADI_ADRV9025_RX1 << chan->channel); + + ret = adi_adrv9025_RxTxEnableSet(phy->madDevice, rxchan, + txchan); + if (ret) + ret = adrv9025_dev_err(phy); + break; + } + /* OBS channel: dispatch on the configured ORx enable mode. */ + if (chan->channel >= CHAN_OBS_RX1) { + switch (adrv9025_orx_get_mode(phy)) { + case ADI_ADRV9025_ORX_EN_DUAL_CH_4PIN_MODE: { + /* + * Dual-channel 4-pin mode: the ORx side ENABLE is + * owned by the ORX_CTRL pin (A for side-A/obs1, C + * for side-B/obs2), not the 0x106 SPI enable. _en + * drives the pin; which ORx of the pair is picked + * by rf_port_select (the select pin). Re-assert the + * split crossbar after the enable edge (the stream + * collapses it on that edge). + */ + struct gpio_desc *en_gpio = + (chan->channel > CHAN_OBS_RX1) ? + phy->orx_ctrl_c_gpio : + phy->orx_ctrl_a_gpio; + + gpiod_set_value_cansleep(en_gpio, val ? 1 : 0); + + if (val) { + ret = adrv9025_orx_xbar_reassert(phy); + if (ret) + ret = adrv9025_dev_err(phy); + } + break; + } + case ADI_ADRV9025_ORX_EN_SPI_MODE: + chan_no = chan->channel; + if (chan_no == CHAN_OBS_RX2) + chan_no += 1; + if (val) { + rxchan |= (ADI_ADRV9025_RX1 << chan_no); rxchan &= ~(ADI_ADRV9025_RX1 << (chan_no + 1)); - } else { - if (chan_no < CHAN_OBS_RX1) { - rxchan &= ~(ADI_ADRV9025_RX1 << chan_no); } else { rxchan &= ~(ADI_ADRV9025_RX1 << chan_no); rxchan &= ~(ADI_ADRV9025_RX1 << (chan_no + 1)); } + + ret = adi_adrv9025_RxTxEnableSet(phy->madDevice, + rxchan, txchan); + if (ret) + ret = adrv9025_dev_err(phy); + break; + default: + ret = -EINVAL; + break; } } - ret = adi_adrv9025_RxTxEnableSet(phy->madDevice, rxchan, - txchan); - if (ret) - ret = adrv9025_dev_err(phy); break; case IIO_CHAN_INFO_HARDWAREGAIN: @@ -1571,36 +1694,11 @@ static int adrv9025_phy_write_raw(struct iio_dev *indio_dev, } else { adi_adrv9025_RxGain_t rxGain; - chan_no = chan->channel; - - if (chan_no > CHAN_RX4) { - ret = adi_adrv9025_RxTxEnableGet(phy->madDevice, &rxchan, - &txchan); - if (ret) { - ret = adrv9025_dev_err(phy); - goto out; - } - if (chan_no == CHAN_OBS_RX1) { - if (rxchan & ADI_ADRV9025_ORX1 && !(rxchan & ADI_ADRV9025_ORX2)) { - chan_no = CHAN_OBS_RX1; - } else if (!(rxchan & ADI_ADRV9025_ORX1) && (rxchan & ADI_ADRV9025_ORX2)) { - chan_no = CHAN_OBS_RX2; - } else { - ret = -EINVAL; - goto out; - } - } else if (chan_no == CHAN_OBS_RX2) { - if (rxchan & ADI_ADRV9025_ORX3 && !(rxchan & ADI_ADRV9025_ORX4)) { - chan_no = CHAN_OBS_RX3; - } else if (!(rxchan & ADI_ADRV9025_ORX3) && (rxchan & ADI_ADRV9025_ORX4)) { - chan_no = CHAN_OBS_RX4; - } else { - ret = -EINVAL; - goto out; - } - } - } + ret = adrv9025_resolve_obs_channel(indio_dev, chan, + &chan_no); + if (ret) + goto out; ret = adrv9025_gain_to_gainindex(phy, chan_no, val, val2, &code);