Skip to content

Commit 39f5b6f

Browse files
committed
iio: adc: ad9088: Add support for CNCO and FNCO mixer mode configuration
This patch introduces support for configuring the mixer modes of both coarse (CNCO) and fine (FNCO) NCOs via IIO attributes. It adds read and write handlers for both RX and TX paths, allowing user-space control over mixer behavior. The supported mixer modes include: - Variable IF - Zero IF - Fs/4 IF - Test tone New IIO attributes: - main_nco_mixer_mode - channel_nco_mixer_mode - *_available variants for both These attributes are exposed per channel and allow fine-grained control over signal path configuration, improving flexibility for diverse RF applications. Signed-off-by: Michael Hennerich <[email protected]>
1 parent db15078 commit 39f5b6f

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

drivers/iio/adc/apollo/ad9088.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,7 +1550,116 @@ static const struct iio_enum ad9088_loopback_modes_enum = {
15501550
.get = ad9088_loopback_mode_read,
15511551
};
15521552

1553+
static int ad9088_cnco_mixer_mode_read(struct iio_dev *indio_dev,
1554+
const struct iio_chan_spec *chan)
1555+
{
1556+
struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev);
1557+
struct ad9088_phy *phy = conv->phy;
1558+
u8 cddc_num, fddc_num, side, mode;
1559+
u32 cddc_mask, fddc_mask;
1560+
int ret;
1561+
1562+
ad9088_iiochan_to_fddc_cddc(phy, chan, &fddc_num,
1563+
&fddc_mask, &cddc_num, &cddc_mask, &side);
1564+
1565+
ret = adi_apollo_hal_bf_get(&phy->ad9088,
1566+
BF_DRC_IF_MODE_TXRX_COARSE_NCO_INFO(chan->output ? calc_tx_cnco_base(cddc_num) : calc_rx_cnco_base(cddc_num)),
1567+
&mode, 1);
1568+
if (ret)
1569+
return ret;
1570+
1571+
return mode & 0x3;
1572+
}
1573+
1574+
static int ad9088_cnco_mixer_mode_write(struct iio_dev *indio_dev,
1575+
const struct iio_chan_spec *chan,
1576+
unsigned int item)
1577+
{
1578+
struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev);
1579+
struct ad9088_phy *phy = conv->phy;
1580+
u8 cddc_num, fddc_num, side;
1581+
u32 cddc_mask, fddc_mask;
1582+
int ret = 0;
1583+
1584+
ad9088_iiochan_to_fddc_cddc(phy, chan, &fddc_num,
1585+
&fddc_mask, &cddc_num, &cddc_mask, &side);
1586+
1587+
guard(mutex)(&phy->lock);
1588+
1589+
return adi_apollo_cnco_mode_set(&phy->ad9088, chan->output ? ADI_APOLLO_TX : ADI_APOLLO_RX,
1590+
cddc_mask, item);
1591+
1592+
return ret;
1593+
}
1594+
1595+
static int ad9088_fnco_mixer_mode_read(struct iio_dev *indio_dev,
1596+
const struct iio_chan_spec *chan)
1597+
{
1598+
struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev);
1599+
struct ad9088_phy *phy = conv->phy;
1600+
u8 cddc_num, fddc_num, side, mode;
1601+
u32 cddc_mask, fddc_mask;
1602+
int ret;
1603+
1604+
ad9088_iiochan_to_fddc_cddc(phy, chan, &fddc_num,
1605+
&fddc_mask, &cddc_num, &cddc_mask, &side);
1606+
1607+
ret = adi_apollo_hal_bf_get(&phy->ad9088,
1608+
BF_DRC_IF_MODE_TXRX_FINE_NCO_INFO(chan->output ? calc_tx_fnco_base(fddc_num) : calc_rx_fnco_base(fddc_num)),
1609+
&mode, 1);
1610+
if (ret)
1611+
return ret;
1612+
1613+
return mode & 0x3;
1614+
}
1615+
1616+
static int ad9088_fnco_mixer_mode_write(struct iio_dev *indio_dev,
1617+
const struct iio_chan_spec *chan,
1618+
unsigned int item)
1619+
{
1620+
struct axiadc_converter *conv = iio_device_get_drvdata(indio_dev);
1621+
struct ad9088_phy *phy = conv->phy;
1622+
u8 cddc_num, fddc_num, side;
1623+
u32 cddc_mask, fddc_mask;
1624+
int ret = 0;
1625+
1626+
ad9088_iiochan_to_fddc_cddc(phy, chan, &fddc_num,
1627+
&fddc_mask, &cddc_num, &cddc_mask, &side);
1628+
1629+
guard(mutex)(&phy->lock);
1630+
1631+
return adi_apollo_fnco_mode_set(&phy->ad9088, chan->output ? ADI_APOLLO_TX : ADI_APOLLO_RX,
1632+
fddc_mask, item);
1633+
1634+
return ret;
1635+
}
1636+
1637+
static const char *const ad9088_mixer_modes[] = {
1638+
[ADI_APOLLO_MXR_VAR_IF_MODE] = "var_IF",
1639+
[ADI_APOLLO_MXR_ZERO_IF_MODE] = "zero_IF",
1640+
[ADI_APOLLO_MXR_FS_BY_4_MODE] = "fs/4_IF",
1641+
[ADI_APOLLO_MXR_TEST_MODE] = "test_tone",
1642+
};
1643+
1644+
static const struct iio_enum ad9088_cnco_mixer_modes_enum = {
1645+
.items = ad9088_mixer_modes,
1646+
.num_items = ARRAY_SIZE(ad9088_mixer_modes),
1647+
.set = ad9088_cnco_mixer_mode_write,
1648+
.get = ad9088_cnco_mixer_mode_read,
1649+
};
1650+
1651+
static const struct iio_enum ad9088_fnco_mixer_modes_enum = {
1652+
.items = ad9088_mixer_modes,
1653+
.num_items = ARRAY_SIZE(ad9088_mixer_modes),
1654+
.set = ad9088_fnco_mixer_mode_write,
1655+
.get = ad9088_fnco_mixer_mode_read,
1656+
};
1657+
15531658
static struct iio_chan_spec_ext_info rxadc_ext_info[] = {
1659+
IIO_ENUM("main_nco_mixer_mode", IIO_SEPARATE, &ad9088_cnco_mixer_modes_enum),
1660+
IIO_ENUM_AVAILABLE("main_nco_mixer_mode", IIO_SHARED_BY_TYPE, &ad9088_fnco_mixer_modes_enum),
1661+
IIO_ENUM("channel_nco_mixer_mode", IIO_SEPARATE, &ad9088_cnco_mixer_modes_enum),
1662+
IIO_ENUM_AVAILABLE("channel_nco_mixer_mode", IIO_SHARED_BY_TYPE, &ad9088_fnco_mixer_modes_enum),
15541663
IIO_ENUM("test_mode", IIO_SEPARATE, &ad9088_testmode_enum),
15551664
IIO_ENUM_AVAILABLE("test_mode", IIO_SHARED_BY_TYPE, &ad9088_testmode_enum),
15561665
IIO_ENUM("loopback", IIO_SEPARATE, &ad9088_loopback_modes_enum),
@@ -1700,6 +1809,10 @@ static struct iio_chan_spec_ext_info rxadc_ext_info[] = {
17001809
};
17011810

17021811
static struct iio_chan_spec_ext_info txdac_ext_info[] = {
1812+
IIO_ENUM("main_nco_mixer_mode", IIO_SEPARATE, &ad9088_cnco_mixer_modes_enum),
1813+
IIO_ENUM_AVAILABLE("main_nco_mixer_mode", IIO_SHARED_BY_TYPE, &ad9088_fnco_mixer_modes_enum),
1814+
IIO_ENUM("channel_nco_mixer_mode", IIO_SEPARATE, &ad9088_cnco_mixer_modes_enum),
1815+
IIO_ENUM_AVAILABLE("channel_nco_mixer_mode", IIO_SHARED_BY_TYPE, &ad9088_fnco_mixer_modes_enum),
17031816
{
17041817
.name = "main_nco_frequency",
17051818
.read = ad9088_ext_info_read,

0 commit comments

Comments
 (0)