mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
iio: xilinx-xadc: Add basic support for Ultrascale System Monitor
The xilinx-xadc IIO driver currently has support for the XADC in the Xilinx 7 series FPGAs. The system-monitor is the equivalent to the XADC in the Xilinx UltraScale and UltraScale+ FPGAs. The IP designers did a good job at maintaining backwards compatibility and only minor changes are required to add basic support for the system-monitor core. The non backwards compatible changes are: * Register map offset was moved from 0x200 to 0x400 * Only one ADC compared to two in the XADC * 10 bit ADC instead of 12 bit ADC * Two of the channels monitor different supplies Add the necessary logic to accommodate these changes to support the system-monitor in the XADC driver. Note that this patch does not include support for some new features found in the system-monitor like additional alarms, user supply monitoring and secondary system-monitor access. This might be added at a later time. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Tested-by: Anand Ashok Dumbre <anandash@xilinx.com> Reviewed-by: Anand Ashok Dumbre <anandash@xilinx.com> Link: https://lore.kernel.org/r/20200922134624.13191-2-lars@metafoo.de Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
d0dc4c80b9
commit
c2b7720a79
4 changed files with 171 additions and 58 deletions
|
@ -1228,8 +1228,15 @@ config XILINX_XADC
|
|||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to have support for the Xilinx XADC. The driver does support
|
||||
both the ZYNQ interface to the XADC as well as the AXI-XADC interface.
|
||||
Say yes here to have support for the Xilinx 7 Series XADC or
|
||||
UltraScale/UltraScale+ System Management Wizard.
|
||||
|
||||
For the 7 Series the driver does support both the ZYNQ interface
|
||||
to the XADC as well as the AXI-XADC interface.
|
||||
|
||||
The driver also support the Xilinx System Management Wizard IP core
|
||||
that can be used to access the System Monitor ADC on the Xilinx
|
||||
UltraScale and UltraScale+ FPGAs.
|
||||
|
||||
The driver can also be build as a module. If so, the module will be called
|
||||
xilinx-xadc.
|
||||
|
|
|
@ -92,7 +92,12 @@ static const unsigned int XADC_ZYNQ_UNMASK_TIMEOUT = 500;
|
|||
#define XADC_AXI_REG_GIER 0x5c
|
||||
#define XADC_AXI_REG_IPISR 0x60
|
||||
#define XADC_AXI_REG_IPIER 0x68
|
||||
#define XADC_AXI_ADC_REG_OFFSET 0x200
|
||||
|
||||
/* 7 Series */
|
||||
#define XADC_7S_AXI_ADC_REG_OFFSET 0x200
|
||||
|
||||
/* UltraScale */
|
||||
#define XADC_US_AXI_ADC_REG_OFFSET 0x400
|
||||
|
||||
#define XADC_AXI_RESET_MAGIC 0xa
|
||||
#define XADC_AXI_GIER_ENABLE BIT(31)
|
||||
|
@ -447,6 +452,12 @@ static const struct xadc_ops xadc_zynq_ops = {
|
|||
.get_dclk_rate = xadc_zynq_get_dclk_rate,
|
||||
.interrupt_handler = xadc_zynq_interrupt_handler,
|
||||
.update_alarm = xadc_zynq_update_alarm,
|
||||
.type = XADC_TYPE_S7,
|
||||
};
|
||||
|
||||
static const unsigned int xadc_axi_reg_offsets[] = {
|
||||
[XADC_TYPE_S7] = XADC_7S_AXI_ADC_REG_OFFSET,
|
||||
[XADC_TYPE_US] = XADC_US_AXI_ADC_REG_OFFSET,
|
||||
};
|
||||
|
||||
static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg,
|
||||
|
@ -454,7 +465,8 @@ static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg,
|
|||
{
|
||||
uint32_t val32;
|
||||
|
||||
xadc_read_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, &val32);
|
||||
xadc_read_reg(xadc, xadc_axi_reg_offsets[xadc->ops->type] + reg * 4,
|
||||
&val32);
|
||||
*val = val32 & 0xffff;
|
||||
|
||||
return 0;
|
||||
|
@ -463,7 +475,8 @@ static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg,
|
|||
static int xadc_axi_write_adc_reg(struct xadc *xadc, unsigned int reg,
|
||||
uint16_t val)
|
||||
{
|
||||
xadc_write_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, val);
|
||||
xadc_write_reg(xadc, xadc_axi_reg_offsets[xadc->ops->type] + reg * 4,
|
||||
val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -541,7 +554,7 @@ static unsigned long xadc_axi_get_dclk(struct xadc *xadc)
|
|||
return clk_get_rate(xadc->clk);
|
||||
}
|
||||
|
||||
static const struct xadc_ops xadc_axi_ops = {
|
||||
static const struct xadc_ops xadc_7s_axi_ops = {
|
||||
.read = xadc_axi_read_adc_reg,
|
||||
.write = xadc_axi_write_adc_reg,
|
||||
.setup = xadc_axi_setup,
|
||||
|
@ -549,6 +562,18 @@ static const struct xadc_ops xadc_axi_ops = {
|
|||
.update_alarm = xadc_axi_update_alarm,
|
||||
.interrupt_handler = xadc_axi_interrupt_handler,
|
||||
.flags = XADC_FLAGS_BUFFERED,
|
||||
.type = XADC_TYPE_S7,
|
||||
};
|
||||
|
||||
static const struct xadc_ops xadc_us_axi_ops = {
|
||||
.read = xadc_axi_read_adc_reg,
|
||||
.write = xadc_axi_write_adc_reg,
|
||||
.setup = xadc_axi_setup,
|
||||
.get_dclk_rate = xadc_axi_get_dclk,
|
||||
.update_alarm = xadc_axi_update_alarm,
|
||||
.interrupt_handler = xadc_axi_interrupt_handler,
|
||||
.flags = XADC_FLAGS_BUFFERED,
|
||||
.type = XADC_TYPE_US,
|
||||
};
|
||||
|
||||
static int _xadc_update_adc_reg(struct xadc *xadc, unsigned int reg,
|
||||
|
@ -732,6 +757,15 @@ static int xadc_power_adc_b(struct xadc *xadc, unsigned int seq_mode)
|
|||
{
|
||||
uint16_t val;
|
||||
|
||||
/*
|
||||
* As per datasheet the power-down bits are don't care in the
|
||||
* UltraScale, but as per reality setting the power-down bit for the
|
||||
* non-existing ADC-B powers down the main ADC, so just return and don't
|
||||
* do anything.
|
||||
*/
|
||||
if (xadc->ops->type == XADC_TYPE_US)
|
||||
return 0;
|
||||
|
||||
/* Powerdown the ADC-B when it is not needed. */
|
||||
switch (seq_mode) {
|
||||
case XADC_CONF1_SEQ_SIMULTANEOUS:
|
||||
|
@ -751,6 +785,10 @@ static int xadc_get_seq_mode(struct xadc *xadc, unsigned long scan_mode)
|
|||
{
|
||||
unsigned int aux_scan_mode = scan_mode >> 16;
|
||||
|
||||
/* UltraScale has only one ADC and supports only continuous mode */
|
||||
if (xadc->ops->type == XADC_TYPE_US)
|
||||
return XADC_CONF1_SEQ_CONTINUOUS;
|
||||
|
||||
if (xadc->external_mux_mode == XADC_EXTERNAL_MUX_DUAL)
|
||||
return XADC_CONF1_SEQ_SIMULTANEOUS;
|
||||
|
||||
|
@ -863,6 +901,7 @@ static int xadc_read_raw(struct iio_dev *indio_dev,
|
|||
struct iio_chan_spec const *chan, int *val, int *val2, long info)
|
||||
{
|
||||
struct xadc *xadc = iio_priv(indio_dev);
|
||||
unsigned int bits = chan->scan_type.realbits;
|
||||
uint16_t val16;
|
||||
int ret;
|
||||
|
||||
|
@ -874,17 +913,17 @@ static int xadc_read_raw(struct iio_dev *indio_dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val16 >>= 4;
|
||||
val16 >>= chan->scan_type.shift;
|
||||
if (chan->scan_type.sign == 'u')
|
||||
*val = val16;
|
||||
else
|
||||
*val = sign_extend32(val16, 11);
|
||||
*val = sign_extend32(val16, bits - 1);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
/* V = (val * 3.0) / 4096 */
|
||||
/* V = (val * 3.0) / 2**bits */
|
||||
switch (chan->address) {
|
||||
case XADC_REG_VCCINT:
|
||||
case XADC_REG_VCCAUX:
|
||||
|
@ -900,19 +939,19 @@ static int xadc_read_raw(struct iio_dev *indio_dev,
|
|||
*val = 1000;
|
||||
break;
|
||||
}
|
||||
*val2 = 12;
|
||||
*val2 = chan->scan_type.realbits;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
case IIO_TEMP:
|
||||
/* Temp in C = (val * 503.975) / 4096 - 273.15 */
|
||||
/* Temp in C = (val * 503.975) / 2**bits - 273.15 */
|
||||
*val = 503975;
|
||||
*val2 = 12;
|
||||
*val2 = bits;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
/* Only the temperature channel has an offset */
|
||||
*val = -((273150 << 12) / 503975);
|
||||
*val = -((273150 << bits) / 503975);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = xadc_read_samplerate(xadc);
|
||||
|
@ -1001,7 +1040,7 @@ static const struct iio_event_spec xadc_voltage_events[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define XADC_CHAN_TEMP(_chan, _scan_index, _addr) { \
|
||||
#define XADC_CHAN_TEMP(_chan, _scan_index, _addr, _bits) { \
|
||||
.type = IIO_TEMP, \
|
||||
.indexed = 1, \
|
||||
.channel = (_chan), \
|
||||
|
@ -1015,14 +1054,14 @@ static const struct iio_event_spec xadc_voltage_events[] = {
|
|||
.scan_index = (_scan_index), \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 12, \
|
||||
.realbits = (_bits), \
|
||||
.storagebits = 16, \
|
||||
.shift = 4, \
|
||||
.shift = 16 - (_bits), \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) { \
|
||||
#define XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, _bits, _ext, _alarm) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = (_chan), \
|
||||
|
@ -1035,41 +1074,82 @@ static const struct iio_event_spec xadc_voltage_events[] = {
|
|||
.scan_index = (_scan_index), \
|
||||
.scan_type = { \
|
||||
.sign = ((_addr) == XADC_REG_VREFN) ? 's' : 'u', \
|
||||
.realbits = 12, \
|
||||
.realbits = (_bits), \
|
||||
.storagebits = 16, \
|
||||
.shift = 4, \
|
||||
.shift = 16 - (_bits), \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
.extend_name = _ext, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec xadc_channels[] = {
|
||||
XADC_CHAN_TEMP(0, 8, XADC_REG_TEMP),
|
||||
XADC_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true),
|
||||
XADC_CHAN_VOLTAGE(1, 10, XADC_REG_VCCAUX, "vccaux", true),
|
||||
XADC_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true),
|
||||
XADC_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true),
|
||||
XADC_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true),
|
||||
XADC_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccoddr", true),
|
||||
XADC_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false),
|
||||
XADC_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false),
|
||||
XADC_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false),
|
||||
XADC_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false),
|
||||
XADC_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false),
|
||||
/* 7 Series */
|
||||
#define XADC_7S_CHAN_TEMP(_chan, _scan_index, _addr) \
|
||||
XADC_CHAN_TEMP(_chan, _scan_index, _addr, 12)
|
||||
#define XADC_7S_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) \
|
||||
XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, 12, _ext, _alarm)
|
||||
|
||||
static const struct iio_chan_spec xadc_7s_channels[] = {
|
||||
XADC_7S_CHAN_TEMP(0, 8, XADC_REG_TEMP),
|
||||
XADC_7S_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true),
|
||||
XADC_7S_CHAN_VOLTAGE(1, 10, XADC_REG_VCCAUX, "vccaux", true),
|
||||
XADC_7S_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true),
|
||||
XADC_7S_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true),
|
||||
XADC_7S_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true),
|
||||
XADC_7S_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccoddr", true),
|
||||
XADC_7S_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false),
|
||||
XADC_7S_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false),
|
||||
XADC_7S_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false),
|
||||
XADC_7S_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false),
|
||||
};
|
||||
|
||||
/* UltraScale */
|
||||
#define XADC_US_CHAN_TEMP(_chan, _scan_index, _addr) \
|
||||
XADC_CHAN_TEMP(_chan, _scan_index, _addr, 10)
|
||||
#define XADC_US_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) \
|
||||
XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, 10, _ext, _alarm)
|
||||
|
||||
static const struct iio_chan_spec xadc_us_channels[] = {
|
||||
XADC_US_CHAN_TEMP(0, 8, XADC_REG_TEMP),
|
||||
XADC_US_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true),
|
||||
XADC_US_CHAN_VOLTAGE(1, 10, XADC_REG_VCCAUX, "vccaux", true),
|
||||
XADC_US_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true),
|
||||
XADC_US_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpsintlp", true),
|
||||
XADC_US_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpsintfp", true),
|
||||
XADC_US_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccpsaux", true),
|
||||
XADC_US_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false),
|
||||
XADC_US_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false),
|
||||
XADC_US_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false),
|
||||
XADC_US_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false),
|
||||
};
|
||||
|
||||
static const struct iio_info xadc_info = {
|
||||
|
@ -1083,8 +1163,16 @@ static const struct iio_info xadc_info = {
|
|||
};
|
||||
|
||||
static const struct of_device_id xadc_of_match_table[] = {
|
||||
{ .compatible = "xlnx,zynq-xadc-1.00.a", (void *)&xadc_zynq_ops },
|
||||
{ .compatible = "xlnx,axi-xadc-1.00.a", (void *)&xadc_axi_ops },
|
||||
{
|
||||
.compatible = "xlnx,zynq-xadc-1.00.a",
|
||||
.data = &xadc_zynq_ops
|
||||
}, {
|
||||
.compatible = "xlnx,axi-xadc-1.00.a",
|
||||
.data = &xadc_7s_axi_ops
|
||||
}, {
|
||||
.compatible = "xlnx,system-management-wiz-1.3",
|
||||
.data = &xadc_us_axi_ops
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, xadc_of_match_table);
|
||||
|
@ -1094,8 +1182,10 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
|
|||
{
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
struct xadc *xadc = iio_priv(indio_dev);
|
||||
const struct iio_chan_spec *channel_templates;
|
||||
struct iio_chan_spec *channels, *chan;
|
||||
struct device_node *chan_node, *child;
|
||||
unsigned int max_channels;
|
||||
unsigned int num_channels;
|
||||
const char *external_mux;
|
||||
u32 ext_mux_chan;
|
||||
|
@ -1136,9 +1226,15 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
|
|||
|
||||
*conf |= XADC_CONF0_MUX | XADC_CONF0_CHAN(ext_mux_chan);
|
||||
}
|
||||
|
||||
channels = devm_kmemdup(dev, xadc_channels,
|
||||
sizeof(xadc_channels), GFP_KERNEL);
|
||||
if (xadc->ops->type == XADC_TYPE_S7) {
|
||||
channel_templates = xadc_7s_channels;
|
||||
max_channels = ARRAY_SIZE(xadc_7s_channels);
|
||||
} else {
|
||||
channel_templates = xadc_us_channels;
|
||||
max_channels = ARRAY_SIZE(xadc_us_channels);
|
||||
}
|
||||
channels = devm_kmemdup(dev, channel_templates,
|
||||
sizeof(channels[0]) * max_channels, GFP_KERNEL);
|
||||
if (!channels)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1148,7 +1244,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
|
|||
chan_node = of_get_child_by_name(np, "xlnx,channels");
|
||||
if (chan_node) {
|
||||
for_each_child_of_node(chan_node, child) {
|
||||
if (num_channels >= ARRAY_SIZE(xadc_channels)) {
|
||||
if (num_channels >= max_channels) {
|
||||
of_node_put(child);
|
||||
break;
|
||||
}
|
||||
|
@ -1184,6 +1280,11 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char * const xadc_type_names[] = {
|
||||
[XADC_TYPE_S7] = "xadc",
|
||||
[XADC_TYPE_US] = "xilinx-system-monitor",
|
||||
};
|
||||
|
||||
static int xadc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *id;
|
||||
|
@ -1222,7 +1323,7 @@ static int xadc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(xadc->base))
|
||||
return PTR_ERR(xadc->base);
|
||||
|
||||
indio_dev->name = "xadc";
|
||||
indio_dev->name = xadc_type_names[xadc->ops->type];
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &xadc_info;
|
||||
|
||||
|
|
|
@ -155,9 +155,6 @@ int xadc_write_event_config(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Register value is msb aligned, the lower 4 bits are ignored */
|
||||
#define XADC_THRESHOLD_VALUE_SHIFT 4
|
||||
|
||||
int xadc_read_event_value(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, enum iio_event_info info,
|
||||
|
@ -177,7 +174,8 @@ int xadc_read_event_value(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
*val >>= XADC_THRESHOLD_VALUE_SHIFT;
|
||||
/* MSB aligned */
|
||||
*val >>= 16 - chan->scan_type.realbits;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
@ -191,7 +189,8 @@ int xadc_write_event_value(struct iio_dev *indio_dev,
|
|||
struct xadc *xadc = iio_priv(indio_dev);
|
||||
int ret = 0;
|
||||
|
||||
val <<= XADC_THRESHOLD_VALUE_SHIFT;
|
||||
/* MSB aligned */
|
||||
val <<= 16 - chan->scan_type.realbits;
|
||||
|
||||
if (val < 0 || val > 0xffff)
|
||||
return -EINVAL;
|
||||
|
|
|
@ -70,6 +70,11 @@ struct xadc {
|
|||
int irq;
|
||||
};
|
||||
|
||||
enum xadc_type {
|
||||
XADC_TYPE_S7, /* Series 7 */
|
||||
XADC_TYPE_US, /* UltraScale and UltraScale+ */
|
||||
};
|
||||
|
||||
struct xadc_ops {
|
||||
int (*read)(struct xadc *xadc, unsigned int reg, uint16_t *val);
|
||||
int (*write)(struct xadc *xadc, unsigned int reg, uint16_t val);
|
||||
|
@ -80,6 +85,7 @@ struct xadc_ops {
|
|||
irqreturn_t (*interrupt_handler)(int irq, void *devid);
|
||||
|
||||
unsigned int flags;
|
||||
enum xadc_type type;
|
||||
};
|
||||
|
||||
static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
|
||||
|
|
Loading…
Reference in a new issue