Third IIO new drivers and cleanups series for 3.15.
New driver * Xilinx XADC driver - This has been ready for a while but was awaiting a device tree ack (or as it turns out 3+ weeks). Cleanup * Drop some unreachable code from mag3110 highlighted by smatch. Fix * vf610 - introduced this cycle - put a possible negative error code into an unsigned long. Another smatch find - this one promoted by guilt that Dan was busy fixing all our messups. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTGMrfAAoJEFSFNJnE9BaILFsP/iW3NlfWdk1JvdERTpvh4eRW zhhvje+ekn5zR5fwyOlpf7PgDW485sCQ6smVmkjiGvHVGK428Bg19NE2qGAEkaCu dlj0NhKDUWEy7yTixcuP9rPGOd7NFc5qsKfbHlMo9bHNdoKlo0KXOaY9vU8APNAC 0fKyioOqQkcRqejO/4E5GH4uquoDF3e+kPk2vlMBGuxlBeQf3t1Va7j7bP601ln2 YAd+P19s2H33Ujxvholyxad6wyM88W+sglJvM3rLvluGWXsQrnJWQPgD+RMjfvOT QOiyoA+dGuZogT7R3g22Ai6OmaxlXxKBXhutgfZ08VvOaJA0ZVyONvOYjdqQ+F/a UTg6WzkcVJSQdpbErHUEpR4p0n0Q/Whq7KAb1KGNkoe9cIiYGNcmHIg7+MsMtbZi GOGmEry4325ghBUULBfVNzUpQfGNHejw4f9gmngilU2lA7JHeyDUFNKWOKShUWMt nUUm41YsvI3Tj34+740UtldvZrpcvQ9lz6AFDh/xe3MnyLr68xwzc975x9PRr6L8 ZGCAbYeGBzVWDKM2Gri1uF0hVobEB58BsRmViPM4Bwqr8Y3bThSpl68wLYaLw9+d xXu/c+VqyPeubtMKHqSEWJH2NraKo1GFkfQCe2MsnKHTnKfykMQeOKlne21/UCpA mZ/daW65ZngKkI1I1552 =OSqU -----END PGP SIGNATURE----- Merge tag 'iio-for-3.15c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: Third IIO new drivers and cleanups series for 3.15. New driver * Xilinx XADC driver - This has been ready for a while but was awaiting a device tree ack (or as it turns out 3+ weeks). Cleanup * Drop some unreachable code from mag3110 highlighted by smatch. Fix * vf610 - introduced this cycle - put a possible negative error code into an unsigned long. Another smatch find - this one promoted by guilt that Dan was busy fixing all our messups.
This commit is contained in:
commit
d62994701b
8 changed files with 1925 additions and 2 deletions
113
Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt
Normal file
113
Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
Xilinx XADC device driver
|
||||||
|
|
||||||
|
This binding document describes the bindings for both of them since the
|
||||||
|
bindings are very similar. 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 binding document describes the bindings for both of them since
|
||||||
|
the bindings are very similar.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should be one of
|
||||||
|
* "xlnx,zynq-xadc-1.00.a": When using the ZYNQ device
|
||||||
|
configuration interface to interface to the XADC hardmacro.
|
||||||
|
* "xlnx,axi-xadc-1.00.a": When using the axi-xadc pcore to
|
||||||
|
interface to the XADC hardmacro.
|
||||||
|
- reg: Address and length of the register set for the device
|
||||||
|
- interrupts: Interrupt for the XADC control interface.
|
||||||
|
- clocks: When using the ZYNQ this must be the ZYNQ PCAP clock,
|
||||||
|
when using the AXI-XADC pcore this must be the clock that provides the
|
||||||
|
clock to the AXI bus interface of the core.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- interrupt-parent: phandle to the parent interrupt controller
|
||||||
|
- xlnx,external-mux:
|
||||||
|
* "none": No external multiplexer is used, this is the default
|
||||||
|
if the property is omitted.
|
||||||
|
* "single": External multiplexer mode is used with one
|
||||||
|
multiplexer.
|
||||||
|
* "dual": External multiplexer mode is used with two
|
||||||
|
multiplexers for simultaneous sampling.
|
||||||
|
- xlnx,external-mux-channel: Configures which pair of pins is used to
|
||||||
|
sample data in external mux mode.
|
||||||
|
Valid values for single external multiplexer mode are:
|
||||||
|
0: VP/VN
|
||||||
|
1: VAUXP[0]/VAUXN[0]
|
||||||
|
2: VAUXP[1]/VAUXN[1]
|
||||||
|
...
|
||||||
|
16: VAUXP[15]/VAUXN[15]
|
||||||
|
Valid values for dual external multiplexer mode are:
|
||||||
|
1: VAUXP[0]/VAUXN[0] - VAUXP[8]/VAUXN[8]
|
||||||
|
2: VAUXP[1]/VAUXN[1] - VAUXP[9]/VAUXN[9]
|
||||||
|
...
|
||||||
|
8: VAUXP[7]/VAUXN[7] - VAUXP[15]/VAUXN[15]
|
||||||
|
|
||||||
|
This property needs to be present if the device is configured for
|
||||||
|
external multiplexer mode (either single or dual). If the device is
|
||||||
|
not using external multiplexer mode the property is ignored.
|
||||||
|
- xnlx,channels: List of external channels that are connected to the ADC
|
||||||
|
Required properties:
|
||||||
|
* #address-cells: Should be 1.
|
||||||
|
* #size-cells: Should be 0.
|
||||||
|
|
||||||
|
The child nodes of this node represent the external channels which are
|
||||||
|
connected to the ADC. If the property is no present no external
|
||||||
|
channels will be assumed to be connected.
|
||||||
|
|
||||||
|
Each child node represents one channel and has the following
|
||||||
|
properties:
|
||||||
|
Required properties:
|
||||||
|
* reg: Pair of pins the the channel is connected to.
|
||||||
|
0: VP/VN
|
||||||
|
1: VAUXP[0]/VAUXN[0]
|
||||||
|
2: VAUXP[1]/VAUXN[1]
|
||||||
|
...
|
||||||
|
16: VAUXP[15]/VAUXN[15]
|
||||||
|
Note each channel number should only be used at most
|
||||||
|
once.
|
||||||
|
Optional properties:
|
||||||
|
* xlnx,bipolar: If set the channel is used in bipolar
|
||||||
|
mode.
|
||||||
|
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
xadc@f8007100 {
|
||||||
|
compatible = "xlnx,zynq-xadc-1.00.a";
|
||||||
|
reg = <0xf8007100 0x20>;
|
||||||
|
interrupts = <0 7 4>;
|
||||||
|
interrupt-parent = <&gic>;
|
||||||
|
clocks = <&pcap_clk>;
|
||||||
|
|
||||||
|
xlnx,channels {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
channel@0 {
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
channel@1 {
|
||||||
|
reg = <1>;
|
||||||
|
};
|
||||||
|
channel@8 {
|
||||||
|
reg = <8>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
xadc@43200000 {
|
||||||
|
compatible = "xlnx,axi-xadc-1.00.a";
|
||||||
|
reg = <0x43200000 0x1000>;
|
||||||
|
interrupts = <0 53 4>;
|
||||||
|
interrupt-parent = <&gic>;
|
||||||
|
clocks = <&fpga1_clk>;
|
||||||
|
|
||||||
|
xlnx,channels {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
channel@0 {
|
||||||
|
reg = <0>;
|
||||||
|
xlnx,bipolar;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -214,4 +214,17 @@ config VIPERBOARD_ADC
|
||||||
Say yes here to access the ADC part of the Nano River
|
Say yes here to access the ADC part of the Nano River
|
||||||
Technologies Viperboard.
|
Technologies Viperboard.
|
||||||
|
|
||||||
|
config XILINX_XADC
|
||||||
|
tristate "Xilinx XADC driver"
|
||||||
|
depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
|
||||||
|
depends on HAS_IOMEM
|
||||||
|
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.
|
||||||
|
|
||||||
|
The driver can also be build as a module. If so, the module will be called
|
||||||
|
xilinx-xadc.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -23,3 +23,5 @@ obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
|
||||||
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
|
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
|
||||||
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
|
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
|
||||||
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
|
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
|
||||||
|
xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o
|
||||||
|
obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o
|
||||||
|
|
|
@ -447,7 +447,7 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
|
||||||
{
|
{
|
||||||
struct vf610_adc *info = iio_priv(indio_dev);
|
struct vf610_adc *info = iio_priv(indio_dev);
|
||||||
unsigned int hc_cfg;
|
unsigned int hc_cfg;
|
||||||
unsigned long ret;
|
long ret;
|
||||||
|
|
||||||
switch (mask) {
|
switch (mask) {
|
||||||
case IIO_CHAN_INFO_RAW:
|
case IIO_CHAN_INFO_RAW:
|
||||||
|
|
1333
drivers/iio/adc/xilinx-xadc-core.c
Normal file
1333
drivers/iio/adc/xilinx-xadc-core.c
Normal file
File diff suppressed because it is too large
Load diff
254
drivers/iio/adc/xilinx-xadc-events.c
Normal file
254
drivers/iio/adc/xilinx-xadc-events.c
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
/*
|
||||||
|
* Xilinx XADC driver
|
||||||
|
*
|
||||||
|
* Copyright 2013 Analog Devices Inc.
|
||||||
|
* Author: Lars-Peter Clauen <lars@metafoo.de>
|
||||||
|
*
|
||||||
|
* Licensed under the GPL-2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/iio/events.h>
|
||||||
|
#include <linux/iio/iio.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
|
#include "xilinx-xadc.h"
|
||||||
|
|
||||||
|
static const struct iio_chan_spec *xadc_event_to_channel(
|
||||||
|
struct iio_dev *indio_dev, unsigned int event)
|
||||||
|
{
|
||||||
|
switch (event) {
|
||||||
|
case XADC_THRESHOLD_OT_MAX:
|
||||||
|
case XADC_THRESHOLD_TEMP_MAX:
|
||||||
|
return &indio_dev->channels[0];
|
||||||
|
case XADC_THRESHOLD_VCCINT_MAX:
|
||||||
|
case XADC_THRESHOLD_VCCAUX_MAX:
|
||||||
|
return &indio_dev->channels[event];
|
||||||
|
default:
|
||||||
|
return &indio_dev->channels[event-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
|
||||||
|
{
|
||||||
|
const struct iio_chan_spec *chan;
|
||||||
|
unsigned int offset;
|
||||||
|
|
||||||
|
/* Temperature threshold error, we don't handle this yet */
|
||||||
|
if (event == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (event < 4)
|
||||||
|
offset = event;
|
||||||
|
else
|
||||||
|
offset = event + 4;
|
||||||
|
|
||||||
|
chan = xadc_event_to_channel(indio_dev, event);
|
||||||
|
|
||||||
|
if (chan->type == IIO_TEMP) {
|
||||||
|
/*
|
||||||
|
* The temperature channel only supports over-temperature
|
||||||
|
* events.
|
||||||
|
*/
|
||||||
|
iio_push_event(indio_dev,
|
||||||
|
IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
|
||||||
|
IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
|
||||||
|
iio_get_time_ns());
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* For other channels we don't know whether it is a upper or
|
||||||
|
* lower threshold event. Userspace will have to check the
|
||||||
|
* channel value if it wants to know.
|
||||||
|
*/
|
||||||
|
iio_push_event(indio_dev,
|
||||||
|
IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
|
||||||
|
IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER),
|
||||||
|
iio_get_time_ns());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for_each_set_bit(i, &events, 8)
|
||||||
|
xadc_handle_event(indio_dev, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned xadc_get_threshold_offset(const struct iio_chan_spec *chan,
|
||||||
|
enum iio_event_direction dir)
|
||||||
|
{
|
||||||
|
unsigned int offset;
|
||||||
|
|
||||||
|
if (chan->type == IIO_TEMP) {
|
||||||
|
offset = XADC_THRESHOLD_OT_MAX;
|
||||||
|
} else {
|
||||||
|
if (chan->channel < 2)
|
||||||
|
offset = chan->channel + 1;
|
||||||
|
else
|
||||||
|
offset = chan->channel + 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir == IIO_EV_DIR_FALLING)
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int xadc_get_alarm_mask(const struct iio_chan_spec *chan)
|
||||||
|
{
|
||||||
|
if (chan->type == IIO_TEMP) {
|
||||||
|
return XADC_ALARM_OT_MASK;
|
||||||
|
} else {
|
||||||
|
switch (chan->channel) {
|
||||||
|
case 0:
|
||||||
|
return XADC_ALARM_VCCINT_MASK;
|
||||||
|
case 1:
|
||||||
|
return XADC_ALARM_VCCAUX_MASK;
|
||||||
|
case 2:
|
||||||
|
return XADC_ALARM_VCCBRAM_MASK;
|
||||||
|
case 3:
|
||||||
|
return XADC_ALARM_VCCPINT_MASK;
|
||||||
|
case 4:
|
||||||
|
return XADC_ALARM_VCCPAUX_MASK;
|
||||||
|
case 5:
|
||||||
|
return XADC_ALARM_VCCODDR_MASK;
|
||||||
|
default:
|
||||||
|
/* We will never get here */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct xadc *xadc = iio_priv(indio_dev);
|
||||||
|
|
||||||
|
return (bool)(xadc->alarm_mask & xadc_get_alarm_mask(chan));
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
unsigned int alarm = xadc_get_alarm_mask(chan);
|
||||||
|
struct xadc *xadc = iio_priv(indio_dev);
|
||||||
|
uint16_t cfg, old_cfg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&xadc->mutex);
|
||||||
|
|
||||||
|
if (state)
|
||||||
|
xadc->alarm_mask |= alarm;
|
||||||
|
else
|
||||||
|
xadc->alarm_mask &= ~alarm;
|
||||||
|
|
||||||
|
xadc->ops->update_alarm(xadc, xadc->alarm_mask);
|
||||||
|
|
||||||
|
ret = _xadc_read_adc_reg(xadc, XADC_REG_CONF1, &cfg);
|
||||||
|
if (ret)
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
|
old_cfg = cfg;
|
||||||
|
cfg |= XADC_CONF1_ALARM_MASK;
|
||||||
|
cfg &= ~((xadc->alarm_mask & 0xf0) << 4); /* bram, pint, paux, ddr */
|
||||||
|
cfg &= ~((xadc->alarm_mask & 0x08) >> 3); /* ot */
|
||||||
|
cfg &= ~((xadc->alarm_mask & 0x07) << 1); /* temp, vccint, vccaux */
|
||||||
|
if (old_cfg != cfg)
|
||||||
|
ret = _xadc_write_adc_reg(xadc, XADC_REG_CONF1, cfg);
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
mutex_unlock(&xadc->mutex);
|
||||||
|
|
||||||
|
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,
|
||||||
|
int *val, int *val2)
|
||||||
|
{
|
||||||
|
unsigned int offset = xadc_get_threshold_offset(chan, dir);
|
||||||
|
struct xadc *xadc = iio_priv(indio_dev);
|
||||||
|
|
||||||
|
switch (info) {
|
||||||
|
case IIO_EV_INFO_VALUE:
|
||||||
|
*val = xadc->threshold[offset];
|
||||||
|
break;
|
||||||
|
case IIO_EV_INFO_HYSTERESIS:
|
||||||
|
*val = xadc->temp_hysteresis;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*val >>= XADC_THRESHOLD_VALUE_SHIFT;
|
||||||
|
|
||||||
|
return IIO_VAL_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
unsigned int offset = xadc_get_threshold_offset(chan, dir);
|
||||||
|
struct xadc *xadc = iio_priv(indio_dev);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
val <<= XADC_THRESHOLD_VALUE_SHIFT;
|
||||||
|
|
||||||
|
if (val < 0 || val > 0xffff)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&xadc->mutex);
|
||||||
|
|
||||||
|
switch (info) {
|
||||||
|
case IIO_EV_INFO_VALUE:
|
||||||
|
xadc->threshold[offset] = val;
|
||||||
|
break;
|
||||||
|
case IIO_EV_INFO_HYSTERESIS:
|
||||||
|
xadc->temp_hysteresis = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mutex_unlock(&xadc->mutex);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan->type == IIO_TEMP) {
|
||||||
|
/*
|
||||||
|
* According to the datasheet we need to set the lower 4 bits to
|
||||||
|
* 0x3, otherwise 125 degree celsius will be used as the
|
||||||
|
* threshold.
|
||||||
|
*/
|
||||||
|
val |= 0x3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since we store the hysteresis as relative (to the threshold)
|
||||||
|
* value, but the hardware expects an absolute value we need to
|
||||||
|
* recalcualte this value whenever the hysteresis or the
|
||||||
|
* threshold changes.
|
||||||
|
*/
|
||||||
|
if (xadc->threshold[offset] < xadc->temp_hysteresis)
|
||||||
|
xadc->threshold[offset + 4] = 0;
|
||||||
|
else
|
||||||
|
xadc->threshold[offset + 4] = xadc->threshold[offset] -
|
||||||
|
xadc->temp_hysteresis;
|
||||||
|
ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset + 4),
|
||||||
|
xadc->threshold[offset + 4]);
|
||||||
|
if (ret)
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == IIO_EV_INFO_VALUE)
|
||||||
|
ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset), val);
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
mutex_unlock(&xadc->mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
209
drivers/iio/adc/xilinx-xadc.h
Normal file
209
drivers/iio/adc/xilinx-xadc.h
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
/*
|
||||||
|
* 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
|
|
@ -194,7 +194,6 @@ static int mag3110_read_raw(struct iio_dev *indio_dev,
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
return IIO_VAL_INT_PLUS_MICRO;
|
|
||||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||||
i = data->ctrl_reg1 >> MAG3110_CTRL_DR_SHIFT;
|
i = data->ctrl_reg1 >> MAG3110_CTRL_DR_SHIFT;
|
||||||
*val = mag3110_samp_freq[i][0];
|
*val = mag3110_samp_freq[i][0];
|
||||||
|
|
Loading…
Add table
Reference in a new issue