diff --git a/drivers/iio/adc/adrv902x/adrv9025.c b/drivers/iio/adc/adrv902x/adrv9025.c index decf81e39861df..9afca9031deec3 100644 --- a/drivers/iio/adc/adrv902x/adrv9025.c +++ b/drivers/iio/adc/adrv902x/adrv9025.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1931,6 +1932,90 @@ static const struct file_operations adrv9025_debugfs_reg_fops = { .write = adrv9025_debugfs_write, }; +static int adrv9025_tx_advanced_dpd_status_show(struct seq_file *s, void *ignored) +{ + struct adrv9025_tx_chan_ctx *ctx = s->private; + adi_adrv9025_DpdStatus_v2_t dpdStatus = { 0 }; + struct adrv9025_rf_phy *phy = ctx->phy; + adi_adrv9025_TxChannels_e txChannel; + u8 chan = ctx->channel; + int ret; + + /* Convert channel index to TX channel enum */ + txChannel = ADI_ADRV9025_TX1 << chan; + + mutex_lock(&phy->lock); + ret = adi_adrv9025_DpdStatusGet_v2(phy->madDevice, txChannel, &dpdStatus); + mutex_unlock(&phy->lock); + if (ret) + return adrv9025_dev_err(phy); + + seq_printf(s, "ADRV9025 TX%u Advanced DPD Status\n", chan); + + /* Basic Status */ + seq_puts(s, "Basic Status:\n"); + seq_printf(s, " Error Code: %d\n", dpdStatus.dpdErrorCode); + seq_printf(s, " Percent Complete: %u%%\n", dpdStatus.dpdPercentComplete); + seq_printf(s, " Iteration Count: %u\n", dpdStatus.dpdIterCount); + seq_printf(s, " Update Count: %u\n", dpdStatus.dpdUpdateCount); + seq_printf(s, " Sync Status: %d\n", dpdStatus.dpdSyncStatus); + seq_printf(s, " Model Table: %d\n", dpdStatus.dpdModelTable); + + /* Power Statistics */ + seq_puts(s, "\nPower Statistics:\n"); + seq_printf(s, " Mean TU Power: %d.%03d dBFS\n", + dpdStatus.dpdStatistics.dpdMeanTuPower_mdB / 1000, + abs(dpdStatus.dpdStatistics.dpdMeanTuPower_mdB % 1000)); + seq_printf(s, " Peak TU Power: %d.%03d dBFS\n", + dpdStatus.dpdStatistics.dpdPeakTuPower_mdB / 1000, + abs(dpdStatus.dpdStatistics.dpdPeakTuPower_mdB % 1000)); + seq_printf(s, " Mean TX Power: %d.%03d dBFS\n", + dpdStatus.dpdStatistics.dpdMeanTxPower_mdB / 1000, + abs(dpdStatus.dpdStatistics.dpdMeanTxPower_mdB % 1000)); + seq_printf(s, " Peak TX Power: %d.%03d dBFS\n", + dpdStatus.dpdStatistics.dpdPeakTxPower_mdB / 1000, + abs(dpdStatus.dpdStatistics.dpdPeakTxPower_mdB % 1000)); + seq_printf(s, " Mean ORx Power: %d.%03d dBFS\n", + dpdStatus.dpdStatistics.dpdMeanOrxPower_mdB / 1000, + abs(dpdStatus.dpdStatistics.dpdMeanOrxPower_mdB % 1000)); + seq_printf(s, " Peak ORx Power: %d.%03d dBFS\n", + dpdStatus.dpdStatistics.dpdPeakOrxPower_mdB / 1000, + abs(dpdStatus.dpdStatistics.dpdPeakOrxPower_mdB % 1000)); + + /* Error Metrics */ + seq_puts(s, "\nError Metrics:\n"); + seq_printf(s, " Direct EVM: %u.%04u%%\n", + dpdStatus.dpdStatistics.dpdDirectEvm_xM / 10000, + dpdStatus.dpdStatistics.dpdDirectEvm_xM % 10000); + seq_printf(s, " Indirect EVM: %u.%04u%%\n", + dpdStatus.dpdStatistics.dpdIndirectEvm_xM / 10000, + dpdStatus.dpdStatistics.dpdIndirectEvm_xM % 10000); + seq_printf(s, " Select Error: %u.%04u%%\n", + dpdStatus.dpdStatistics.dpdSelectError_xM / 10000, + dpdStatus.dpdStatistics.dpdSelectError_xM % 10000); + seq_printf(s, " Indirect Error: %u.%04u%%\n", + dpdStatus.dpdStatistics.dpdIndirectError_xM / 10000, + dpdStatus.dpdStatistics.dpdIndirectError_xM % 10000); + + /* Error Status */ + seq_puts(s, "\nError Status:\n"); + seq_printf(s, " Error Status 0: metrics_mask=0x%04x, action_mask=0x%04x\n", + dpdStatus.dpdErrorStatus0.dpdMetricsMask, + dpdStatus.dpdErrorStatus0.dpdActionMask); + seq_printf(s, " Error Status 1: metrics_mask=0x%04x, action_mask=0x%04x\n", + dpdStatus.dpdErrorStatus1.dpdMetricsMask, + dpdStatus.dpdErrorStatus1.dpdActionMask); + seq_printf(s, " Persistent Error 0: metrics_mask=0x%04x, action_mask=0x%04x\n", + dpdStatus.dpdPersistentErrorStatus0.dpdMetricsMask, + dpdStatus.dpdPersistentErrorStatus0.dpdActionMask); + seq_printf(s, " Persistent Error 1: metrics_mask=0x%04x, action_mask=0x%04x\n", + dpdStatus.dpdPersistentErrorStatus1.dpdMetricsMask, + dpdStatus.dpdPersistentErrorStatus1.dpdActionMask); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(adrv9025_tx_advanced_dpd_status); + static void adrv9025_add_debugfs_entry(struct adrv9025_rf_phy *phy, const char *propname, unsigned int cmd) { @@ -1991,6 +2076,21 @@ static int adrv9025_register_debugfs(struct iio_dev *indio_dev) &phy->debugfs_entry[i], &adrv9025_debugfs_reg_fops); } + + /* Create seqfile-based debugfs entries for each TX channel */ + for (i = 0; i < ADRV9025_NUMBER_OF_TX_CHANNELS; i++) { + char attr[64]; + + phy->tx_chan_ctx[i].phy = phy; + phy->tx_chan_ctx[i].channel = i; + + sprintf(attr, "tx%d_advanced_dpd_status", i); + debugfs_create_file(attr, 0444, + iio_get_debugfs_dentry(indio_dev), + &phy->tx_chan_ctx[i], + &adrv9025_tx_advanced_dpd_status_fops); + } + return 0; } @@ -3293,7 +3393,7 @@ static int adrv9025_probe(struct spi_device *spi) phy->spi_device_id = id; phy->dev_clk = clk; phy->jdev = jdev; - phy->agcConfig = kzalloc(sizeof(adi_adrv9025_AgcCfg_t), GFP_KERNEL); + phy->agcConfig = devm_kzalloc(&spi->dev, sizeof(adi_adrv9025_AgcCfg_t), GFP_KERNEL); if (!(phy->agcConfig)) return -ENOMEM; phy->dpdModelConfig = devm_kzalloc(&spi->dev, sizeof(adi_adrv9025_DpdModelConfig_v2_t), GFP_KERNEL); diff --git a/drivers/iio/adc/adrv902x/adrv9025.h b/drivers/iio/adc/adrv902x/adrv9025.h index 9c66193c29c1ae..7827afcdbd3997 100644 --- a/drivers/iio/adc/adrv902x/adrv9025.h +++ b/drivers/iio/adc/adrv902x/adrv9025.h @@ -58,6 +58,7 @@ enum debugfs_cmd { DBGFS_TX1_DPD_STATUS, DBGFS_TX2_DPD_STATUS, DBGFS_TX3_DPD_STATUS, + DBGFS_ADVANCED_DPD_STATUS, }; enum adrv9025_rx_ext_info { @@ -109,6 +110,11 @@ struct adrv9025_debugfs_entry { u8 cmd; }; +struct adrv9025_tx_chan_ctx { + struct adrv9025_rf_phy *phy; + u8 channel; +}; + enum adrv9025_clocks { RX_SAMPL_CLK, TX_SAMPL_CLK, @@ -172,6 +178,9 @@ struct adrv9025_rf_phy { adi_adrv9025_DpdModelConfig_v2_t *dpdModelConfig; adi_adrv9025_TxChannels_e dpdTxChannel; adi_adrv9025_DpdTrackingConfig_t *dpdTrackingConfig; + + /* TX channel context for debugfs */ + struct adrv9025_tx_chan_ctx tx_chan_ctx[4]; }; int adrv9025_hdl_loopback(struct adrv9025_rf_phy *phy, bool enable);