Commit f62252bf authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-4.19a' of...

Merge tag 'iio-for-4.19a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

First set of IIO new device support, features and cleanups in the 4.19 cycle

The usual mixed bunch.  Particular good to see is the generic
touch screen driver.  Will be interesting to see if this works
for other ADCs without major changes.

Core features
* Channel types
  - New position relative channel type primarily for touch screen
    sensors to feed the generic touchscreen driver.

New device support
* ad5586
  - Add support for the AD5311R DAC.

* Generic touch screen driver as an IIO consumer.
  - Note this is in input, but due to dependencies is coming through
    the IIO tree.
  - Specific support for this added to the at91-sama5d2 ADC.
  - Various necessary DT bindings added.

Staging Drops
* ADIS16060 gyro
  - A device with a very odd interface that was never cleanly supported.
    It's now very difficult to get, so unlikely it'll ever be fixed up.

Cleanups and minor features and fixes
* core
  - Fix y2038 timestamp issues now the core support is in place.
* 104-quad-8
  - Provide some defines for magic numbers to help readability.
  - Fix an off by one error in register selection
* ad7606
  - Put in a missing function parameter name in a prototype.
* adis16023
  - Use generic sign_extend function rather than local version.
* adis16240
  - Use generic sign_extend funciton rather than local version.
* at91-sama5d2
  - Drop dependency on HAS_DMA now this is handled elsewhere.  Will
    improve build test coverage.
  - Add oversampling ratio control.  Note there is a minor ABI change
    here to increase the apparent depth to 14 bits so as to allow
    for transparent provision of different oversampling ratios that
    drop the actual bit depth to 13 or 12 bits.
* hx711
  - Add a MAINTAINERS entry for this device.
* inv_mpu6050
  - Replace the timestamp fifo 'special' code with generic timestamp
    handling.
  - Switch to using local store of timestamp divider rather than rate
    as that is more helpful for accurate time measurement.
  - Fix an unaligned access that didn't seem to be causing any trouble.
  - Use the fifo overflow bit to track the overflow status rather than
    a software counter.
  - New timestamping mechanism to deal with missed sample interrupts.
* stm32-adc
  - Drop HAS_DMA build dependency.
* sun4i-gpadc
  - Select REGMAP_IRQ a very rarely hit build issue fix.
parents 6557dd49 6794e23f
......@@ -197,6 +197,18 @@ Description:
Angle of rotation. Units after application of scale and offset
are radians.
What: /sys/bus/iio/devices/iio:deviceX/in_positionrelative_x_raw
What: /sys/bus/iio/devices/iio:deviceX/in_positionrelative_y_raw
KernelVersion: 4.18
Contact: linux-iio@vger.kernel.org
Description:
Relative position in direction x or y on a pad (may be
arbitrarily assigned but should match other such assignments on
device).
Units after application of scale and offset are milli percents
from the pad's size in both directions. Should be calibrated by
the consumer.
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_raw
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_raw
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_raw
......
......@@ -21,6 +21,14 @@ Optional properties:
- dmas: Phandle to dma channel for the ADC.
- dma-names: Must be "rx" when dmas property is being used.
See ../../dma/dma.txt for details.
- #io-channel-cells: in case consumer drivers are attached, this must be 1.
See <Documentation/devicetree/bindings/iio/iio-bindings.txt> for details.
Properties for consumer drivers:
- Consumer drivers can be connected to this producer device, as specified
in <Documentation/devicetree/bindings/iio/iio-bindings.txt>
- Channels exposed are specified in:
<dt-bindings/iio/adc/at91-sama5d2_adc.txt>
Example:
......@@ -38,4 +46,5 @@ adc: adc@fc030000 {
atmel,trigger-edge-type = <IRQ_TYPE_EDGE_BOTH>;
dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(25))>;
dma-names = "rx";
#io-channel-cells = <1>;
}
Generic resistive touchscreen ADC
Required properties:
- compatible: must be "resistive-adc-touch"
The device must be connected to an ADC device that provides channels for
position measurement and optional pressure.
Refer to ../iio/iio-bindings.txt for details
- iio-channels: must have at least two channels connected to an ADC device.
These should correspond to the channels exposed by the ADC device and should
have the right index as the ADC device registers them. These channels
represent the relative position on the "x" and "y" axes.
- iio-channel-names: must have all the channels' names. Mandatory channels
are "x" and "y".
Optional properties:
- iio-channels: The third channel named "pressure" is optional and can be
used if the ADC device also measures pressure besides position.
If this channel is missing, pressure will be ignored and the touchscreen
will only report position.
- iio-channel-names: optional channel named "pressure".
Example:
resistive_touch: resistive_touch {
compatible = "resistive-adc-touch";
touchscreen-min-pressure = <50000>;
io-channels = <&adc 24>, <&adc 25>, <&adc 26>;
io-channel-names = "x", "y", "pressure";
};
......@@ -7,6 +7,9 @@ Optional properties for Touchscreens:
(in pixels)
- touchscreen-max-pressure : maximum reported pressure (arbitrary range
dependent on the controller)
- touchscreen-min-pressure : minimum pressure on the touchscreen to be
achieved in order for the touchscreen
driver to report a touch event.
- touchscreen-fuzz-x : horizontal noise value of the absolute input
device (in pixels)
- touchscreen-fuzz-y : vertical noise value of the absolute input
......
......@@ -2547,6 +2547,13 @@ S: Maintained
F: drivers/auxdisplay/
F: include/linux/cfag12864b.h
AVIA HX711 ANALOG DIGITAL CONVERTER IIO DRIVER
M: Andreas Klinger <ak@it-klinger.de>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/adc/avia-hx711.txt
F: drivers/iio/adc/hx711.c
AX.25 NETWORK LAYER
M: Ralf Baechle <ralf@linux-mips.org>
L: linux-hams@vger.kernel.org
......@@ -6006,6 +6013,12 @@ F: drivers/base/power/domain*.c
F: include/linux/pm_domain.h
F: Documentation/devicetree/bindings/power/power_domain.txt
GENERIC RESISTIVE TOUCHSCREEN ADC DRIVER
M: Eugen Hristev <eugen.hristev@microchip.com>
L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/touchscreen/resistive-adc-touch.c
GENERIC UIO DRIVER FOR PCI DEVICES
M: "Michael S. Tsirkin" <mst@redhat.com>
L: kvm@vger.kernel.org
......
......@@ -157,7 +157,6 @@ config AT91_SAMA5D2_ADC
tristate "Atmel AT91 SAMA5D2 ADC"
depends on ARCH_AT91 || COMPILE_TEST
depends on HAS_IOMEM
depends on HAS_DMA
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
......@@ -647,7 +646,6 @@ config SD_ADC_MODULATOR
config STM32_ADC_CORE
tristate "STMicroelectronics STM32 adc core"
depends on ARCH_STM32 || COMPILE_TEST
depends on HAS_DMA
depends on OF
depends on REGULATOR
select IIO_BUFFER
......@@ -717,6 +715,7 @@ config SUN4I_GPADC
depends on IIO
depends on MFD_SUN4I_GPADC || MACH_SUN8I
depends on THERMAL || !THERMAL_OF
select REGMAP_IRQ
help
Say yes here to build support for Allwinner (A10, A13 and A31) SoCs
GPADC. This ADC provides 4 channels which can be used as an ADC or as
......
This diff is collapsed.
......@@ -59,6 +59,39 @@ struct quad8_iio {
unsigned int base;
};
#define QUAD8_REG_CHAN_OP 0x11
#define QUAD8_REG_INDEX_INPUT_LEVELS 0x16
/* Borrow Toggle flip-flop */
#define QUAD8_FLAG_BT BIT(0)
/* Carry Toggle flip-flop */
#define QUAD8_FLAG_CT BIT(1)
/* Error flag */
#define QUAD8_FLAG_E BIT(4)
/* Up/Down flag */
#define QUAD8_FLAG_UD BIT(5)
/* Reset and Load Signal Decoders */
#define QUAD8_CTR_RLD 0x00
/* Counter Mode Register */
#define QUAD8_CTR_CMR 0x20
/* Input / Output Control Register */
#define QUAD8_CTR_IOR 0x40
/* Index Control Register */
#define QUAD8_CTR_IDR 0x60
/* Reset Byte Pointer (three byte data pointer) */
#define QUAD8_RLD_RESET_BP 0x01
/* Reset Counter */
#define QUAD8_RLD_RESET_CNTR 0x02
/* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */
#define QUAD8_RLD_RESET_FLAGS 0x04
/* Reset Error flag */
#define QUAD8_RLD_RESET_E 0x06
/* Preset Register to Counter */
#define QUAD8_RLD_PRESET_CNTR 0x08
/* Transfer Counter to Output Latch */
#define QUAD8_RLD_CNTR_OUT 0x10
#define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00
#define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
static int quad8_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
......@@ -72,19 +105,21 @@ static int quad8_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->type == IIO_INDEX) {
*val = !!(inb(priv->base + 0x16) & BIT(chan->channel));
*val = !!(inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS)
& BIT(chan->channel));
return IIO_VAL_INT;
}
flags = inb(base_offset + 1);
borrow = flags & BIT(0);
carry = !!(flags & BIT(1));
borrow = flags & QUAD8_FLAG_BT;
carry = !!(flags & QUAD8_FLAG_CT);
/* Borrow XOR Carry effectively doubles count range */
*val = (borrow ^ carry) << 24;
/* Reset Byte Pointer; transfer Counter to Output Latch */
outb(0x11, base_offset + 1);
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
base_offset + 1);
for (i = 0; i < 3; i++)
*val |= (unsigned int)inb(base_offset) << (8 * i);
......@@ -120,17 +155,17 @@ static int quad8_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
/* Reset Byte Pointer */
outb(0x01, base_offset + 1);
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
/* Counter can only be set via Preset Register */
for (i = 0; i < 3; i++)
outb(val >> (8 * i), base_offset);
/* Transfer Preset Register to Counter */
outb(0x08, base_offset + 1);
outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1);
/* Reset Byte Pointer */
outb(0x01, base_offset + 1);
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
/* Set Preset Register back to original value */
val = priv->preset[chan->channel];
......@@ -138,9 +173,9 @@ static int quad8_write_raw(struct iio_dev *indio_dev,
outb(val >> (8 * i), base_offset);
/* Reset Borrow, Carry, Compare, and Sign flags */
outb(0x02, base_offset + 1);
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
/* Reset Error flag */
outb(0x06, base_offset + 1);
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
return 0;
case IIO_CHAN_INFO_ENABLE:
......@@ -153,7 +188,7 @@ static int quad8_write_raw(struct iio_dev *indio_dev,
ior_cfg = val | priv->preset_enable[chan->channel] << 1;
/* Load I/O control configuration */
outb(0x40 | ior_cfg, base_offset + 1);
outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1);
return 0;
case IIO_CHAN_INFO_SCALE:
......@@ -217,7 +252,7 @@ static ssize_t quad8_write_preset(struct iio_dev *indio_dev, uintptr_t private,
priv->preset[chan->channel] = preset;
/* Reset Byte Pointer */
outb(0x01, base_offset + 1);
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
/* Set Preset Register */
for (i = 0; i < 3; i++)
......@@ -258,7 +293,7 @@ static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev,
(unsigned int)preset_enable << 1;
/* Load I/O control configuration to Input / Output Control Register */
outb(0x40 | ior_cfg, base_offset);
outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
return len;
}
......@@ -274,7 +309,7 @@ static int quad8_get_noise_error(struct iio_dev *indio_dev,
struct quad8_iio *const priv = iio_priv(indio_dev);
const int base_offset = priv->base + 2 * chan->channel + 1;
return !!(inb(base_offset) & BIT(4));
return !!(inb(base_offset) & QUAD8_FLAG_E);
}
static const struct iio_enum quad8_noise_error_enum = {
......@@ -294,7 +329,7 @@ static int quad8_get_count_direction(struct iio_dev *indio_dev,
struct quad8_iio *const priv = iio_priv(indio_dev);
const int base_offset = priv->base + 2 * chan->channel + 1;
return !!(inb(base_offset) & BIT(5));
return !!(inb(base_offset) & QUAD8_FLAG_UD);
}
static const struct iio_enum quad8_count_direction_enum = {
......@@ -324,7 +359,7 @@ static int quad8_set_count_mode(struct iio_dev *indio_dev,
mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3;
/* Load mode configuration to Counter Mode Register */
outb(0x20 | mode_cfg, base_offset);
outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
return 0;
}
......@@ -364,7 +399,7 @@ static int quad8_set_synchronous_mode(struct iio_dev *indio_dev,
priv->synchronous_mode[chan->channel] = synchronous_mode;
/* Load Index Control configuration to Index Control Register */
outb(0x60 | idr_cfg, base_offset);
outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
return 0;
}
......@@ -410,7 +445,7 @@ static int quad8_set_quadrature_mode(struct iio_dev *indio_dev,
priv->quadrature_mode[chan->channel] = quadrature_mode;
/* Load mode configuration to Counter Mode Register */
outb(0x20 | mode_cfg, base_offset);
outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
return 0;
}
......@@ -446,7 +481,7 @@ static int quad8_set_index_polarity(struct iio_dev *indio_dev,
priv->index_polarity[chan->channel] = index_polarity;
/* Load Index Control configuration to Index Control Register */
outb(0x60 | idr_cfg, base_offset);
outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
return 0;
}
......@@ -556,28 +591,28 @@ static int quad8_probe(struct device *dev, unsigned int id)
priv->base = base[id];
/* Reset all counters and disable interrupt function */
outb(0x01, base[id] + 0x11);
outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
/* Set initial configuration for all counters */
for (i = 0; i < QUAD8_NUM_COUNTERS; i++) {
base_offset = base[id] + 2 * i;
/* Reset Byte Pointer */
outb(0x01, base_offset + 1);
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
/* Reset Preset Register */
for (j = 0; j < 3; j++)
outb(0x00, base_offset);
/* Reset Borrow, Carry, Compare, and Sign flags */
outb(0x04, base_offset + 1);
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
/* Reset Error flag */
outb(0x06, base_offset + 1);
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
/* Binary encoding; Normal count; non-quadrature mode */
outb(0x20, base_offset + 1);
outb(QUAD8_CTR_CMR, base_offset + 1);
/* Disable A and B inputs; preset on index; FLG1 as Carry */
outb(0x40, base_offset + 1);
outb(QUAD8_CTR_IOR, base_offset + 1);
/* Disable index function; negative index polarity */
outb(0x60, base_offset + 1);
outb(QUAD8_CTR_IDR, base_offset + 1);
}
/* Enable all counters */
outb(0x00, base[id] + 0x11);
outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
return devm_iio_device_register(dev, indio_dev);
}
......
......@@ -221,6 +221,7 @@ static struct iio_chan_spec name[] = { \
AD5868_CHANNEL(7, 7, bits, _shift), \
}
DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6);
DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0);
DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4);
......@@ -231,6 +232,12 @@ DECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2);
DECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4);
static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
[ID_AD5311R] = {
.channels = ad5311r_channels,
.int_vref_mv = 2500,
.num_channels = 1,
.regmap_type = AD5693_REGMAP,
},
[ID_AD5671R] = {
.channels = ad5672_channels,
.int_vref_mv = 2500,
......
......@@ -45,6 +45,7 @@
* ad5686_supported_device_ids:
*/
enum ad5686_supported_device_ids {
ID_AD5311R,
ID_AD5671R,
ID_AD5672R,
ID_AD5675R,
......
......@@ -71,6 +71,7 @@ static int ad5686_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id ad5686_i2c_id[] = {
{"ad5311r", ID_AD5311R},
{"ad5671r", ID_AD5671R},
{"ad5675r", ID_AD5675R},
{"ad5691r", ID_AD5691R},
......
......@@ -20,8 +20,6 @@
#include <linux/jiffies.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include <linux/iio/iio.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
......@@ -84,7 +82,7 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = {
static const struct inv_mpu6050_chip_config chip_config_6050 = {
.fsr = INV_MPU6050_FSR_2000DPS,
.lpf = INV_MPU6050_FILTER_20HZ,
.fifo_rate = INV_MPU6050_INIT_FIFO_RATE,
.divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE),
.gyro_fifo_enable = false,
.accl_fifo_enable = false,
.accl_fs = INV_MPU6050_FS_02G,
......@@ -280,7 +278,7 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
if (result)
goto error_power_off;
d = INV_MPU6050_ONE_K_HZ / INV_MPU6050_INIT_FIFO_RATE - 1;
d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE);
result = regmap_write(st->map, st->reg->sample_rate_div, d);
if (result)
goto error_power_off;
......@@ -297,6 +295,13 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
memcpy(&st->chip_config, hw_info[st->chip_type].config,
sizeof(struct inv_mpu6050_chip_config));
/*
* Internal chip period is 1ms (1kHz).
* Let's use at the beginning the theorical value before measuring
* with interrupt timestamps.
*/
st->chip_period = NSEC_PER_MSEC;
return inv_mpu6050_set_power_itg(st, false);
error_power_off:
......@@ -630,7 +635,7 @@ static ssize_t
inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
s32 fifo_rate;
int fifo_rate;
u8 d;
int result;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
......@@ -646,8 +651,13 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
if (result)
return result;
/* compute the chip sample rate divider */
d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(fifo_rate);
/* compute back the fifo rate to handle truncation cases */
fifo_rate = INV_MPU6050_DIVIDER_TO_FIFO_RATE(d);
mutex_lock(&st->lock);
if (fifo_rate == st->chip_config.fifo_rate) {
if (d == st->chip_config.divider) {
result = 0;
goto fifo_rate_fail_unlock;
}
......@@ -655,11 +665,10 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
if (result)
goto fifo_rate_fail_unlock;
d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1;
result = regmap_write(st->map, st->reg->sample_rate_div, d);
if (result)
goto fifo_rate_fail_power_off;
st->chip_config.fifo_rate = fifo_rate;
st->chip_config.divider = d;
result = inv_mpu6050_set_lpf(st, fifo_rate);
if (result)
......@@ -687,7 +696,7 @@ inv_fifo_rate_show(struct device *dev, struct device_attribute *attr,
unsigned fifo_rate;
mutex_lock(&st->lock);
fifo_rate = st->chip_config.fifo_rate;
fifo_rate = INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider);
mutex_unlock(&st->lock);
return scnprintf(buf, PAGE_SIZE, "%u\n", fifo_rate);
......@@ -1003,7 +1012,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
indio_dev->modes = INDIO_BUFFER_TRIGGERED;
result = devm_iio_triggered_buffer_setup(dev, indio_dev,
inv_mpu6050_irq_handler,
iio_pollfunc_store_time,
inv_mpu6050_read_fifo,
NULL);
if (result) {
......@@ -1016,8 +1025,6 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
return result;
}
INIT_KFIFO(st->timestamps);
spin_lock_init(&st->time_stamp_lock);
result = devm_iio_device_register(dev, indio_dev);
if (result) {
dev_err(dev, "IIO register fail %d\n", result);
......
......@@ -12,8 +12,6 @@
*/
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
......@@ -88,7 +86,7 @@ enum inv_devices {
* @accl_fs: accel full scale range.
* @accl_fifo_enable: enable accel data output
* @gyro_fifo_enable: enable gyro data output
* @fifo_rate: FIFO update rate.
* @divider: chip sample rate divider (sample rate divider - 1)
*/
struct inv_mpu6050_chip_config {
unsigned int fsr:2;
......@@ -96,7 +94,7 @@ struct inv_mpu6050_chip_config {
unsigned int accl_fs:2;
unsigned int accl_fifo_enable:1;
unsigned int gyro_fifo_enable:1;
u16 fifo_rate;
u8 divider;
u8 user_ctrl;
};
......@@ -116,40 +114,40 @@ struct inv_mpu6050_hw {
/*
* struct inv_mpu6050_state - Driver state variables.
* @TIMESTAMP_FIFO_SIZE: fifo size for timestamp.
* @lock: Chip access lock.
* @trig: IIO trigger.
* @chip_config: Cached attribute information.
* @reg: Map of important registers.
* @hw: Other hardware-specific information.
* @chip_type: chip type.
* @time_stamp_lock: spin lock to time stamp.
* @plat_data: platform data (deprecated in favor of @orientation).
* @orientation: sensor chip orientation relative to main hardware.
* @timestamps: kfifo queue to store time stamp.
* @map regmap pointer.
* @irq interrupt number.
* @irq_mask the int_pin_cfg mask to configure interrupt type.
* @chip_period: chip internal period estimation (~1kHz).
* @it_timestamp: timestamp from previous interrupt.
* @data_timestamp: timestamp for next data sample.
*/
struct inv_mpu6050_state {
#define TIMESTAMP_FIFO_SIZE 16
struct mutex lock;
struct iio_trigger *trig;
struct inv_mpu6050_chip_config chip_config;
const struct inv_mpu6050_reg_map *reg;
const struct inv_mpu6050_hw *hw;
enum inv_devices chip_type;
spinlock_t time_stamp_lock;
struct i2c_mux_core *muxc;
struct i2c_client *mux_client;
unsigned int powerup_count;
struct inv_mpu6050_platform_data plat_data;
struct iio_mount_matrix orientation;
DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
struct regmap *map;
int irq;
u8 irq_mask;
unsigned skip_samples;
s64 chip_period;
s64 it_timestamp;
s64 data_timestamp;
};
/*register and associated bit definition*/
......@@ -174,6 +172,7 @@ struct inv_mpu6050_state {
#define INV_MPU6050_REG_RAW_GYRO 0x43
#define INV_MPU6050_REG_INT_STATUS 0x3A
#define INV_MPU6050_BIT_FIFO_OVERFLOW_INT 0x10
#define INV_MPU6050_BIT_RAW_DATA_RDY_INT 0x01
#define INV_MPU6050_REG_USER_CTRL 0x6A
......@@ -198,7 +197,6 @@ struct inv_mpu6050_state {
#define INV_MPU6050_BYTES_PER_3AXIS_SENSOR 6
#define INV_MPU6050_FIFO_COUNT_BYTE 2
#define INV_MPU6050_FIFO_THRESHOLD 500
/* mpu6500 registers */
#define INV_MPU6500_REG_ACCEL_CONFIG_2 0x1D
......@@ -231,13 +229,24 @@ struct inv_mpu6050_state {
#define INV_MPU6050_LATCH_INT_EN 0x20
#define INV_MPU6050_BIT_BYPASS_EN 0x2
/* Allowed timestamp period jitter in percent */
#define INV_MPU6050_TS_PERIOD_JITTER 4
/* init parameters */
#define INV_MPU6050_INIT_FIFO_RATE 50
#define INV_MPU6050_TIME_STAMP_TOR 5
#define INV_MPU6050_MAX_FIFO_RATE 1000
#define INV_MPU6050_MIN_FIFO_RATE 4
#define INV_MPU6050_ONE_K_HZ 1000
/* chip internal frequency: 1KHz */
#define INV_MPU6050_INTERNAL_FREQ_HZ 1000
/* return the frequency divider (chip sample rate divider + 1) */
#define INV_MPU6050_FREQ_DIVIDER(st) \
((st)->chip_config.divider + 1)
/* chip sample rate divider to fifo rate */
#define INV_MPU6050_FIFO_RATE_TO_DIVIDER(fifo_rate) \
((INV_MPU6050_INTERNAL_FREQ_HZ / (fifo_rate)) - 1)
#define INV_MPU6050_DIVIDER_TO_FIFO_RATE(divider) \
(INV_MPU6050_INTERNAL_FREQ_HZ / ((divider) + 1))
#define INV_MPU6050_REG_WHOAMI 117
......@@ -300,7 +309,6 @@ enum inv_mpu6050_clock_sel_e {
NUM_CLK
};
irqreturn_t inv_mpu6050_irq_handler(int irq, void *p);
irqreturn_t inv_mpu6050_read_fifo(int irq, void *p);
int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type);
int inv_reset_fifo(struct iio_dev *indio_dev);
......
......@@ -19,18 +19,83 @@
#include <linux/jiffies.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kfifo.h>
#include <linux/poll.h>
#include <linux/math64.h>
#include <asm/unaligned.h>
#include "inv_mpu_iio.h"
static void inv_clear_kfifo(struct inv_mpu6050_state *st)
/**
* inv_mpu6050_update_period() - Update chip internal period estimation
*
* @st: driver state
* @timestamp: the interrupt timestamp
* @nb: number of data set in the fifo
*
* This function uses interrupt timestamps to estimate the chip period and
* to choose the data timestamp to come.
*/
static void inv_mpu6050_update_period(struct inv_mpu6050_state *st,
s64 timestamp, size_t nb)
{
unsigned long flags;
/* Period boundaries for accepting timestamp */
const s64 period_min =
(NSEC_PER_MSEC * (100 - INV_MPU6050_TS_PERIOD_JITTER)) / 100;
const s64 period_max =
(NSEC_PER_MSEC * (100 + INV_MPU6050_TS_PERIOD_JITTER)) / 100;
const s32 divider = INV_MPU6050_FREQ_DIVIDER(st);
s64 delta, interval;
bool use_it_timestamp = false;
if (st->it_timestamp == 0) {
/* not initialized, forced to use it_timestamp */
use_it_timestamp = true;
} else if (nb == 1) {
/*
* Validate the use of it timestamp by checking if interrupt
* has been delayed.
* nb > 1 means interrupt was delayed for more than 1 sample,
* so it's obviously not good.
* Compute the chip period between 2 interrupts for validating.
*/
delta = div_s64(timestamp - st->it_timestamp, divider);
if (delta > period_min && delta < period_max) {
/* update chip period and use it timestamp */
st->chip_period = (st->chip_period + delta) / 2;
use_it_timestamp = true;
}
}
if (use_it_timestamp) {
/*
* Manage case of multiple samples in the fifo (nb > 1):
* compute timestamp corresponding to the first sample using
* estimated chip period.
*/
interval = (nb - 1) * st->chip_period * divider;
st->data_timestamp = timestamp - interval;
}
/* take the spin lock sem to avoid interrupt kick in */
spin_lock_irqsave(&st->time_stamp_lock, flags);
kfifo_reset(&st->timestamps);
spin_unlock_irqrestore(&st->time_stamp_lock, flags);
/* save it timestamp */
st->it_timestamp = timestamp;
}
/**
* inv_mpu6050_get_timestamp() - Return the current data timestamp
*
* @st: driver state
* @return: current data timestamp
*
* This function returns the current data timestamp and prepares for next one.
*/
static s64 inv_mpu6050_get_timestamp(struct inv_mpu6050_state *st)
{
s64 ts;
/* return current data timestamp and increment */
ts = st->data_timestamp;
st->data_timestamp += st->chip_period * INV_MPU6050_FREQ_DIVIDER(st);
return ts;
}
int inv_reset_fifo(struct iio_dev *indio_dev)
......@@ -39,6 +104,9 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
u8 d;
struct inv_mpu6050_state *st = iio_priv(indio_dev);
/* reset it timestamp validation */
st->it_timestamp = 0;
/* disable interrupt */
result = regmap_write(st->map, st->reg->int_enable, 0);
if (result) {
......@@ -62,9 +130,6 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
if (result)
goto reset_fifo_fail;
/* clear timestamps fifo */
inv_clear_kfifo(st);
/* enable interrupt */
if (st->chip_config.accl_fifo_enable ||
st->chip_config.gyro_fifo_enable) {
......@@ -98,23 +163,6 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
return result;
}
/**
* inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt.
*/
irqreturn_t inv_mpu6050_irq_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct inv_mpu6050_state *st = iio_priv(indio_dev);
s64 timestamp;
timestamp = iio_get_time_ns(indio_dev);
kfifo_in_spinlocked(&st->timestamps, &timestamp, 1,
&st->time_stamp_lock);
return IRQ_WAKE_THREAD;
}
/**
* inv_mpu6050_read_fifo() - Transfer data from hardware FIFO to KFIFO.
*/
......@@ -129,6 +177,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
u16 fifo_count;
s64 timestamp;
int int_status;
size_t i, nb;
mutex_lock(&st->lock);
......@@ -139,6 +188,9 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
"failed to ack interrupt\n");
goto flush_fifo;
}
/* handle fifo overflow by reseting fifo */
if (int_status & INV_MPU6050_BIT_FIFO_OVERFLOW_INT)
goto flush_fifo;
if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT)) {
dev_warn(regmap_get_device(st->map),
"spurious interrupt with status 0x%x\n", int_status);
......@@ -163,38 +215,23 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
INV_MPU6050_FIFO_COUNT_BYTE);
if (result)
goto end_session;
fifo_count = be16_to_cpup((__be16 *)(&data[0]));
if (fifo_count < bytes_per_datum)
goto end_session;
/* fifo count can't be an odd number. If it is odd, reset the FIFO. */
if (fifo_count & 1)
goto flush_fifo;
if (fifo_count > INV_MPU6050_FIFO_THRESHOLD)
goto flush_fifo;
/* Timestamp mismatch. */
if (kfifo_len(&st->timestamps) >
fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR)
goto flush_fifo;
do {
fifo_count = get_unaligned_be16(&data[0]);
/* compute and process all complete datum */
nb = fifo_count / bytes_per_datum;
inv_mpu6050_update_period(st, pf->timestamp, nb);
for (i = 0; i < nb; ++i) {
result = regmap_bulk_read(st->map, st->reg->fifo_r_w,
data, bytes_per_datum);
if (result)
goto flush_fifo;
result = kfifo_out(&st->timestamps, &timestamp, 1);
/* when there is no timestamp, put timestamp as 0 */
if (result == 0)
timestamp = 0;
/* skip first samples if needed */
if (st->skip_samples)
if (st->skip_samples) {
st->skip_samples--;
else
iio_push_to_buffers_with_timestamp(indio_dev, data,
timestamp);
fifo_count -= bytes_per_datum;
} while (fifo_count >= bytes_per_datum);
continue;
}
timestamp = inv_mpu6050_get_timestamp(st);
iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp);
}
end_session:
mutex_unlock(&st->lock);
......
......@@ -85,6 +85,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_COUNT] = "count",
[IIO_INDEX] = "index",
[IIO_GRAVITY] = "gravity",
[IIO_POSITIONRELATIVE] = "positionrelative",
};
static const char * const iio_modifier_names[] = {
......@@ -207,35 +208,27 @@ static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
*/
s64 iio_get_time_ns(const struct iio_dev *indio_dev)
{
struct timespec tp;
struct timespec64 tp;
switch (iio_device_get_clock(indio_dev)) {
case CLOCK_REALTIME:
ktime_get_real_ts(&tp);
break;
return ktime_get_real_ns();
case CLOCK_MONOTONIC:
ktime_get_ts(&tp);
break;
return ktime_get_ns();
case CLOCK_MONOTONIC_RAW:
getrawmonotonic(&tp);
break;
return ktime_get_raw_ns();
case CLOCK_REALTIME_COARSE:
tp = current_kernel_time();
break;
return ktime_to_ns(ktime_get_coarse_real());
case CLOCK_MONOTONIC_COARSE:
tp = get_monotonic_coarse();
break;
ktime_get_coarse_ts64(&tp);
return timespec64_to_ns(&tp);
case CLOCK_BOOTTIME:
get_monotonic_boottime(&tp);
break;
return ktime_get_boot_ns();
case CLOCK_TAI:
timekeeping_clocktai(&tp);
break;
return ktime_get_tai_ns();
default:
BUG();
}
return timespec_to_ns(&tp);
}
EXPORT_SYMBOL(iio_get_time_ns);
......
......@@ -92,6 +92,19 @@ config TOUCHSCREEN_AD7879_SPI
To compile this driver as a module, choose M here: the
module will be called ad7879-spi.
config TOUCHSCREEN_ADC
tristate "Generic ADC based resistive touchscreen"
depends on IIO
select IIO_BUFFER_CB
help
Say Y here if you want to use the generic ADC
resistive touchscreen driver.
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 resistive-adc-touch.ko.
config TOUCHSCREEN_AR1021_I2C
tristate "Microchip AR1020/1021 i2c touchscreen"
depends on I2C && OF
......
......@@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADC) += resistive-adc-touch.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* ADC generic resistive touchscreen (GRTS)
* This is a generic input driver that connects to an ADC
* given the channels in device tree, and reports events to the input
* subsystem.
*
* Copyright (C) 2017,2018 Microchip Technology,
* Author: Eugen Hristev <eugen.hristev@microchip.com>
*
*/
#include <linux/input.h>
#include <linux/input/touchscreen.h>
#include <linux/iio/consumer.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#define DRIVER_NAME "resistive-adc-touch"
#define GRTS_DEFAULT_PRESSURE_MIN 50000
#define GRTS_MAX_POS_MASK GENMASK(11, 0)
/**
* grts_state - generic resistive touch screen information struct
* @pressure_min: number representing the minimum for the pressure
* @pressure: are we getting pressure info or not
* @iio_chans: list of channels acquired
* @iio_cb: iio_callback buffer for the data
* @input: the input device structure that we register
* @prop: touchscreen properties struct
*/
struct grts_state {
u32 pressure_min;
bool pressure;
struct iio_channel *iio_chans;
struct iio_cb_buffer *iio_cb;
struct input_dev *input;
struct touchscreen_properties prop;
};
static int grts_cb(const void *data, void *private)
{
const u16 *touch_info = data;
struct grts_state *st = private;
unsigned int x, y, press = 0x0;
/* channel data coming in buffer in the order below */
x = touch_info[0];
y = touch_info[1];
if (st->pressure)
press = touch_info[2];
if ((!x && !y) || (st->pressure && (press < st->pressure_min))) {
/* report end of touch */
input_report_key(st->input, BTN_TOUCH, 0);
input_sync(st->input);
return 0;
}
/* report proper touch to subsystem*/
touchscreen_report_pos(st->input, &st->prop, x, y, false);
if (st->pressure)
input_report_abs(st->input, ABS_PRESSURE, press);
input_report_key(st->input, BTN_TOUCH, 1);
input_sync(st->input);
return 0;
}
static int grts_open(struct input_dev *dev)
{
int error;
struct grts_state *st = input_get_drvdata(dev);
error = iio_channel_start_all_cb(st->iio_cb);
if (error) {
dev_err(dev->dev.parent, "failed to start callback buffer.\n");
return error;
}
return 0;
}
static void grts_close(struct input_dev *dev)
{
struct grts_state *st = input_get_drvdata(dev);
iio_channel_stop_all_cb(st->iio_cb);
}
static void grts_disable(void *data)
{
iio_channel_release_all_cb(data);
}
static int grts_probe(struct platform_device *pdev)
{
struct grts_state *st;
struct input_dev *input;
struct device *dev = &pdev->dev;
struct iio_channel *chan;
int error;
st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL);
if (!st)
return -ENOMEM;
/* get the channels from IIO device */
st->iio_chans = devm_iio_channel_get_all(dev);
if (IS_ERR(st->iio_chans)) {
error = PTR_ERR(st->iio_chans);
if (error != -EPROBE_DEFER)
dev_err(dev, "can't get iio channels.\n");
return error;
}
chan = &st->iio_chans[0];
st->pressure = false;
while (chan && chan->indio_dev) {
if (!strcmp(chan->channel->datasheet_name, "pressure"))
st->pressure = true;
chan++;
}
if (st->pressure) {
error = device_property_read_u32(dev,
"touchscreen-min-pressure",
&st->pressure_min);
if (error) {
dev_dbg(dev, "can't get touchscreen-min-pressure property.\n");
st->pressure_min = GRTS_DEFAULT_PRESSURE_MIN;
}
}
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "failed to allocate input device.\n");
return -ENOMEM;
}
input->name = DRIVER_NAME;
input->id.bustype = BUS_HOST;
input->open = grts_open;
input->close = grts_close;
input_set_abs_params(input, ABS_X, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
if (st->pressure)
input_set_abs_params(input, ABS_PRESSURE, st->pressure_min,
0xffff, 0, 0);
input_set_capability(input, EV_KEY, BTN_TOUCH);
/* parse optional device tree properties */
touchscreen_parse_properties(input, false, &st->prop);
st->input = input;
input_set_drvdata(input, st);
error = input_register_device(input);
if (error) {
dev_err(dev, "failed to register input device.");
return error;
}
st->iio_cb = iio_channel_get_all_cb(dev, grts_cb, st);
if (IS_ERR(st->iio_cb)) {
dev_err(dev, "failed to allocate callback buffer.\n");
return PTR_ERR(st->iio_cb);
}
error = devm_add_action_or_reset(dev, grts_disable, st->iio_cb);
if (error) {
dev_err(dev, "failed to add disable action.\n");
return error;
}
return 0;
}
static const struct of_device_id grts_of_match[] = {
{
.compatible = "resistive-adc-touch",
}, {
/* sentinel */
},
};
MODULE_DEVICE_TABLE(of, grts_of_match);
static struct platform_driver grts_driver = {
.probe = grts_probe,
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(grts_of_match),
},
};
module_platform_driver(grts_driver);
MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
MODULE_DESCRIPTION("Generic ADC Resistive Touch Driver");
MODULE_LICENSE("GPL v2");
......@@ -9,7 +9,6 @@ source "drivers/staging/iio/adc/Kconfig"
source "drivers/staging/iio/addac/Kconfig"
source "drivers/staging/iio/cdc/Kconfig"
source "drivers/staging/iio/frequency/Kconfig"
source "drivers/staging/iio/gyro/Kconfig"
source "drivers/staging/iio/impedance-analyzer/Kconfig"
source "drivers/staging/iio/meter/Kconfig"
source "drivers/staging/iio/resolver/Kconfig"
......
......@@ -8,7 +8,6 @@ obj-y += adc/
obj-y += addac/
obj-y += cdc/
obj-y += frequency/
obj-y += gyro/
obj-y += impedance-analyzer/
obj-y += meter/
obj-y += resolver/
......@@ -168,7 +168,6 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
{
struct adis *st = iio_priv(indio_dev);
int ret;
int bits;
u8 addr;
s16 val16;
......@@ -202,14 +201,11 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
*val = 25000 / -470 - 1278; /* 25 C = 1278 */
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS:
bits = 14;
addr = adis16203_addresses[chan->scan_index];
ret = adis_read_reg_16(st, addr, &val16);
if (ret)
return ret;
val16 &= (1 << bits) - 1;
val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
*val = val16;
*val = sign_extend32(val16, 13);
return IIO_VAL_INT;
default:
return -EINVAL;
......
......@@ -250,7 +250,6 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
{
struct adis *st = iio_priv(indio_dev);
int ret;
int bits;
u8 addr;
s16 val16;
......@@ -287,24 +286,18 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
*val = 25000 / 244 - 0x133; /* 25 C = 0x133 */
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS:
bits = 10;
addr = adis16240_addresses[chan->scan_index][0];
ret = adis_read_reg_16(st, addr, &val16);
if (ret)
return ret;
val16 &= (1 << bits) - 1;
val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
*val = val16;
*val = sign_extend32(val16, 9);
return IIO_VAL_INT;
case IIO_CHAN_INFO_PEAK:
bits = 10;
addr = adis16240_addresses[chan->scan_index][1];
ret = adis_read_reg_16(st, addr, &val16);
if (ret)
return ret;
val16 &= (1 << bits) - 1;
val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
*val = val16;
*val = sign_extend32(val16, 9);
return IIO_VAL_INT;
}
return -EINVAL;
......
......@@ -57,7 +57,7 @@ struct ad7606_state {
struct ad7606_bus_ops {
/* more methods added in future? */
int (*read_block)(struct device *, int, void *);
int (*read_block)(struct device *dev, int num, void *data);
};
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
......
#
# IIO Digital Gyroscope Sensor drivers configuration
#
menu "Digital gyroscope sensors"
config ADIS16060
tristate "Analog Devices ADIS16060 Yaw Rate Gyroscope with SPI driver"
depends on SPI
help
Say Y (yes) here to build support for Analog Devices adis16060 wide bandwidth
yaw rate gyroscope with SPI.
To compile this driver as a module, say M here: the module will be
called adis16060. If unsure, say N.
endmenu
#
# Makefile for digital gyroscope sensor drivers
#
adis16060-y := adis16060_core.o
obj-$(CONFIG_ADIS16060) += adis16060.o
/*
* ADIS16060 Wide Bandwidth Yaw Rate Gyroscope with SPI driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define ADIS16060_GYRO 0x20 /* Measure Angular Rate (Gyro) */
#define ADIS16060_TEMP_OUT 0x10 /* Measure Temperature */
#define ADIS16060_AIN2 0x80 /* Measure AIN2 */
#define ADIS16060_AIN1 0x40 /* Measure AIN1 */
/**
* struct adis16060_state - device instance specific data
* @us_w: actual spi_device to write config
* @us_r: actual spi_device to read back data
* @buf: transmit or receive buffer
* @buf_lock: mutex to protect tx and rx
**/
struct adis16060_state {
struct spi_device *us_w;
struct spi_device *us_r;
struct mutex buf_lock;
u8 buf[3] ____cacheline_aligned;
};
static struct iio_dev *adis16060_iio_dev;
static int adis16060_spi_write_then_read(struct iio_dev *indio_dev,
u8 conf, u16 *val)
{
int ret;
struct adis16060_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->buf[2] = conf; /* The last 8 bits clocked in are latched */
ret = spi_write(st->us_w, st->buf, 3);
if (ret < 0) {
mutex_unlock(&st->buf_lock);
return ret;
}
ret = spi_read(st->us_r, st->buf, 3);
/* The internal successive approximation ADC begins the
* conversion process on the falling edge of MSEL1 and
* starts to place data MSB first on the DOUT line at
* the 6th falling edge of SCLK
*/
if (!ret)
*val = ((st->buf[0] & 0x3) << 12) |
(st->buf[1] << 4) |
((st->buf[2] >> 4) & 0xF);
mutex_unlock(&st->buf_lock);
return ret;
}
static int adis16060_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2,
long mask)
{
u16 tval = 0;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = adis16060_spi_write_then_read(indio_dev,
chan->address, &tval);
if (ret < 0)
return ret;
*val = tval;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
*val = -7;
*val2 = 461117;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = 34000;
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
static const struct iio_info adis16060_info = {
.read_raw = adis16060_read_raw,
};
static const struct iio_chan_spec adis16060_channels[] = {
{
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.address = ADIS16060_GYRO,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.address = ADIS16060_AIN1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.address = ADIS16060_AIN2,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16060_TEMP_OUT,
}
};
static int adis16060_r_probe(struct spi_device *spi)
{
int ret;
struct adis16060_state *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
st->us_r = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16060_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = adis16060_channels;
indio_dev->num_channels = ARRAY_SIZE(adis16060_channels);
ret = devm_iio_device_register(&spi->dev, indio_dev);
if (ret)
return ret;
adis16060_iio_dev = indio_dev;
return 0;
}
static int adis16060_w_probe(struct spi_device *spi)
{
int ret;
struct iio_dev *indio_dev = adis16060_iio_dev;
struct adis16060_state *st;
if (!indio_dev) {
ret = -ENODEV;
goto error_ret;
}
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->us_w = spi;
return 0;
error_ret:
return ret;
}
static int adis16060_w_remove(struct spi_device *spi)
{
return 0;
}
static struct spi_driver adis16060_r_driver = {
.driver = {
.name = "adis16060_r",
},
.probe = adis16060_r_probe,
};
static struct spi_driver adis16060_w_driver = {
.driver = {
.name = "adis16060_w",
},
.probe = adis16060_w_probe,
.remove = adis16060_w_remove,
};
static __init int adis16060_init(void)
{
int ret;
ret = spi_register_driver(&adis16060_r_driver);
if (ret < 0)
return ret;
ret = spi_register_driver(&adis16060_w_driver);
if (ret < 0) {
spi_unregister_driver(&adis16060_r_driver);
return ret;
}
return 0;
}
module_init(adis16060_init);
static __exit void adis16060_exit(void)
{
spi_unregister_driver(&adis16060_w_driver);
spi_unregister_driver(&adis16060_r_driver);
}
module_exit(adis16060_exit);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADIS16060 Yaw Rate Gyroscope Driver");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This header provides constants for configuring the AT91 SAMA5D2 ADC
*/
#ifndef _DT_BINDINGS_IIO_ADC_AT91_SAMA5D2_ADC_H
#define _DT_BINDINGS_IIO_ADC_AT91_SAMA5D2_ADC_H
/* X relative position channel index */
#define AT91_SAMA5D2_ADC_X_CHANNEL 24
/* Y relative position channel index */
#define AT91_SAMA5D2_ADC_Y_CHANNEL 25
/* pressure channel index */
#define AT91_SAMA5D2_ADC_P_CHANNEL 26
#endif
......@@ -44,6 +44,7 @@ enum iio_chan_type {
IIO_COUNT,
IIO_INDEX,
IIO_GRAVITY,
IIO_POSITIONRELATIVE,
};
enum iio_modifier {
......
......@@ -58,6 +58,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_PH] = "ph",
[IIO_UVINDEX] = "uvindex",
[IIO_GRAVITY] = "gravity",
[IIO_POSITIONRELATIVE] = "positionrelative",
};
static const char * const iio_ev_type_text[] = {
......@@ -151,6 +152,7 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_PH:
case IIO_UVINDEX:
case IIO_GRAVITY:
case IIO_POSITIONRELATIVE:
break;
default:
return false;
......
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