The Xilinx XADC is a ADC that can be found in the series 7 FPGAs from Xilinx. The XADC has a DRP interface for communication. Currently two different frontends for the DRP interface exist. One that is only available on the ZYNQ family as a hardmacro in the SoC portion of the ZYNQ. The other one is available on all series 7 platforms and is a softmacro with a AXI interface. This driver supports both interfaces and internally has a small abstraction layer that hides the specifics of these interfaces from the main driver logic. The ADC has a couple of internal channels which are used for voltage and temperature monitoring of the FPGA as well as one primary and up to 16 channels auxiliary channels for measuring external voltages. The external auxiliary channels can either be directly connected each to one physical pin on the FPGA or they can make use of an external multiplexer which is responsible for multiplexing the external signals onto one pair of physical pins. The voltage and temperature monitoring channels also have an event capability which allows to generate a interrupt when their value falls below or raises above a set threshold. Buffered sampling mode is supported by the driver, but only for AXI-XADC since the ZYNQ XADC interface does not have capabilities for supporting buffer mode (no end-of-conversion interrupt). If buffered mode is supported the driver will register two triggers. One "xadc-samplerate" trigger which will generate samples with the configured samplerate. And one "xadc-convst" trigger which will generate one sample each time the CONVST (conversion start) signal is asserted. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
		
			
				
	
	
		
			209 lines
		
	
	
	
		
			5.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			209 lines
		
	
	
	
		
			5.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Xilinx XADC driver
 | 
						|
 *
 | 
						|
 * Copyright 2013 Analog Devices Inc.
 | 
						|
 *  Author: Lars-Peter Clauen <lars@metafoo.de>
 | 
						|
 *
 | 
						|
 * Licensed under the GPL-2.
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef __IIO_XILINX_XADC__
 | 
						|
#define __IIO_XILINX_XADC__
 | 
						|
 | 
						|
#include <linux/interrupt.h>
 | 
						|
#include <linux/mutex.h>
 | 
						|
#include <linux/spinlock.h>
 | 
						|
 | 
						|
struct iio_dev;
 | 
						|
struct clk;
 | 
						|
struct xadc_ops;
 | 
						|
struct platform_device;
 | 
						|
 | 
						|
void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events);
 | 
						|
 | 
						|
int xadc_read_event_config(struct iio_dev *indio_dev,
 | 
						|
	const struct iio_chan_spec *chan, enum iio_event_type type,
 | 
						|
	enum iio_event_direction dir);
 | 
						|
int xadc_write_event_config(struct iio_dev *indio_dev,
 | 
						|
	const struct iio_chan_spec *chan, enum iio_event_type type,
 | 
						|
	enum iio_event_direction dir, int state);
 | 
						|
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,
 | 
						|
	int *val, int *val2);
 | 
						|
int xadc_write_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,
 | 
						|
	int val, int val2);
 | 
						|
 | 
						|
enum xadc_external_mux_mode {
 | 
						|
	XADC_EXTERNAL_MUX_NONE,
 | 
						|
	XADC_EXTERNAL_MUX_SINGLE,
 | 
						|
	XADC_EXTERNAL_MUX_DUAL,
 | 
						|
};
 | 
						|
 | 
						|
struct xadc {
 | 
						|
	void __iomem *base;
 | 
						|
	struct clk *clk;
 | 
						|
 | 
						|
	const struct xadc_ops *ops;
 | 
						|
 | 
						|
	uint16_t threshold[16];
 | 
						|
	uint16_t temp_hysteresis;
 | 
						|
	unsigned int alarm_mask;
 | 
						|
 | 
						|
	uint16_t *data;
 | 
						|
 | 
						|
	struct iio_trigger *trigger;
 | 
						|
	struct iio_trigger *convst_trigger;
 | 
						|
	struct iio_trigger *samplerate_trigger;
 | 
						|
 | 
						|
	enum xadc_external_mux_mode external_mux_mode;
 | 
						|
 | 
						|
	unsigned int zynq_alarm;
 | 
						|
	unsigned int zynq_masked_alarm;
 | 
						|
	unsigned int zynq_intmask;
 | 
						|
	struct delayed_work zynq_unmask_work;
 | 
						|
 | 
						|
	struct mutex mutex;
 | 
						|
	spinlock_t lock;
 | 
						|
 | 
						|
	struct completion completion;
 | 
						|
};
 | 
						|
 | 
						|
struct xadc_ops {
 | 
						|
	int (*read)(struct xadc *, unsigned int, uint16_t *);
 | 
						|
	int (*write)(struct xadc *, unsigned int, uint16_t);
 | 
						|
	int (*setup)(struct platform_device *pdev, struct iio_dev *indio_dev,
 | 
						|
			int irq);
 | 
						|
	void (*update_alarm)(struct xadc *, unsigned int);
 | 
						|
	unsigned long (*get_dclk_rate)(struct xadc *);
 | 
						|
	irqreturn_t (*interrupt_handler)(int, void *);
 | 
						|
	irqreturn_t (*threaded_interrupt_handler)(int, void *);
 | 
						|
 | 
						|
	unsigned int flags;
 | 
						|
};
 | 
						|
 | 
						|
static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
 | 
						|
	uint16_t *val)
 | 
						|
{
 | 
						|
	lockdep_assert_held(&xadc->mutex);
 | 
						|
	return xadc->ops->read(xadc, reg, val);
 | 
						|
}
 | 
						|
 | 
						|
static inline int _xadc_write_adc_reg(struct xadc *xadc, unsigned int reg,
 | 
						|
	uint16_t val)
 | 
						|
{
 | 
						|
	lockdep_assert_held(&xadc->mutex);
 | 
						|
	return xadc->ops->write(xadc, reg, val);
 | 
						|
}
 | 
						|
 | 
						|
static inline int xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
 | 
						|
	uint16_t *val)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	mutex_lock(&xadc->mutex);
 | 
						|
	ret = _xadc_read_adc_reg(xadc, reg, val);
 | 
						|
	mutex_unlock(&xadc->mutex);
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
static inline int xadc_write_adc_reg(struct xadc *xadc, unsigned int reg,
 | 
						|
	uint16_t val)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	mutex_lock(&xadc->mutex);
 | 
						|
	ret = _xadc_write_adc_reg(xadc, reg, val);
 | 
						|
	mutex_unlock(&xadc->mutex);
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
/* XADC hardmacro register definitions */
 | 
						|
#define XADC_REG_TEMP		0x00
 | 
						|
#define XADC_REG_VCCINT		0x01
 | 
						|
#define XADC_REG_VCCAUX		0x02
 | 
						|
#define XADC_REG_VPVN		0x03
 | 
						|
#define XADC_REG_VREFP		0x04
 | 
						|
#define XADC_REG_VREFN		0x05
 | 
						|
#define XADC_REG_VCCBRAM	0x06
 | 
						|
 | 
						|
#define XADC_REG_VCCPINT	0x0d
 | 
						|
#define XADC_REG_VCCPAUX	0x0e
 | 
						|
#define XADC_REG_VCCO_DDR	0x0f
 | 
						|
#define XADC_REG_VAUX(x)	(0x10 + (x))
 | 
						|
 | 
						|
#define XADC_REG_MAX_TEMP	0x20
 | 
						|
#define XADC_REG_MAX_VCCINT	0x21
 | 
						|
#define XADC_REG_MAX_VCCAUX	0x22
 | 
						|
#define XADC_REG_MAX_VCCBRAM	0x23
 | 
						|
#define XADC_REG_MIN_TEMP	0x24
 | 
						|
#define XADC_REG_MIN_VCCINT	0x25
 | 
						|
#define XADC_REG_MIN_VCCAUX	0x26
 | 
						|
#define XADC_REG_MIN_VCCBRAM	0x27
 | 
						|
#define XADC_REG_MAX_VCCPINT	0x28
 | 
						|
#define XADC_REG_MAX_VCCPAUX	0x29
 | 
						|
#define XADC_REG_MAX_VCCO_DDR	0x2a
 | 
						|
#define XADC_REG_MIN_VCCPINT	0x2b
 | 
						|
#define XADC_REG_MIN_VCCPAUX	0x2c
 | 
						|
#define XADC_REG_MIN_VCCO_DDR	0x2d
 | 
						|
 | 
						|
#define XADC_REG_CONF0		0x40
 | 
						|
#define XADC_REG_CONF1		0x41
 | 
						|
#define XADC_REG_CONF2		0x42
 | 
						|
#define XADC_REG_SEQ(x)		(0x48 + (x))
 | 
						|
#define XADC_REG_INPUT_MODE(x)	(0x4c + (x))
 | 
						|
#define XADC_REG_THRESHOLD(x)	(0x50 + (x))
 | 
						|
 | 
						|
#define XADC_REG_FLAG		0x3f
 | 
						|
 | 
						|
#define XADC_CONF0_EC			BIT(9)
 | 
						|
#define XADC_CONF0_ACQ			BIT(8)
 | 
						|
#define XADC_CONF0_MUX			BIT(11)
 | 
						|
#define XADC_CONF0_CHAN(x)		(x)
 | 
						|
 | 
						|
#define XADC_CONF1_SEQ_MASK		(0xf << 12)
 | 
						|
#define XADC_CONF1_SEQ_DEFAULT		(0 << 12)
 | 
						|
#define XADC_CONF1_SEQ_SINGLE_PASS	(1 << 12)
 | 
						|
#define XADC_CONF1_SEQ_CONTINUOUS	(2 << 12)
 | 
						|
#define XADC_CONF1_SEQ_SINGLE_CHANNEL	(3 << 12)
 | 
						|
#define XADC_CONF1_SEQ_SIMULTANEOUS	(4 << 12)
 | 
						|
#define XADC_CONF1_SEQ_INDEPENDENT	(8 << 12)
 | 
						|
#define XADC_CONF1_ALARM_MASK		0x0f0f
 | 
						|
 | 
						|
#define XADC_CONF2_DIV_MASK	0xff00
 | 
						|
#define XADC_CONF2_DIV_OFFSET	8
 | 
						|
 | 
						|
#define XADC_CONF2_PD_MASK	(0x3 << 4)
 | 
						|
#define XADC_CONF2_PD_NONE	(0x0 << 4)
 | 
						|
#define XADC_CONF2_PD_ADC_B	(0x2 << 4)
 | 
						|
#define XADC_CONF2_PD_BOTH	(0x3 << 4)
 | 
						|
 | 
						|
#define XADC_ALARM_TEMP_MASK		BIT(0)
 | 
						|
#define XADC_ALARM_VCCINT_MASK		BIT(1)
 | 
						|
#define XADC_ALARM_VCCAUX_MASK		BIT(2)
 | 
						|
#define XADC_ALARM_OT_MASK		BIT(3)
 | 
						|
#define XADC_ALARM_VCCBRAM_MASK		BIT(4)
 | 
						|
#define XADC_ALARM_VCCPINT_MASK		BIT(5)
 | 
						|
#define XADC_ALARM_VCCPAUX_MASK		BIT(6)
 | 
						|
#define XADC_ALARM_VCCODDR_MASK		BIT(7)
 | 
						|
 | 
						|
#define XADC_THRESHOLD_TEMP_MAX		0x0
 | 
						|
#define XADC_THRESHOLD_VCCINT_MAX	0x1
 | 
						|
#define XADC_THRESHOLD_VCCAUX_MAX	0x2
 | 
						|
#define XADC_THRESHOLD_OT_MAX		0x3
 | 
						|
#define XADC_THRESHOLD_TEMP_MIN		0x4
 | 
						|
#define XADC_THRESHOLD_VCCINT_MIN	0x5
 | 
						|
#define XADC_THRESHOLD_VCCAUX_MIN	0x6
 | 
						|
#define XADC_THRESHOLD_OT_MIN		0x7
 | 
						|
#define XADC_THRESHOLD_VCCBRAM_MAX	0x8
 | 
						|
#define XADC_THRESHOLD_VCCPINT_MAX	0x9
 | 
						|
#define XADC_THRESHOLD_VCCPAUX_MAX	0xa
 | 
						|
#define XADC_THRESHOLD_VCCODDR_MAX	0xb
 | 
						|
#define XADC_THRESHOLD_VCCBRAM_MIN	0xc
 | 
						|
#define XADC_THRESHOLD_VCCPINT_MIN	0xd
 | 
						|
#define XADC_THRESHOLD_VCCPAUX_MIN	0xe
 | 
						|
#define XADC_THRESHOLD_VCCODDR_MIN	0xf
 | 
						|
 | 
						|
#endif
 |