iio: adc: adi-axi-adc: support digital interface calibration
Implement the new IIO backend APIs for calibrating the data digital interfaces. While at it, removed the tabs in 'struct adi_axi_adc_state' and used spaces for the members. Signed-off-by: Nuno Sa <nuno.sa@analog.com> Link: https://lore.kernel.org/r/20240426-ad9467-new-features-v2-6-6361fc3ba1cc@analog.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
fbc186055b
commit
7ecb8ee5c9
@ -7,11 +7,13 @@
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
@ -37,6 +39,9 @@
|
||||
#define ADI_AXI_REG_RSTN_MMCM_RSTN BIT(1)
|
||||
#define ADI_AXI_REG_RSTN_RSTN BIT(0)
|
||||
|
||||
#define ADI_AXI_ADC_REG_CTRL 0x0044
|
||||
#define ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK BIT(1)
|
||||
|
||||
/* ADC Channel controls */
|
||||
|
||||
#define ADI_AXI_REG_CHAN_CTRL(c) (0x0400 + (c) * 0x40)
|
||||
@ -51,14 +56,28 @@
|
||||
#define ADI_AXI_REG_CHAN_CTRL_PN_TYPE_OWR BIT(1)
|
||||
#define ADI_AXI_REG_CHAN_CTRL_ENABLE BIT(0)
|
||||
|
||||
#define ADI_AXI_ADC_REG_CHAN_STATUS(c) (0x0404 + (c) * 0x40)
|
||||
#define ADI_AXI_ADC_CHAN_STAT_PN_MASK GENMASK(2, 1)
|
||||
|
||||
#define ADI_AXI_ADC_REG_CHAN_CTRL_3(c) (0x0418 + (c) * 0x40)
|
||||
#define ADI_AXI_ADC_CHAN_PN_SEL_MASK GENMASK(19, 16)
|
||||
|
||||
/* IO Delays */
|
||||
#define ADI_AXI_ADC_REG_DELAY(l) (0x0800 + (l) * 0x4)
|
||||
#define AXI_ADC_DELAY_CTRL_MASK GENMASK(4, 0)
|
||||
|
||||
#define ADI_AXI_ADC_MAX_IO_NUM_LANES 15
|
||||
|
||||
#define ADI_AXI_REG_CHAN_CTRL_DEFAULTS \
|
||||
(ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT | \
|
||||
ADI_AXI_REG_CHAN_CTRL_FMT_EN | \
|
||||
ADI_AXI_REG_CHAN_CTRL_ENABLE)
|
||||
|
||||
struct adi_axi_adc_state {
|
||||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
/* lock to protect multiple accesses to the device registers */
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
static int axi_adc_enable(struct iio_backend *back)
|
||||
@ -104,6 +123,100 @@ static int axi_adc_data_format_set(struct iio_backend *back, unsigned int chan,
|
||||
ADI_AXI_REG_CHAN_CTRL_FMT_MASK, val);
|
||||
}
|
||||
|
||||
static int axi_adc_data_sample_trigger(struct iio_backend *back,
|
||||
enum iio_backend_sample_trigger trigger)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
|
||||
switch (trigger) {
|
||||
case IIO_BACKEND_SAMPLE_TRIGGER_EDGE_RISING:
|
||||
return regmap_clear_bits(st->regmap, ADI_AXI_ADC_REG_CTRL,
|
||||
ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK);
|
||||
case IIO_BACKEND_SAMPLE_TRIGGER_EDGE_FALLING:
|
||||
return regmap_set_bits(st->regmap, ADI_AXI_ADC_REG_CTRL,
|
||||
ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_adc_iodelays_set(struct iio_backend *back, unsigned int lane,
|
||||
unsigned int tap)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (tap > FIELD_MAX(AXI_ADC_DELAY_CTRL_MASK))
|
||||
return -EINVAL;
|
||||
if (lane > ADI_AXI_ADC_MAX_IO_NUM_LANES)
|
||||
return -EINVAL;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
ret = regmap_write(st->regmap, ADI_AXI_ADC_REG_DELAY(lane), tap);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* If readback is ~0, that means there are issues with the
|
||||
* delay_clk.
|
||||
*/
|
||||
ret = regmap_read(st->regmap, ADI_AXI_ADC_REG_DELAY(lane), &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (val == U32_MAX)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axi_adc_test_pattern_set(struct iio_backend *back,
|
||||
unsigned int chan,
|
||||
enum iio_backend_test_pattern pattern)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
|
||||
switch (pattern) {
|
||||
case IIO_BACKEND_NO_TEST_PATTERN:
|
||||
/* nothing to do */
|
||||
return 0;
|
||||
case IIO_BACKEND_ADI_PRBS_9A:
|
||||
return regmap_update_bits(st->regmap, ADI_AXI_ADC_REG_CHAN_CTRL_3(chan),
|
||||
ADI_AXI_ADC_CHAN_PN_SEL_MASK,
|
||||
FIELD_PREP(ADI_AXI_ADC_CHAN_PN_SEL_MASK, 0));
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_adc_chan_status(struct iio_backend *back, unsigned int chan,
|
||||
bool *error)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
/* reset test bits by setting them */
|
||||
ret = regmap_write(st->regmap, ADI_AXI_ADC_REG_CHAN_STATUS(chan),
|
||||
ADI_AXI_ADC_CHAN_STAT_PN_MASK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* let's give enough time to validate or erroring the incoming pattern */
|
||||
fsleep(1000);
|
||||
|
||||
ret = regmap_read(st->regmap, ADI_AXI_ADC_REG_CHAN_STATUS(chan), &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ADI_AXI_ADC_CHAN_STAT_PN_MASK & val)
|
||||
*error = true;
|
||||
else
|
||||
*error = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axi_adc_chan_enable(struct iio_backend *back, unsigned int chan)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
@ -152,6 +265,10 @@ static const struct iio_backend_ops adi_axi_adc_generic = {
|
||||
.chan_disable = axi_adc_chan_disable,
|
||||
.request_buffer = axi_adc_request_buffer,
|
||||
.free_buffer = axi_adc_free_buffer,
|
||||
.data_sample_trigger = axi_adc_data_sample_trigger,
|
||||
.iodelay_set = axi_adc_iodelays_set,
|
||||
.test_pattern_set = axi_adc_test_pattern_set,
|
||||
.chan_status = axi_adc_chan_status,
|
||||
};
|
||||
|
||||
static int adi_axi_adc_probe(struct platform_device *pdev)
|
||||
|
Loading…
Reference in New Issue
Block a user