Commit def7cb8c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'staging-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging tree update from Greg Kroah-Hartman:
 "Here is the big staging tree update for the 3.7-rc1 merge window.

  There are a few patches in here that are outside of the staging area,
  namely HID and IIO patches, but all of them have been acked by the
  relevant subsystem maintainers.  The IIO stuff is still coming in
  through this tree as it hasn't entirely moved out of the staging tree,
  but is almost there.

  Other than that, there wa a ton of work on the comedi drivers to make
  them more readable and the correct style.  Doing that removed a lot of
  code, but we added a new driver to the staging tree, so we didn't end
  up with a net reduction this time around:

   662 files changed, 51649 insertions(+), 26582 deletions(-)

  All of these patches have been in the linux-next tree already.

  Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"

* tag 'staging-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1094 commits)
  staging: comedi: jr3_pci: fix iomem dereference
  staging: comedi: drivers: use comedi_fc.h cmdtest helpers
  Staging: winbond: usb_free_urb(NULL) is safe
  Staging: winbond: checkpatch cleanup
  Staging: winbond: Removed undesired spaces, lines and tabs
  Staging: winbond: Typo corrections in comments
  Staging: winbond: Changed c99 comments to c89 comments
  staging: r8712u: Do not queue cloned skb
  staging: comedi: ni_mio_common: always lock in ni_ai_poll()
  staging: comedi: s626: add FIXME comment
  staging: comedi: s626: don't dereference insn->data
  staging: comedi: s526: fix if() check in s526_gpct_winsn()
  staging: comedi: s626: cleanup comments in s626_initialize()
  staging: comedi: s626: remove clear of kzalloc'ed data
  staging: comedi: s626: remove 'WDInterval' from private data
  staging: comedi: s626: remove 'ChargeEnabled' from private data
  staging: comedi: s626: remove 'IsBoardRevA' comment
  staging: comedi: s626: #if 0 out the "SAA7146 BUG WORKAROUND"
  staging: comedi: s626: remove 'allocatedBuf' from private data
  staging: comedi: s626: add final attach message
  ...
parents 06d2fe15 e1878957
* Freescale i.MX28 LRADC device driver
Required properties:
- compatible: Should be "fsl,imx28-lradc"
- reg: Address and length of the register set for the device
- interrupts: Should contain the LRADC interrupts
Examples:
lradc@80050000 {
compatible = "fsl,imx28-lradc";
reg = <0x80050000 0x2000>;
interrupts = <10 14 15 16 17 18 19
20 21 22 23 24 25>;
};
Freescale i.MX IPUv3
====================
Required properties:
- compatible: Should be "fsl,<chip>-ipu"
- reg: should be register base and length as documented in the
datasheet
- interrupts: Should contain sync interrupt and error interrupt,
in this order.
- #crtc-cells: 1, See below
example:
ipu: ipu@18000000 {
#crtc-cells = <1>;
compatible = "fsl,imx53-ipu";
reg = <0x18000000 0x080000000>;
interrupts = <11 10>;
};
Parallel display support
========================
Required properties:
- compatible: Should be "fsl,imx-parallel-display"
- crtc: the crtc this display is connected to, see below
Optional properties:
- interface_pix_fmt: How this display is connected to the
crtc. Currently supported types: "rgb24", "rgb565"
- edid: verbatim EDID data block describing attached display.
- ddc: phandle describing the i2c bus handling the display data
channel
example:
display@di0 {
compatible = "fsl,imx-parallel-display";
edid = [edid-data];
crtc = <&ipu 0>;
interface-pix-fmt = "rgb24";
};
HID Sensors Framework
======================
HID sensor framework provides necessary interfaces to implement sensor drivers,
which are connected to a sensor hub. The sensor hub is a HID device and it provides
a report descriptor conforming to HID 1.12 sensor usage tables.
Description from the HID 1.12 "HID Sensor Usages" specification:
"Standardization of HID usages for sensors would allow (but not require) sensor
hardware vendors to provide a consistent Plug And Play interface at the USB boundary,
thereby enabling some operating systems to incorporate common device drivers that
could be reused between vendors, alleviating any need for the vendors to provide
the drivers themselves."
This specification describes many usage IDs, which describe the type of sensor
and also the individual data fields. Each sensor can have variable number of
data fields. The length and order is specified in the report descriptor. For
example a part of report descriptor can look like:
INPUT(1)[INPUT]
..
Field(2)
Physical(0020.0073)
Usage(1)
0020.045f
Logical Minimum(-32767)
Logical Maximum(32767)
Report Size(8)
Report Count(1)
Report Offset(16)
Flags(Variable Absolute)
..
..
The report is indicating "sensor page (0x20)" contains an accelerometer-3D (0x73).
This accelerometer-3D has some fields. Here for example field 2 is motion intensity
(0x045f) with a logical minimum value of -32767 and logical maximum of 32767. The
order of fields and length of each field is important as the input event raw
data will use this format.
Implementation
=================
This specification defines many different types of sensors with different sets of
data fields. It is difficult to have a common input event to user space applications,
for different sensors. For example an accelerometer can send X,Y and Z data, whereas
an ambient light sensor can send illumination data.
So the implementation has two parts:
- Core hid driver
- Individual sensor processing part (sensor drivers)
Core driver
-----------
The core driver registers (hid-sensor-hub) registers as a HID driver. It parses
report descriptors and identifies all the sensors present. It adds an MFD device
with name HID-SENSOR-xxxx (where xxxx is usage id from the specification).
For example
HID-SENSOR-200073 is registered for an Accelerometer 3D driver.
So if any driver with this name is inserted, then the probe routine for that
function will be called. So an accelerometer processing driver can register
with this name and will be probed if there is an accelerometer-3D detected.
The core driver provides a set of APIs which can be used by the processing
drivers to register and get events for that usage id. Also it provides parsing
functions, which get and set each input/feature/output report.
Individual sensor processing part (sensor drivers)
-----------
The processing driver will use an interface provided by the core driver to parse
the report and get the indexes of the fields and also can get events. This driver
can use IIO interface to use the standard ABI defined for a type of sensor.
Core driver Interface
=====================
Callback structure:
Each processing driver can use this structure to set some callbacks.
int (*suspend)(..): Callback when HID suspend is received
int (*resume)(..): Callback when HID resume is received
int (*capture_sample)(..): Capture a sample for one of its data fields
int (*send_event)(..): One complete event is received which can have
multiple data fields.
Registration functions:
int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
struct hid_sensor_hub_callbacks *usage_callback):
Registers callbacks for an usage id. The callback functions are not allowed
to sleep.
int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
u32 usage_id):
Removes callbacks for an usage id.
Parsing function:
int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
u8 type,
u32 usage_id, u32 attr_usage_id,
struct hid_sensor_hub_attribute_info *info);
A processing driver can look for some field of interest and check if it exists
in a report descriptor. If it exists it will store necessary information
so that fields can be set or get individually.
These indexes avoid searching every time and getting field index to get or set.
Set Feature report
int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
u32 field_index, s32 value);
This interface is used to set a value for a field in feature report. For example
if there is a field report_interval, which is parsed by a call to
sensor_hub_input_get_attribute_info before, then it can directly set that individual
field.
int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
u32 field_index, s32 *value);
This interface is used to get a value for a field in input report. For example
if there is a field report_interval, which is parsed by a call to
sensor_hub_input_get_attribute_info before, then it can directly get that individual
field value.
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
u32 attr_usage_id, u32 report_id);
This is used to get a particular field value through input reports. For example
accelerometer wants to poll X axis value, then it can call this function with
the usage id of X axis. HID sensors can provide events, so this is not necessary
to poll for any field. If there is some new sample, the core driver will call
registered callback function to process the sample.
...@@ -708,6 +708,20 @@ config HID_ZYDACRON ...@@ -708,6 +708,20 @@ config HID_ZYDACRON
---help--- ---help---
Support for Zydacron remote control. Support for Zydacron remote control.
config HID_SENSOR_HUB
tristate "HID Sensors framework support"
depends on USB_HID
select MFD_CORE
default n
-- help---
Support for HID Sensor framework. This creates a MFD instance
for a sensor hub and identifies all the sensors connected to it.
Each sensor is registered as a MFD cell, so that sensor specific
processing can be done in a separate driver. Each sensor
drivers can use the service provided by this driver to register
for events and handle data streams. Each sensor driver can format
data and present to user mode using input or IIO interface.
endmenu endmenu
endif # HID endif # HID
......
...@@ -112,6 +112,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o ...@@ -112,6 +112,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
obj-$(CONFIG_HID_WACOM) += hid-wacom.o obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_HID_WALTOP) += hid-waltop.o obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/
......
...@@ -1568,6 +1568,10 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1568,6 +1568,10 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_1020) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_09FA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_1020) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_09FA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
...@@ -1665,6 +1669,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1665,6 +1669,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_SENSOR_HUB_7014) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) },
......
...@@ -429,6 +429,11 @@ ...@@ -429,6 +429,11 @@
#define USB_VENDOR_ID_IMATION 0x0718 #define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000 #define USB_DEVICE_ID_DISC_STAKKA 0xd000
#define USB_VENDOR_ID_INTEL_8086 0x8086
#define USB_VENDOR_ID_INTEL_8087 0x8087
#define USB_DEVICE_ID_SENSOR_HUB_1020 0x1020
#define USB_DEVICE_ID_SENSOR_HUB_09FA 0x09FA
#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615 #define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
...@@ -706,6 +711,7 @@ ...@@ -706,6 +711,7 @@
#define USB_VENDOR_ID_STANTUM_STM 0x0483 #define USB_VENDOR_ID_STANTUM_STM 0x0483
#define USB_DEVICE_ID_MTP_STM 0x3261 #define USB_DEVICE_ID_MTP_STM 0x3261
#define USB_DEVICE_ID_SENSOR_HUB_7014 0x7014
#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403 #define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403
#define USB_DEVICE_ID_MTP_SITRONIX 0x5001 #define USB_DEVICE_ID_MTP_SITRONIX 0x5001
......
This diff is collapsed.
# #
# Industrial I/O subsytem configuration # Industrial I/O subsystem configuration
# #
menuconfig IIO menuconfig IIO
...@@ -54,10 +54,15 @@ config IIO_CONSUMERS_PER_TRIGGER ...@@ -54,10 +54,15 @@ config IIO_CONSUMERS_PER_TRIGGER
This value controls the maximum number of consumers that a This value controls the maximum number of consumers that a
given trigger may handle. Default is 2. given trigger may handle. Default is 2.
source "drivers/iio/accel/Kconfig"
source "drivers/iio/adc/Kconfig" source "drivers/iio/adc/Kconfig"
source "drivers/iio/amplifiers/Kconfig" source "drivers/iio/amplifiers/Kconfig"
source "drivers/iio/light/Kconfig" source "drivers/iio/light/Kconfig"
source "drivers/iio/frequency/Kconfig" source "drivers/iio/frequency/Kconfig"
source "drivers/iio/dac/Kconfig" source "drivers/iio/dac/Kconfig"
source "drivers/iio/common/Kconfig"
source "drivers/iio/gyro/Kconfig"
source "drivers/iio/light/Kconfig"
source "drivers/iio/magnetometer/Kconfig"
endif # IIO endif # IIO
...@@ -10,8 +10,13 @@ industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o ...@@ -10,8 +10,13 @@ industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
obj-y += accel/
obj-y += adc/ obj-y += adc/
obj-y += amplifiers/ obj-y += amplifiers/
obj-y += light/ obj-y += light/
obj-y += frequency/ obj-y += frequency/
obj-y += dac/ obj-y += dac/
obj-y += common/
obj-y += gyro/
obj-y += light/
obj-y += magnetometer/
#
# Accelerometer drivers
#
menu "Accelerometers"
config HID_SENSOR_ACCEL_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select HID_SENSOR_IIO_COMMON
tristate "HID Acelerometers 3D"
help
Say yes here to build support for the HID SENSOR
accelerometers 3D.
endmenu
#
# Makefile for industrial I/O accelerometer drivers
#
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
This diff is collapsed.
...@@ -3,6 +3,11 @@ ...@@ -3,6 +3,11 @@
# #
menu "Analog to digital converters" menu "Analog to digital converters"
config AD_SIGMA_DELTA
tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config AD7266 config AD7266
tristate "Analog Devices AD7265/AD7266 ADC driver" tristate "Analog Devices AD7265/AD7266 ADC driver"
depends on SPI_MASTER depends on SPI_MASTER
...@@ -13,6 +18,33 @@ config AD7266 ...@@ -13,6 +18,33 @@ config AD7266
Say yes here to build support for Analog Devices AD7265 and AD7266 Say yes here to build support for Analog Devices AD7265 and AD7266
ADCs. ADCs.
config AD7791
tristate "Analog Devices AD7791 ADC driver"
depends on SPI
select AD_SIGMA_DELTA
help
Say yes here to build support for Analog Devices AD7787, AD7788, AD7789,
AD7790 and AD7791 SPI analog to digital converters (ADC). If unsure, say
N (but it is safe to say "Y").
To compile this driver as a module, choose M here: the module will be
called ad7791.
config AD7476
tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices AD7273, AD7274, AD7276,
AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7476.
config AT91_ADC config AT91_ADC
tristate "Atmel AT91 ADC" tristate "Atmel AT91 ADC"
depends on ARCH_AT91 depends on ARCH_AT91
...@@ -22,4 +54,10 @@ config AT91_ADC ...@@ -22,4 +54,10 @@ config AT91_ADC
help help
Say yes here to build support for Atmel AT91 ADC. Say yes here to build support for Atmel AT91 ADC.
config LP8788_ADC
bool "LP8788 ADC driver"
depends on MFD_LP8788
help
Say yes here to build support for TI LP8788 ADC.
endmenu endmenu
...@@ -2,5 +2,9 @@ ...@@ -2,5 +2,9 @@
# Makefile for IIO ADC drivers # Makefile for IIO ADC drivers
# #
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
...@@ -99,7 +99,7 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p) ...@@ -99,7 +99,7 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p)
if (ret == 0) { if (ret == 0) {
if (indio_dev->scan_timestamp) if (indio_dev->scan_timestamp)
((s64 *)st->data)[1] = pf->timestamp; ((s64 *)st->data)[1] = pf->timestamp;
iio_push_to_buffer(buffer, (u8 *)st->data, pf->timestamp); iio_push_to_buffer(buffer, (u8 *)st->data);
} }
iio_trigger_notify_done(indio_dev->trig); iio_trigger_notify_done(indio_dev->trig);
......
...@@ -18,8 +18,76 @@ ...@@ -18,8 +18,76 @@
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h> #include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "ad7476.h" #define RES_MASK(bits) ((1 << (bits)) - 1)
struct ad7476_state;
struct ad7476_chip_info {
unsigned int int_vref_uv;
struct iio_chan_spec channel[2];
void (*reset)(struct ad7476_state *);
};
struct ad7476_state {
struct spi_device *spi;
const struct ad7476_chip_info *chip_info;
struct regulator *reg;
struct spi_transfer xfer;
struct spi_message msg;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
* Make the buffer large enough for one 16 bit sample and one 64 bit
* aligned 64 bit timestamp.
*/
unsigned char data[ALIGN(2, sizeof(s64)) + sizeof(s64)]
____cacheline_aligned;
};
enum ad7476_supported_device_ids {
ID_AD7091R,
ID_AD7276,
ID_AD7277,
ID_AD7278,
ID_AD7466,
ID_AD7467,
ID_AD7468,
ID_AD7495,
ID_AD7940,
};
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7476_state *st = iio_priv(indio_dev);
s64 time_ns;
int b_sent;
b_sent = spi_sync(st->spi, &st->msg);
if (b_sent < 0)
goto done;
time_ns = iio_get_time_ns();
if (indio_dev->scan_timestamp)
((s64 *)st->data)[1] = time_ns;
iio_push_to_buffer(indio_dev->buffer, st->data);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static void ad7091_reset(struct ad7476_state *st)
{
/* Any transfers with 8 scl cycles will reset the device */
spi_read(st->spi, st->data, 1);
}
static int ad7476_scan_direct(struct ad7476_state *st) static int ad7476_scan_direct(struct ad7476_state *st)
{ {
...@@ -29,7 +97,7 @@ static int ad7476_scan_direct(struct ad7476_state *st) ...@@ -29,7 +97,7 @@ static int ad7476_scan_direct(struct ad7476_state *st)
if (ret) if (ret)
return ret; return ret;
return (st->data[0] << 8) | st->data[1]; return be16_to_cpup((__be16 *)st->data);
} }
static int ad7476_read_raw(struct iio_dev *indio_dev, static int ad7476_read_raw(struct iio_dev *indio_dev,
...@@ -40,7 +108,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, ...@@ -40,7 +108,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
{ {
int ret; int ret;
struct ad7476_state *st = iio_priv(indio_dev); struct ad7476_state *st = iio_priv(indio_dev);
unsigned int scale_uv; int scale_uv;
switch (m) { switch (m) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
...@@ -57,62 +125,80 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, ...@@ -57,62 +125,80 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
RES_MASK(st->chip_info->channel[0].scan_type.realbits); RES_MASK(st->chip_info->channel[0].scan_type.realbits);
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
scale_uv = (st->int_vref_mv * 1000) if (!st->chip_info->int_vref_uv) {
>> st->chip_info->channel[0].scan_type.realbits; scale_uv = regulator_get_voltage(st->reg);
*val = scale_uv/1000; if (scale_uv < 0)
*val2 = (scale_uv%1000)*1000; return scale_uv;
} else {
scale_uv = st->chip_info->int_vref_uv;
}
scale_uv >>= chan->scan_type.realbits;
*val = scale_uv / 1000;
*val2 = (scale_uv % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
} }
return -EINVAL; return -EINVAL;
} }
#define AD7476_CHAN(bits) \ #define _AD7476_CHAN(bits, _shift, _info_mask) \
{ \ { \
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask = _info_mask | \
IIO_CHAN_INFO_SCALE_SHARED_BIT, \ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.scan_type = { \ .scan_type = { \
.sign = 'u', \ .sign = 'u', \
.realbits = bits, \ .realbits = (bits), \
.storagebits = 16, \ .storagebits = 16, \
.shift = 12 - bits, \ .shift = (_shift), \
.endianness = IIO_BE, \
}, \ }, \
} }
#define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \
IIO_CHAN_INFO_RAW_SEPARATE_BIT)
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
IIO_CHAN_INFO_RAW_SEPARATE_BIT)
#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0)
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
[ID_AD7466] = { [ID_AD7091R] = {
.channel[0] = AD7476_CHAN(12), .channel[0] = AD7091R_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
.reset = ad7091_reset,
}, },
[ID_AD7467] = { [ID_AD7276] = {
.channel[0] = AD7476_CHAN(10), .channel[0] = AD7940_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7468] = { [ID_AD7277] = {
.channel[0] = AD7476_CHAN(8), .channel[0] = AD7940_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7475] = { [ID_AD7278] = {
.channel[0] = AD7476_CHAN(12), .channel[0] = AD7940_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7476] = { [ID_AD7466] = {
.channel[0] = AD7476_CHAN(12), .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7477] = { [ID_AD7467] = {
.channel[0] = AD7476_CHAN(10), .channel[0] = AD7476_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7478] = { [ID_AD7468] = {
.channel[0] = AD7476_CHAN(8), .channel[0] = AD7476_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7495] = { [ID_AD7495] = {
.channel[0] = AD7476_CHAN(12), .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
.int_vref_mv = 2500, .int_vref_uv = 2500000,
},
[ID_AD7940] = {
.channel[0] = AD7940_CHAN(14),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
}; };
...@@ -123,10 +209,9 @@ static const struct iio_info ad7476_info = { ...@@ -123,10 +209,9 @@ static const struct iio_info ad7476_info = {
static int __devinit ad7476_probe(struct spi_device *spi) static int __devinit ad7476_probe(struct spi_device *spi)
{ {
struct ad7476_platform_data *pdata = spi->dev.platform_data;
struct ad7476_state *st; struct ad7476_state *st;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
int ret, voltage_uv = 0; int ret;
indio_dev = iio_device_alloc(sizeof(*st)); indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) { if (indio_dev == NULL) {
...@@ -134,25 +219,18 @@ static int __devinit ad7476_probe(struct spi_device *spi) ...@@ -134,25 +219,18 @@ static int __devinit ad7476_probe(struct spi_device *spi)
goto error_ret; goto error_ret;
} }
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
st->reg = regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
goto error_put_reg;
voltage_uv = regulator_get_voltage(st->reg);
}
st->chip_info = st->chip_info =
&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data]; &ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
if (st->chip_info->int_vref_mv) st->reg = regulator_get(&spi->dev, "vcc");
st->int_vref_mv = st->chip_info->int_vref_mv; if (IS_ERR(st->reg)) {
else if (pdata && pdata->vref_mv) ret = PTR_ERR(st->reg);
st->int_vref_mv = pdata->vref_mv; goto error_free_dev;
else if (voltage_uv) }
st->int_vref_mv = voltage_uv / 1000;
else ret = regulator_enable(st->reg);
dev_warn(&spi->dev, "reference voltage unspecified\n"); if (ret)
goto error_put_reg;
spi_set_drvdata(spi, indio_dev); spi_set_drvdata(spi, indio_dev);
...@@ -173,57 +251,67 @@ static int __devinit ad7476_probe(struct spi_device *spi) ...@@ -173,57 +251,67 @@ static int __devinit ad7476_probe(struct spi_device *spi)
spi_message_init(&st->msg); spi_message_init(&st->msg);
spi_message_add_tail(&st->xfer, &st->msg); spi_message_add_tail(&st->xfer, &st->msg);
ret = ad7476_register_ring_funcs_and_init(indio_dev); ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad7476_trigger_handler, NULL);
if (ret) if (ret)
goto error_disable_reg; goto error_disable_reg;
if (st->chip_info->reset)
st->chip_info->reset(st);
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
if (ret) if (ret)
goto error_ring_unregister; goto error_ring_unregister;
return 0; return 0;
error_ring_unregister: error_ring_unregister:
ad7476_ring_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg: error_disable_reg:
if (!IS_ERR(st->reg)) regulator_disable(st->reg);
regulator_disable(st->reg);
error_put_reg: error_put_reg:
if (!IS_ERR(st->reg)) regulator_put(st->reg);
regulator_put(st->reg); error_free_dev:
iio_device_free(indio_dev); iio_device_free(indio_dev);
error_ret: error_ret:
return ret; return ret;
} }
static int ad7476_remove(struct spi_device *spi) static int __devexit ad7476_remove(struct spi_device *spi)
{ {
struct iio_dev *indio_dev = spi_get_drvdata(spi); struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7476_state *st = iio_priv(indio_dev); struct ad7476_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
ad7476_ring_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
if (!IS_ERR(st->reg)) { regulator_disable(st->reg);
regulator_disable(st->reg); regulator_put(st->reg);
regulator_put(st->reg);
}
iio_device_free(indio_dev); iio_device_free(indio_dev);
return 0; return 0;
} }
static const struct spi_device_id ad7476_id[] = { static const struct spi_device_id ad7476_id[] = {
{"ad7091r", ID_AD7091R},
{"ad7273", ID_AD7277},
{"ad7274", ID_AD7276},
{"ad7276", ID_AD7276},
{"ad7277", ID_AD7277},
{"ad7278", ID_AD7278},
{"ad7466", ID_AD7466}, {"ad7466", ID_AD7466},
{"ad7467", ID_AD7467}, {"ad7467", ID_AD7467},
{"ad7468", ID_AD7468}, {"ad7468", ID_AD7468},
{"ad7475", ID_AD7475}, {"ad7475", ID_AD7466},
{"ad7476", ID_AD7476}, {"ad7476", ID_AD7466},
{"ad7476a", ID_AD7476}, {"ad7476a", ID_AD7466},
{"ad7477", ID_AD7477}, {"ad7477", ID_AD7467},
{"ad7477a", ID_AD7477}, {"ad7477a", ID_AD7467},
{"ad7478", ID_AD7478}, {"ad7478", ID_AD7468},
{"ad7478a", ID_AD7478}, {"ad7478a", ID_AD7468},
{"ad7495", ID_AD7495}, {"ad7495", ID_AD7495},
{"ad7910", ID_AD7467},
{"ad7920", ID_AD7466},
{"ad7940", ID_AD7940},
{} {}
}; };
MODULE_DEVICE_TABLE(spi, ad7476_id); MODULE_DEVICE_TABLE(spi, ad7476_id);
...@@ -240,5 +328,5 @@ static struct spi_driver ad7476_driver = { ...@@ -240,5 +328,5 @@ static struct spi_driver ad7476_driver = {
module_spi_driver(ad7476_driver); module_spi_driver(ad7476_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7475/6/7/8(A) AD7466/7/8 ADC"); MODULE_DESCRIPTION("Analog Devices AD7476 and similar 1-channel ADCs");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
This diff is collapsed.
This diff is collapsed.
...@@ -82,7 +82,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) ...@@ -82,7 +82,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
*timestamp = pf->timestamp; *timestamp = pf->timestamp;
} }
buffer->access->store_to(buffer, (u8 *)st->buffer, pf->timestamp); buffer->access->store_to(buffer, (u8 *)st->buffer);
iio_trigger_notify_done(idev->trig); iio_trigger_notify_done(idev->trig);
st->irq_enabled = true; st->irq_enabled = true;
...@@ -545,13 +545,6 @@ static int __devinit at91_adc_probe(struct platform_device *pdev) ...@@ -545,13 +545,6 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
goto error_free_device; goto error_free_device;
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "No resource defined\n");
ret = -ENXIO;
goto error_ret;
}
platform_set_drvdata(pdev, idev); platform_set_drvdata(pdev, idev);
idev->dev.parent = &pdev->dev; idev->dev.parent = &pdev->dev;
...@@ -566,18 +559,12 @@ static int __devinit at91_adc_probe(struct platform_device *pdev) ...@@ -566,18 +559,12 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
goto error_free_device; goto error_free_device;
} }
if (!request_mem_region(res->start, resource_size(res), res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
"AT91 adc registers")) {
dev_err(&pdev->dev, "Resources are unavailable.\n");
ret = -EBUSY;
goto error_free_device;
}
st->reg_base = ioremap(res->start, resource_size(res)); st->reg_base = devm_request_and_ioremap(&pdev->dev, res);
if (!st->reg_base) { if (!st->reg_base) {
dev_err(&pdev->dev, "Failed to map registers.\n");
ret = -ENOMEM; ret = -ENOMEM;
goto error_release_mem; goto error_free_device;
} }
/* /*
...@@ -592,45 +579,35 @@ static int __devinit at91_adc_probe(struct platform_device *pdev) ...@@ -592,45 +579,35 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
idev); idev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to allocate IRQ.\n"); dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
goto error_unmap_reg; goto error_free_device;
} }
st->clk = clk_get(&pdev->dev, "adc_clk"); st->clk = devm_clk_get(&pdev->dev, "adc_clk");
if (IS_ERR(st->clk)) { if (IS_ERR(st->clk)) {
dev_err(&pdev->dev, "Failed to get the clock.\n"); dev_err(&pdev->dev, "Failed to get the clock.\n");
ret = PTR_ERR(st->clk); ret = PTR_ERR(st->clk);
goto error_free_irq; goto error_free_irq;
} }
ret = clk_prepare(st->clk); ret = clk_prepare_enable(st->clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Could not prepare the clock.\n"); dev_err(&pdev->dev,
goto error_free_clk; "Could not prepare or enable the clock.\n");
} goto error_free_irq;
ret = clk_enable(st->clk);
if (ret) {
dev_err(&pdev->dev, "Could not enable the clock.\n");
goto error_unprepare_clk;
} }
st->adc_clk = clk_get(&pdev->dev, "adc_op_clk"); st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk");
if (IS_ERR(st->adc_clk)) { if (IS_ERR(st->adc_clk)) {
dev_err(&pdev->dev, "Failed to get the ADC clock.\n"); dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
ret = PTR_ERR(st->adc_clk); ret = PTR_ERR(st->adc_clk);
goto error_disable_clk; goto error_disable_clk;
} }
ret = clk_prepare(st->adc_clk); ret = clk_prepare_enable(st->adc_clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Could not prepare the ADC clock.\n"); dev_err(&pdev->dev,
goto error_free_adc_clk; "Could not prepare or enable the ADC clock.\n");
} goto error_disable_clk;
ret = clk_enable(st->adc_clk);
if (ret) {
dev_err(&pdev->dev, "Could not enable the ADC clock.\n");
goto error_unprepare_adc_clk;
} }
/* /*
...@@ -694,23 +671,11 @@ static int __devinit at91_adc_probe(struct platform_device *pdev) ...@@ -694,23 +671,11 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
error_unregister_buffer: error_unregister_buffer:
at91_adc_buffer_remove(idev); at91_adc_buffer_remove(idev);
error_disable_adc_clk: error_disable_adc_clk:
clk_disable(st->adc_clk); clk_disable_unprepare(st->adc_clk);
error_unprepare_adc_clk:
clk_unprepare(st->adc_clk);
error_free_adc_clk:
clk_put(st->adc_clk);
error_disable_clk: error_disable_clk:
clk_disable(st->clk); clk_disable_unprepare(st->clk);
error_unprepare_clk:
clk_unprepare(st->clk);
error_free_clk:
clk_put(st->clk);
error_free_irq: error_free_irq:
free_irq(st->irq, idev); free_irq(st->irq, idev);
error_unmap_reg:
iounmap(st->reg_base);
error_release_mem:
release_mem_region(res->start, resource_size(res));
error_free_device: error_free_device:
iio_device_free(idev); iio_device_free(idev);
error_ret: error_ret:
...@@ -720,20 +685,14 @@ static int __devinit at91_adc_probe(struct platform_device *pdev) ...@@ -720,20 +685,14 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
static int __devexit at91_adc_remove(struct platform_device *pdev) static int __devexit at91_adc_remove(struct platform_device *pdev)
{ {
struct iio_dev *idev = platform_get_drvdata(pdev); struct iio_dev *idev = platform_get_drvdata(pdev);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct at91_adc_state *st = iio_priv(idev); struct at91_adc_state *st = iio_priv(idev);
iio_device_unregister(idev); iio_device_unregister(idev);
at91_adc_trigger_remove(idev); at91_adc_trigger_remove(idev);
at91_adc_buffer_remove(idev); at91_adc_buffer_remove(idev);
clk_disable_unprepare(st->adc_clk); clk_disable_unprepare(st->adc_clk);
clk_put(st->adc_clk); clk_disable_unprepare(st->clk);
clk_disable(st->clk);
clk_unprepare(st->clk);
clk_put(st->clk);
free_irq(st->irq, idev); free_irq(st->irq, idev);
iounmap(st->reg_base);
release_mem_region(res->start, resource_size(res));
iio_device_free(idev); iio_device_free(idev);
return 0; return 0;
......
/*
* TI LP8788 MFD - ADC driver
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/iio/machine.h>
#include <linux/mfd/lp8788.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
/* register address */
#define LP8788_ADC_CONF 0x60
#define LP8788_ADC_RAW 0x61
#define LP8788_ADC_DONE 0x63
#define ADC_CONV_START 1
struct lp8788_adc {
struct lp8788 *lp;
struct iio_map *map;
struct mutex lock;
};
static const int lp8788_scale[LPADC_MAX] = {
[LPADC_VBATT_5P5] = 1343101,
[LPADC_VIN_CHG] = 3052503,
[LPADC_IBATT] = 610500,
[LPADC_IC_TEMP] = 61050,
[LPADC_VBATT_6P0] = 1465201,
[LPADC_VBATT_5P0] = 1221001,
[LPADC_ADC1] = 610500,
[LPADC_ADC2] = 610500,
[LPADC_VDD] = 1025641,
[LPADC_VCOIN] = 757020,
[LPADC_ADC3] = 610500,
[LPADC_ADC4] = 610500,
};
static int lp8788_get_adc_result(struct lp8788_adc *adc, enum lp8788_adc_id id,
int *val)
{
unsigned int msb;
unsigned int lsb;
unsigned int result;
u8 data;
u8 rawdata[2];
int size = ARRAY_SIZE(rawdata);
int retry = 5;
int ret;
data = (id << 1) | ADC_CONV_START;
ret = lp8788_write_byte(adc->lp, LP8788_ADC_CONF, data);
if (ret)
goto err_io;
/* retry until adc conversion is done */
data = 0;
while (retry--) {
usleep_range(100, 200);
ret = lp8788_read_byte(adc->lp, LP8788_ADC_DONE, &data);
if (ret)
goto err_io;
/* conversion done */
if (data)
break;
}
ret = lp8788_read_multi_bytes(adc->lp, LP8788_ADC_RAW, rawdata, size);
if (ret)
goto err_io;
msb = (rawdata[0] << 4) & 0x00000ff0;
lsb = (rawdata[1] >> 4) & 0x0000000f;
result = msb | lsb;
*val = result;
return 0;
err_io:
return ret;
}
static int lp8788_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct lp8788_adc *adc = iio_priv(indio_dev);
enum lp8788_adc_id id = chan->channel;
int ret;
mutex_lock(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = lp8788_get_adc_result(adc, id, val) ? -EIO : IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
*val = lp8788_scale[id] / 1000000;
*val2 = lp8788_scale[id] % 1000000;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
default:
ret = -EINVAL;
break;
}
mutex_unlock(&adc->lock);
return ret;
}
static const struct iio_info lp8788_adc_info = {
.read_raw = &lp8788_adc_read_raw,
.driver_module = THIS_MODULE,
};
#define LP8788_CHAN(_id, _type) { \
.type = _type, \
.indexed = 1, \
.channel = LPADC_##_id, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.datasheet_name = #_id, \
}
static const struct iio_chan_spec lp8788_adc_channels[] = {
[LPADC_VBATT_5P5] = LP8788_CHAN(VBATT_5P5, IIO_VOLTAGE),
[LPADC_VIN_CHG] = LP8788_CHAN(VIN_CHG, IIO_VOLTAGE),
[LPADC_IBATT] = LP8788_CHAN(IBATT, IIO_CURRENT),
[LPADC_IC_TEMP] = LP8788_CHAN(IC_TEMP, IIO_TEMP),
[LPADC_VBATT_6P0] = LP8788_CHAN(VBATT_6P0, IIO_VOLTAGE),
[LPADC_VBATT_5P0] = LP8788_CHAN(VBATT_5P0, IIO_VOLTAGE),
[LPADC_ADC1] = LP8788_CHAN(ADC1, IIO_VOLTAGE),
[LPADC_ADC2] = LP8788_CHAN(ADC2, IIO_VOLTAGE),
[LPADC_VDD] = LP8788_CHAN(VDD, IIO_VOLTAGE),
[LPADC_VCOIN] = LP8788_CHAN(VCOIN, IIO_VOLTAGE),
[LPADC_ADC3] = LP8788_CHAN(ADC3, IIO_VOLTAGE),
[LPADC_ADC4] = LP8788_CHAN(ADC4, IIO_VOLTAGE),
};
/* default maps used by iio consumer (lp8788-charger driver) */
static struct iio_map lp8788_default_iio_maps[] = {
{
.consumer_dev_name = "lp8788-charger",
.consumer_channel = "lp8788_vbatt_5p0",
.adc_channel_label = "VBATT_5P0",
},
{
.consumer_dev_name = "lp8788-charger",
.consumer_channel = "lp8788_adc1",
.adc_channel_label = "ADC1",
},
{ }
};
static int lp8788_iio_map_register(struct iio_dev *indio_dev,
struct lp8788_platform_data *pdata,
struct lp8788_adc *adc)
{
struct iio_map *map;
int ret;
map = (!pdata || !pdata->adc_pdata) ?
lp8788_default_iio_maps : pdata->adc_pdata;
ret = iio_map_array_register(indio_dev, map);
if (ret) {
dev_err(adc->lp->dev, "iio map err: %d\n", ret);
return ret;
}
adc->map = map;
return 0;
}
static inline void lp8788_iio_map_unregister(struct iio_dev *indio_dev,
struct lp8788_adc *adc)
{
iio_map_array_unregister(indio_dev, adc->map);
}
static int __devinit lp8788_adc_probe(struct platform_device *pdev)
{
struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
struct iio_dev *indio_dev;
struct lp8788_adc *adc;
int ret;
indio_dev = iio_device_alloc(sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->lp = lp;
platform_set_drvdata(pdev, indio_dev);
ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc);
if (ret)
goto err_iio_map;
mutex_init(&adc->lock);
indio_dev->dev.parent = lp->dev;
indio_dev->name = pdev->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &lp8788_adc_info;
indio_dev->channels = lp8788_adc_channels;
indio_dev->num_channels = ARRAY_SIZE(lp8788_adc_channels);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(lp->dev, "iio dev register err: %d\n", ret);
goto err_iio_device;
}
return 0;
err_iio_device:
lp8788_iio_map_unregister(indio_dev, adc);
err_iio_map:
iio_device_free(indio_dev);
return ret;
}
static int __devexit lp8788_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct lp8788_adc *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
lp8788_iio_map_unregister(indio_dev, adc);
iio_device_free(indio_dev);
return 0;
}
static struct platform_driver lp8788_adc_driver = {
.probe = lp8788_adc_probe,
.remove = __devexit_p(lp8788_adc_remove),
.driver = {
.name = LP8788_DEV_ADC,
.owner = THIS_MODULE,
},
};
module_platform_driver(lp8788_adc_driver);
MODULE_DESCRIPTION("Texas Instruments LP8788 ADC Driver");
MODULE_AUTHOR("Milo Kim");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:lp8788-adc");
#
# IIO common modules
#
source "drivers/iio/common/hid-sensors/Kconfig"
#
# Makefile for the IIO common modules.
# Common modules contains modules, which can be shared among multiple
# IIO modules. For example if the trigger processing is common for
# multiple IIO modules then this can be moved to a common module
# instead of duplicating in each module.
#
obj-y += hid-sensors/
#
# Hid Sensor common modules
#
menu "Hid Sensor IIO Common"
config HID_SENSOR_IIO_COMMON
tristate "Common modules for all HID Sensor IIO drivers"
depends on HID_SENSOR_HUB
select IIO_TRIGGER if IIO_BUFFER
help
Say yes here to build support for HID sensor to use
HID sensor common processing for attributes and IIO triggers.
There are many attributes which can be shared among multiple
HID sensor drivers, this module contains processing for those
attributes.
config HID_SENSOR_ENUM_BASE_QUIRKS
tristate "ENUM base quirks for HID Sensor IIO drivers"
depends on HID_SENSOR_IIO_COMMON
help
Say yes here to build support for sensor hub FW using
enumeration, which is using 1 as base instead of 0.
Since logical minimum is still set 0 instead of 1,
there is no easy way to differentiate.
endmenu
#
# Makefile for the Hid sensor common modules.
#
obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o
hid-sensor-iio-common-y := hid-sensor-attributes.o hid-sensor-trigger.o
/*
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include "hid-sensor-attributes.h"
static int pow_10(unsigned power)
{
int i;
int ret = 1;
for (i = 0; i < power; ++i)
ret = ret * 10;
return ret;
}
static void simple_div(int dividend, int divisor, int *whole,
int *micro_frac)
{
int rem;
int exp = 0;
*micro_frac = 0;
if (divisor == 0) {
*whole = 0;
return;
}
*whole = dividend/divisor;
rem = dividend % divisor;
if (rem) {
while (rem <= divisor) {
rem *= 10;
exp++;
}
*micro_frac = (rem / divisor) * pow_10(6-exp);
}
}
static void split_micro_fraction(unsigned int no, int exp, int *val1, int *val2)
{
*val1 = no/pow_10(exp);
*val2 = no%pow_10(exp) * pow_10(6-exp);
}
/*
VTF format uses exponent and variable size format.
For example if the size is 2 bytes
0x0067 with VTF16E14 format -> +1.03
To convert just change to 0x67 to decimal and use two decimal as E14 stands
for 10^-2.
Negative numbers are 2's complement
*/
static void convert_from_vtf_format(u32 value, int size, int exp,
int *val1, int *val2)
{
int sign = 1;
if (value & BIT(size*8 - 1)) {
value = ((1LL << (size * 8)) - value);
sign = -1;
}
exp = hid_sensor_convert_exponent(exp);
if (exp >= 0) {
*val1 = sign * value * pow_10(exp);
*val2 = 0;
} else {
split_micro_fraction(value, -exp, val1, val2);
if (*val1)
*val1 = sign * (*val1);
else
*val2 = sign * (*val2);
}
}
static u32 convert_to_vtf_format(int size, int exp, int val1, int val2)
{
u32 value;
int sign = 1;
if (val1 < 0 || val2 < 0)
sign = -1;
exp = hid_sensor_convert_exponent(exp);
if (exp < 0) {
value = abs(val1) * pow_10(-exp);
value += abs(val2) / pow_10(6+exp);
} else
value = abs(val1) / pow_10(exp);
if (sign < 0)
value = ((1LL << (size * 8)) - value);
return value;
}
int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st,
int *val1, int *val2)
{
s32 value;
int ret;
ret = sensor_hub_get_feature(st->hsdev,
st->poll.report_id,
st->poll.index, &value);
if (ret < 0 || value < 0) {
*val1 = *val2 = 0;
return -EINVAL;
} else {
if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
simple_div(1000, value, val1, val2);
else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
simple_div(1, value, val1, val2);
else {
*val1 = *val2 = 0;
return -EINVAL;
}
}
return IIO_VAL_INT_PLUS_MICRO;
}
EXPORT_SYMBOL(hid_sensor_read_samp_freq_value);
int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st,
int val1, int val2)
{
s32 value;
int ret;
if (val1 < 0 || val2 < 0)
ret = -EINVAL;
value = val1 * pow_10(6) + val2;
if (value) {
if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
value = pow_10(9)/value;
else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
value = pow_10(6)/value;
else
value = 0;
}
ret = sensor_hub_set_feature(st->hsdev,
st->poll.report_id,
st->poll.index, value);
if (ret < 0 || value < 0)
ret = -EINVAL;
return ret;
}
EXPORT_SYMBOL(hid_sensor_write_samp_freq_value);
int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st,
int *val1, int *val2)
{
s32 value;
int ret;
ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity.report_id,
st->sensitivity.index, &value);
if (ret < 0 || value < 0) {
*val1 = *val2 = 0;
return -EINVAL;
} else {
convert_from_vtf_format(value, st->sensitivity.size,
st->sensitivity.unit_expo,
val1, val2);
}
return IIO_VAL_INT_PLUS_MICRO;
}
EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value);
int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st,
int val1, int val2)
{
s32 value;
int ret;
value = convert_to_vtf_format(st->sensitivity.size,
st->sensitivity.unit_expo,
val1, val2);
ret = sensor_hub_set_feature(st->hsdev,
st->sensitivity.report_id,
st->sensitivity.index, value);
if (ret < 0 || value < 0)
ret = -EINVAL;
return ret;
}
EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
struct hid_sensor_iio_common *st)
{
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_PROP_REPORT_INTERVAL,
&st->poll);
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_PROP_REPORT_STATE,
&st->report_state);
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_PROY_POWER_STATE,
&st->power_state);
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS,
&st->sensitivity);
hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n",
st->poll.index, st->poll.report_id,
st->report_state.index, st->report_state.report_id,
st->power_state.index, st->power_state.report_id,
st->sensitivity.index, st->sensitivity.report_id);
return 0;
}
EXPORT_SYMBOL(hid_sensor_parse_common_attributes);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_DESCRIPTION("HID Sensor common attribute processing");
MODULE_LICENSE("GPL");
/*
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef _HID_SENSORS_ATTRIBUTES_H
#define _HID_SENSORS_ATTRIBUTES_H
/* Common hid sensor iio structure */
struct hid_sensor_iio_common {
struct hid_sensor_hub_device *hsdev;
struct platform_device *pdev;
unsigned usage_id;
bool data_ready;
struct hid_sensor_hub_attribute_info poll;
struct hid_sensor_hub_attribute_info report_state;
struct hid_sensor_hub_attribute_info power_state;
struct hid_sensor_hub_attribute_info sensitivity;
};
/*Convert from hid unit expo to regular exponent*/
static inline int hid_sensor_convert_exponent(int unit_expo)
{
if (unit_expo < 0x08)
return unit_expo;
else if (unit_expo <= 0x0f)
return -(0x0f-unit_expo+1);
else
return 0;
}
int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
struct hid_sensor_iio_common *st);
int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st,
int val1, int val2);
int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st,
int *val1, int *val2);
int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st,
int val1, int val2);
int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st,
int *val1, int *val2);
#endif
/*
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/sysfs.h>
#include "hid-sensor-attributes.h"
#include "hid-sensor-trigger.h"
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct hid_sensor_iio_common *st = trig->private_data;
int state_val;
state_val = state ? 1 : 0;
#if (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS) || \
(defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS_MODULE)
++state_val;
#endif
st->data_ready = state;
sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
st->power_state.index,
(s32)state_val);
sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
st->report_state.index,
(s32)state_val);
return 0;
}
void hid_sensor_remove_trigger(struct iio_dev *indio_dev)
{
iio_trigger_unregister(indio_dev->trig);
iio_trigger_free(indio_dev->trig);
indio_dev->trig = NULL;
}
EXPORT_SYMBOL(hid_sensor_remove_trigger);
static const struct iio_trigger_ops hid_sensor_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
};
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_iio_common *attrb)
{
int ret;
struct iio_trigger *trig;
trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id);
if (trig == NULL) {
dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
ret = -ENOMEM;
goto error_ret;
}
trig->dev.parent = indio_dev->dev.parent;
trig->private_data = attrb;
trig->ops = &hid_sensor_trigger_ops;
ret = iio_trigger_register(trig);
if (ret) {
dev_err(&indio_dev->dev, "Trigger Register Failed\n");
goto error_free_trig;
}
indio_dev->trig = trig;
return ret;
error_free_trig:
iio_trigger_free(trig);
error_ret:
return ret;
}
EXPORT_SYMBOL(hid_sensor_setup_trigger);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_DESCRIPTION("HID Sensor trigger processing");
MODULE_LICENSE("GPL");
/*
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef _HID_SENSOR_TRIGGER_H
#define _HID_SENSOR_TRIGGER_H
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_iio_common *attrb);
void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
#endif
...@@ -57,11 +57,12 @@ config AD5624R_SPI ...@@ -57,11 +57,12 @@ config AD5624R_SPI
config AD5446 config AD5446
tristate "Analog Devices AD5446 and similar single channel DACs driver" tristate "Analog Devices AD5446 and similar single channel DACs driver"
depends on SPI depends on (SPI_MASTER || I2C)
help help
Say yes here to build support for Analog Devices AD5444, AD5446, AD5450, Say yes here to build support for Analog Devices AD5300, AD5301, AD5310,
AD5451, AD5452, AD5453, AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453,
AD5611, AD5620, AD5621, AD5640, AD5660, AD5662 DACs. AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5602, AD5611, AD5612,
AD5620, AD5621, AD5622, AD5640, AD5660, AD5662 DACs.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called ad5446. module will be called ad5446.
...@@ -76,6 +77,17 @@ config AD5504 ...@@ -76,6 +77,17 @@ config AD5504
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called ad5504. module will be called ad5504.
config AD5755
tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver"
depends on SPI_MASTER
help
Say yes here to build support for Analog Devices AD5755, AD5755-1,
AD5757, AD5735, AD5737 quad channel Digital to
Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5755.
config AD5764 config AD5764
tristate "Analog Devices AD5764/64R/44/44R DAC driver" tristate "Analog Devices AD5764/64R/44/44R DAC driver"
depends on SPI_MASTER depends on SPI_MASTER
......
...@@ -9,6 +9,7 @@ obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o ...@@ -9,6 +9,7 @@ obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
obj-$(CONFIG_AD5064) += ad5064.o obj-$(CONFIG_AD5064) += ad5064.o
obj-$(CONFIG_AD5504) += ad5504.o obj-$(CONFIG_AD5504) += ad5504.o
obj-$(CONFIG_AD5446) += ad5446.o obj-$(CONFIG_AD5446) += ad5446.o
obj-$(CONFIG_AD5755) += ad5755.o
obj-$(CONFIG_AD5764) += ad5764.o obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o obj-$(CONFIG_AD5686) += ad5686.o
......
This diff is collapsed.
/*
* AD5446 SPI DAC driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef IIO_DAC_AD5446_H_
#define IIO_DAC_AD5446_H_
/* DAC Control Bits */
#define AD5446_LOAD (0x0 << 14) /* Load and update */
#define AD5446_SDO_DIS (0x1 << 14) /* Disable SDO */
#define AD5446_NOP (0x2 << 14) /* No operation */
#define AD5446_CLK_RISING (0x3 << 14) /* Clock data on rising edge */
#define AD5620_LOAD (0x0 << 14) /* Load and update Norm Operation*/
#define AD5620_PWRDWN_1k (0x1 << 14) /* Power-down: 1kOhm to GND */
#define AD5620_PWRDWN_100k (0x2 << 14) /* Power-down: 100kOhm to GND */
#define AD5620_PWRDWN_TRISTATE (0x3 << 14) /* Power-down: Three-state */
#define AD5660_LOAD (0x0 << 16) /* Load and update Norm Operation*/
#define AD5660_PWRDWN_1k (0x1 << 16) /* Power-down: 1kOhm to GND */
#define AD5660_PWRDWN_100k (0x2 << 16) /* Power-down: 100kOhm to GND */
#define AD5660_PWRDWN_TRISTATE (0x3 << 16) /* Power-down: Three-state */
#define MODE_PWRDWN_1k 0x1
#define MODE_PWRDWN_100k 0x2
#define MODE_PWRDWN_TRISTATE 0x3
/**
* struct ad5446_state - driver instance specific data
* @spi: spi_device
* @chip_info: chip model specific constants, available modes etc
* @reg: supply regulator
* @vref_mv: actual reference voltage used
*/
struct ad5446_state {
struct spi_device *spi;
const struct ad5446_chip_info *chip_info;
struct regulator *reg;
unsigned short vref_mv;
unsigned cached_val;
unsigned pwr_down_mode;
unsigned pwr_down;
};
/**
* struct ad5446_chip_info - chip specific information
* @channel: channel spec for the DAC
* @int_vref_mv: AD5620/40/60: the internal reference voltage
* @write: chip specific helper function to write to the register
*/
struct ad5446_chip_info {
struct iio_chan_spec channel;
u16 int_vref_mv;
int (*write)(struct ad5446_state *st, unsigned val);
};
/**
* ad5446_supported_device_ids:
* The AD5620/40/60 parts are available in different fixed internal reference
* voltage options. The actual part numbers may look differently
* (and a bit cryptic), however this style is used to make clear which
* parts are supported here.
*/
enum ad5446_supported_device_ids {
ID_AD5444,
ID_AD5446,
ID_AD5450,
ID_AD5451,
ID_AD5541A,
ID_AD5512A,
ID_AD5553,
ID_AD5601,
ID_AD5611,
ID_AD5621,
ID_AD5620_2500,
ID_AD5620_1250,
ID_AD5640_2500,
ID_AD5640_1250,
ID_AD5660_2500,
ID_AD5660_1250,
ID_AD5662,
};
#endif /* IIO_DAC_AD5446_H_ */
This diff is collapsed.
#
# IIO Digital Gyroscope Sensor drivers configuration
#
menu "Digital gyroscope sensors"
config HID_SENSOR_GYRO_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select HID_SENSOR_IIO_COMMON
tristate "HID Gyroscope 3D"
help
Say yes here to build support for the HID SENSOR
Gyroscope 3D.
endmenu
#
# Makefile for industrial I/O gyroscope sensor drivers
#
obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
This diff is collapsed.
...@@ -422,7 +422,7 @@ ssize_t iio_buffer_store_enable(struct device *dev, ...@@ -422,7 +422,7 @@ ssize_t iio_buffer_store_enable(struct device *dev,
ret = indio_dev->setup_ops->preenable(indio_dev); ret = indio_dev->setup_ops->preenable(indio_dev);
if (ret) { if (ret) {
printk(KERN_ERR printk(KERN_ERR
"Buffer not started:" "Buffer not started: "
"buffer preenable failed\n"); "buffer preenable failed\n");
goto error_ret; goto error_ret;
} }
...@@ -431,12 +431,12 @@ ssize_t iio_buffer_store_enable(struct device *dev, ...@@ -431,12 +431,12 @@ ssize_t iio_buffer_store_enable(struct device *dev,
ret = buffer->access->request_update(buffer); ret = buffer->access->request_update(buffer);
if (ret) { if (ret) {
printk(KERN_INFO printk(KERN_INFO
"Buffer not started:" "Buffer not started: "
"buffer parameter update failed\n"); "buffer parameter update failed\n");
goto error_ret; goto error_ret;
} }
} }
/* Definitely possible for devices to support both of these.*/ /* Definitely possible for devices to support both of these. */
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) { if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
if (!indio_dev->trig) { if (!indio_dev->trig) {
printk(KERN_INFO printk(KERN_INFO
...@@ -456,7 +456,7 @@ ssize_t iio_buffer_store_enable(struct device *dev, ...@@ -456,7 +456,7 @@ ssize_t iio_buffer_store_enable(struct device *dev,
ret = indio_dev->setup_ops->postenable(indio_dev); ret = indio_dev->setup_ops->postenable(indio_dev);
if (ret) { if (ret) {
printk(KERN_INFO printk(KERN_INFO
"Buffer not started:" "Buffer not started: "
"postenable failed\n"); "postenable failed\n");
indio_dev->currentmode = previous_mode; indio_dev->currentmode = previous_mode;
if (indio_dev->setup_ops->postdisable) if (indio_dev->setup_ops->postdisable)
...@@ -657,7 +657,7 @@ EXPORT_SYMBOL_GPL(iio_scan_mask_query); ...@@ -657,7 +657,7 @@ EXPORT_SYMBOL_GPL(iio_scan_mask_query);
/** /**
* struct iio_demux_table() - table describing demux memcpy ops * struct iio_demux_table() - table describing demux memcpy ops
* @from: index to copy from * @from: index to copy from
* @to: index to copy to * @to: index to copy to
* @length: how many bytes to copy * @length: how many bytes to copy
* @l: list head used for management * @l: list head used for management
*/ */
...@@ -682,12 +682,11 @@ static unsigned char *iio_demux(struct iio_buffer *buffer, ...@@ -682,12 +682,11 @@ static unsigned char *iio_demux(struct iio_buffer *buffer,
return buffer->demux_bounce; return buffer->demux_bounce;
} }
int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data, int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data)
s64 timestamp)
{ {
unsigned char *dataout = iio_demux(buffer, data); unsigned char *dataout = iio_demux(buffer, data);
return buffer->access->store_to(buffer, dataout, timestamp); return buffer->access->store_to(buffer, dataout);
} }
EXPORT_SYMBOL_GPL(iio_push_to_buffer); EXPORT_SYMBOL_GPL(iio_push_to_buffer);
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/iio/events.h> #include <linux/iio/events.h>
/* IDA to assign each registered device a unique id*/ /* IDA to assign each registered device a unique id */
static DEFINE_IDA(iio_ida); static DEFINE_IDA(iio_ida);
static dev_t iio_devt; static dev_t iio_devt;
...@@ -99,6 +99,7 @@ static const char * const iio_chan_info_postfix[] = { ...@@ -99,6 +99,7 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_FREQUENCY] = "frequency", [IIO_CHAN_INFO_FREQUENCY] = "frequency",
[IIO_CHAN_INFO_PHASE] = "phase", [IIO_CHAN_INFO_PHASE] = "phase",
[IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain", [IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
[IIO_CHAN_INFO_HYSTERESIS] = "hysteresis",
}; };
const struct iio_chan_spec const struct iio_chan_spec
...@@ -365,6 +366,7 @@ static ssize_t iio_read_channel_info(struct device *dev, ...@@ -365,6 +366,7 @@ static ssize_t iio_read_channel_info(struct device *dev,
{ {
struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned long long tmp;
int val, val2; int val, val2;
bool scale_db = false; bool scale_db = false;
int ret = indio_dev->info->read_raw(indio_dev, this_attr->c, int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
...@@ -390,6 +392,11 @@ static ssize_t iio_read_channel_info(struct device *dev, ...@@ -390,6 +392,11 @@ static ssize_t iio_read_channel_info(struct device *dev,
return sprintf(buf, "-%d.%09u\n", val, -val2); return sprintf(buf, "-%d.%09u\n", val, -val2);
else else
return sprintf(buf, "%d.%09u\n", val, val2); return sprintf(buf, "%d.%09u\n", val, val2);
case IIO_VAL_FRACTIONAL:
tmp = div_s64((s64)val * 1000000000LL, val2);
val2 = do_div(tmp, 1000000000LL);
val = tmp;
return sprintf(buf, "%d.%09u\n", val, val2);
default: default:
return 0; return 0;
} }
...@@ -729,7 +736,7 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) ...@@ -729,7 +736,7 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
attrcount = attrcount_orig; attrcount = attrcount_orig;
/* /*
* New channel registration method - relies on the fact a group does * New channel registration method - relies on the fact a group does
* not need to be initialized if it is name is NULL. * not need to be initialized if its name is NULL.
*/ */
if (indio_dev->channels) if (indio_dev->channels)
for (i = 0; i < indio_dev->num_channels; i++) { for (i = 0; i < indio_dev->num_channels; i++) {
...@@ -980,6 +987,6 @@ EXPORT_SYMBOL(iio_device_unregister); ...@@ -980,6 +987,6 @@ EXPORT_SYMBOL(iio_device_unregister);
subsys_initcall(iio_init); subsys_initcall(iio_init);
module_exit(iio_exit); module_exit(iio_exit);
MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("Industrial I/O core"); MODULE_DESCRIPTION("Industrial I/O core");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
This diff is collapsed.
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/kfifo.h> #include <linux/kfifo.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/iio/kfifo_buf.h> #include <linux/iio/kfifo_buf.h>
#include <linux/sched.h>
struct iio_kfifo { struct iio_kfifo {
struct iio_buffer buffer; struct iio_buffer buffer;
...@@ -22,7 +23,8 @@ static inline int __iio_allocate_kfifo(struct iio_kfifo *buf, ...@@ -22,7 +23,8 @@ static inline int __iio_allocate_kfifo(struct iio_kfifo *buf,
return -EINVAL; return -EINVAL;
__iio_update_buffer(&buf->buffer, bytes_per_datum, length); __iio_update_buffer(&buf->buffer, bytes_per_datum, length);
return kfifo_alloc(&buf->kf, bytes_per_datum*length, GFP_KERNEL); return __kfifo_alloc((struct __kfifo *)&buf->kf, length,
bytes_per_datum, GFP_KERNEL);
} }
static int iio_request_update_kfifo(struct iio_buffer *r) static int iio_request_update_kfifo(struct iio_buffer *r)
...@@ -35,6 +37,7 @@ static int iio_request_update_kfifo(struct iio_buffer *r) ...@@ -35,6 +37,7 @@ static int iio_request_update_kfifo(struct iio_buffer *r)
kfifo_free(&buf->kf); kfifo_free(&buf->kf);
ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum, ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
buf->buffer.length); buf->buffer.length);
r->stufftoread = false;
error_ret: error_ret:
return ret; return ret;
} }
...@@ -81,6 +84,9 @@ static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd) ...@@ -81,6 +84,9 @@ static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd)
static int iio_set_length_kfifo(struct iio_buffer *r, int length) static int iio_set_length_kfifo(struct iio_buffer *r, int length)
{ {
/* Avoid an invalid state */
if (length < 2)
length = 2;
if (r->length != length) { if (r->length != length) {
r->length = length; r->length = length;
iio_mark_update_needed_kfifo(r); iio_mark_update_needed_kfifo(r);
...@@ -89,14 +95,16 @@ static int iio_set_length_kfifo(struct iio_buffer *r, int length) ...@@ -89,14 +95,16 @@ static int iio_set_length_kfifo(struct iio_buffer *r, int length)
} }
static int iio_store_to_kfifo(struct iio_buffer *r, static int iio_store_to_kfifo(struct iio_buffer *r,
u8 *data, u8 *data)
s64 timestamp)
{ {
int ret; int ret;
struct iio_kfifo *kf = iio_to_kfifo(r); struct iio_kfifo *kf = iio_to_kfifo(r);
ret = kfifo_in(&kf->kf, data, r->bytes_per_datum); ret = kfifo_in(&kf->kf, data, 1);
if (ret != r->bytes_per_datum) if (ret != 1)
return -EBUSY; return -EBUSY;
r->stufftoread = true;
wake_up_interruptible(&r->pollq);
return 0; return 0;
} }
...@@ -106,11 +114,18 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r, ...@@ -106,11 +114,18 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
int ret, copied; int ret, copied;
struct iio_kfifo *kf = iio_to_kfifo(r); struct iio_kfifo *kf = iio_to_kfifo(r);
if (n < r->bytes_per_datum) if (n < r->bytes_per_datum || r->bytes_per_datum == 0)
return -EINVAL; return -EINVAL;
n = rounddown(n, r->bytes_per_datum);
ret = kfifo_to_user(&kf->kf, buf, n, &copied); ret = kfifo_to_user(&kf->kf, buf, n, &copied);
if (ret < 0)
return ret;
if (kfifo_is_empty(&kf->kf))
r->stufftoread = false;
/* verify it is still empty to avoid race */
if (!kfifo_is_empty(&kf->kf))
r->stufftoread = true;
return copied; return copied;
} }
...@@ -136,7 +151,7 @@ struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev) ...@@ -136,7 +151,7 @@ struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
iio_buffer_init(&kf->buffer); iio_buffer_init(&kf->buffer);
kf->buffer.attrs = &iio_kfifo_attribute_group; kf->buffer.attrs = &iio_kfifo_attribute_group;
kf->buffer.access = &kfifo_access_funcs; kf->buffer.access = &kfifo_access_funcs;
kf->buffer.length = 2;
return &kf->buffer; return &kf->buffer;
} }
EXPORT_SYMBOL(iio_kfifo_allocate); EXPORT_SYMBOL(iio_kfifo_allocate);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment