Skip to content

Commit

Permalink
iio: adc: cf_axi_adc_core: Support for EXT SYNC
Browse files Browse the repository at this point in the history
This patch adds a new device attributes 'sync_start_enable' and
'sync_start_enable_available' reading the later returns the available
modes which depend on HDL core synthesis parameters.
The options are explained below. Reading 'sync_start_enable' returns
either 'arm' while waiting for the external synchronization signal
or 'disarm' otherwise.

 - arm: Setting this bit will arm the trigger mechanism sensitive to an
	external sync signal. Once the external sync signal goes high
	it synchronizes channels within a DAC, and across multiple
	instances. This bit has an effect only the EXT_SYNC
	synthesis parameter is set. This bit self clears.

 - disarm: Setting this bit will disarm the trigger mechanism
	sensitive to an external sync signal. This bit has an
	effect only the EXT_SYNC synthesis parameter is set.
	This bit self clears.

 - trigger_manual: Setting this bit will issue an external sync event
	if it is hooked up inside the fabric. This bit has an effect
	only the EXT_SYNC synthesis parameter is set.
	This bit self clears.

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
  • Loading branch information
mhennerich authored and dbogdan committed Feb 2, 2022
1 parent 6b0d341 commit 0792eac
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 12 deletions.
9 changes: 9 additions & 0 deletions drivers/iio/adc/cf_axi_adc.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define ADI_CMOS_OR_LVDS_N (1 << 7)
#define ADI_PPS_RECEIVER_ENABLE (1 << 8)
#define ADI_SCALECORRECTION_ONLY (1 << 9)
#define ADI_EXT_SYNC (1 << 12)

#define ADI_REG_RSTN 0x0040
#define ADI_RSTN (1 << 0)
Expand All @@ -37,6 +38,11 @@
#define ADI_DDR_EDGESEL (1 << 1)
#define ADI_PIN_MODE (1 << 0)

#define ADI_REG_CNTRL_2 0x0048
#define ADI_EXT_SYNC_ARM (1 << 1)
#define ADI_EXT_SYNC_DISARM (1 << 2)
#define ADI_MANUAL_SYNC_REQUEST (1 << 8)

#define ADI_REG_CLK_FREQ 0x0054
#define ADI_CLK_FREQ(x) (((x) & 0xFFFFFFFF) << 0)
#define ADI_TO_CLK_FREQ(x) (((x) >> 0) & 0xFFFFFFFF)
Expand Down Expand Up @@ -65,6 +71,9 @@
#define ADI_DELAY_RDATA(x) (((x) & 0x1F) << 0)
#define ADI_TO_DELAY_RDATA(x) (((x) >> 0) & 0x1F)

#define ADI_REG_SYNC_STATUS 0x0068
#define ADI_ADC_SYNC_STATUS (1 << 0)

#define ADI_REG_DRP_CNTRL 0x0070
#define ADI_DRP_SEL (1 << 29)
#define ADI_DRP_RWN (1 << 28)
Expand Down
78 changes: 66 additions & 12 deletions drivers/iio/adc/cf_axi_adc_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct axiadc_state {
unsigned int have_slave_channels;
bool additional_channel;
bool dp_disable;
bool ext_sync_avail;

struct iio_chan_spec channels[AXIADC_MAX_CHANNEL];
};
Expand Down Expand Up @@ -400,42 +401,93 @@ static ssize_t axiadc_sampling_frequency_available(struct device *dev,
return ret;
}

static ssize_t axiadc_sync_start(struct device *dev,
static const char * const axiadc_sync_ctrls[] = {
"arm", "disarm", "trigger_manual",
};

static ssize_t axiadc_sync_start_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct axiadc_state *st = iio_priv(indio_dev);
bool state;
u32 reg;
int ret;

ret = strtobool(buf, &state);
ret = sysfs_match_string(axiadc_sync_ctrls, buf);
if (ret < 0)
return ret;

if (state) {
mutex_lock(&indio_dev->mlock);
mutex_lock(&indio_dev->mlock);
if (st->ext_sync_avail) {
switch (ret) {
case 0:
axiadc_write(st, ADI_REG_CNTRL_2, ADI_EXT_SYNC_ARM);
break;
case 1:
axiadc_write(st, ADI_REG_CNTRL_2, ADI_EXT_SYNC_DISARM);
break;
case 2:
axiadc_write(st, ADI_REG_CNTRL_2, ADI_MANUAL_SYNC_REQUEST);
break;
default:
ret = -EINVAL;
}
} else if (ret == 0) {
u32 reg;

reg = axiadc_read(st, ADI_REG_CNTRL);
axiadc_write(st, ADI_REG_CNTRL, reg | ADI_SYNC);
mutex_unlock(&indio_dev->mlock);
}
mutex_unlock(&indio_dev->mlock);

return len;
return ret < 0 ? ret : len;
}

static IIO_DEVICE_ATTR(sync_start_enable, 0200,
NULL,
axiadc_sync_start,
static ssize_t axiadc_sync_start_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct axiadc_state *st = iio_priv(indio_dev);
u32 reg;

switch ((u32)this_attr->address) {
case 0:
reg = axiadc_read(st, ADI_REG_SYNC_STATUS);

return sprintf(buf, "%s\n", reg & ADI_ADC_SYNC_STATUS ?
axiadc_sync_ctrls[0] : axiadc_sync_ctrls[1]);
case 1:
if (st->ext_sync_avail)
return sprintf(buf, "arm disarm trigger_manual\n");
else
return sprintf(buf, "arm\n");
default:
return -EINVAL;
}

return -EINVAL;
}

static IIO_DEVICE_ATTR(sync_start_enable, 0644,
axiadc_sync_start_show,
axiadc_sync_start_store,
0);

static IIO_DEVICE_ATTR(sync_start_enable_available, 0444,
axiadc_sync_start_show,
NULL,
1);

static IIO_DEVICE_ATTR(in_voltage_sampling_frequency_available, S_IRUGO,
axiadc_sampling_frequency_available,
NULL,
0);

static struct attribute *axiadc_attributes[] = {
&iio_dev_attr_sync_start_enable.dev_attr.attr,
&iio_dev_attr_sync_start_enable_available.dev_attr.attr,
&iio_dev_attr_in_voltage_sampling_frequency_available.dev_attr.attr,
NULL,
};
Expand Down Expand Up @@ -1020,7 +1072,7 @@ static int axiadc_probe(struct platform_device *pdev)
struct resource *mem;
struct axiadc_spidev axiadc_spidev;
struct axiadc_converter *conv;
unsigned int skip = 1;
unsigned int config, skip = 1;
int ret;

dev_dbg(&pdev->dev, "Device Tree Probing \'%s\'\n",
Expand Down Expand Up @@ -1076,6 +1128,8 @@ static int axiadc_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, indio_dev);

config = axiadc_read(st, ADI_REG_CONFIG);
st->ext_sync_avail = !!(config & ADI_EXT_SYNC);
st->dp_disable = false; /* FIXME: resolve later which reg & bit to read for this */

conv = to_converter(st->dev_spi);
Expand Down

0 comments on commit 0792eac

Please sign in to comment.