- reg: Address and length of the register set for the device
- interrupts: Should contain the LRADC interrupts
+Optional properties:
+- fsl,lradc-touchscreen-wires: Number of wires used to connect the touchscreen
+ to LRADC. Valid value is either 4 or 5. If this
+ property is not present, then the touchscreen is
+ disabled.
+
Examples:
lradc@80050000 {
};
lradc@80050000 {
+ compatible = "fsl,imx23-lradc";
reg = <0x80050000 0x2000>;
+ interrupts = <36 37 38 39 40 41 42 43 44>;
status = "disabled";
};
#include <media/si4713.h>
#include <linux/leds-lp5523.h>
-#include <../drivers/staging/iio/light/tsl2563.h>
+#include <linux/platform_data/tsl2563.h>
#include <linux/lis3lv02d.h>
#if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE)
Say yes here to build support for the HID SENSOR
accelerometers 3D.
+config KXSD9
+ tristate "Kionix KXSD9 Accelerometer Driver"
+ depends on SPI
+ help
+ Say yes here to build support for the Kionix KXSD9 accelerometer.
+ Currently this only supports the device via an SPI interface.
+
endmenu
#
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
+obj-$(CONFIG_KXSD9) += kxsd9.o
{
struct iio_dev *indio_dev;
struct kxsd9_state *st;
- int ret = 0;
+ int ret;
indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
indio_dev->info = &kxsd9_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_free_dev;
-
spi->mode = SPI_MODE_0;
spi_setup(spi);
kxsd9_power_up(st);
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_free_dev;
+
return 0;
error_free_dev:
config MAX1363
tristate "Maxim max1363 ADC driver"
depends on I2C
- select IIO_TRIGGER
- select MAX1363_RING_BUFFER
select IIO_BUFFER
- select IIO_KFIFO_BUF
+ select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for many Maxim i2c analog to digital
converters (ADC). (max1361, max1362, max1363, max1364, max1036,
#
menu "Digital gyroscope sensors"
+config ADIS16080
+ tristate "Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices ADIS16080, ADIS16100 Yaw
+ Rate Gyroscope with SPI.
+
config ADIS16136
tristate "Analog devices ADIS16136 and similar gyroscopes driver"
depends on SPI_MASTER
# Makefile for industrial I/O gyroscope sensor drivers
#
+obj-$(CONFIG_ADIS16080) += adis16080.o
obj-$(CONFIG_ADIS16136) += adis16136.o
obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
#define ADIS16080_DIN_WRITE (1 << 15)
+struct adis16080_chip_info {
+ int scale_val;
+ int scale_val2;
+};
+
/**
* struct adis16080_state - device instance specific data
* @us: actual spi_device to write data
+ * @info: chip specific parameters
* @buf: transmit or receive buffer
- * @buf_lock: mutex to protect tx and rx
**/
struct adis16080_state {
struct spi_device *us;
- struct mutex buf_lock;
+ const struct adis16080_chip_info *info;
- u8 buf[2] ____cacheline_aligned;
+ __be16 buf ____cacheline_aligned;
};
-static int adis16080_spi_write(struct iio_dev *indio_dev,
- u16 val)
+static int adis16080_read_sample(struct iio_dev *indio_dev,
+ u16 addr, int *val)
{
- int ret;
struct adis16080_state *st = iio_priv(indio_dev);
-
- mutex_lock(&st->buf_lock);
- st->buf[0] = val >> 8;
- st->buf[1] = val;
-
- ret = spi_write(st->us, st->buf, 2);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-static int adis16080_spi_read(struct iio_dev *indio_dev,
- u16 *val)
-{
+ struct spi_message m;
int ret;
- struct adis16080_state *st = iio_priv(indio_dev);
+ struct spi_transfer t[] = {
+ {
+ .tx_buf = &st->buf,
+ .len = 2,
+ .cs_change = 1,
+ }, {
+ .rx_buf = &st->buf,
+ .len = 2,
+ },
+ };
- mutex_lock(&st->buf_lock);
+ st->buf = cpu_to_be16(addr | ADIS16080_DIN_WRITE);
- ret = spi_read(st->us, st->buf, 2);
+ spi_message_init(&m);
+ spi_message_add_tail(&t[0], &m);
+ spi_message_add_tail(&t[1], &m);
+ ret = spi_sync(st->us, &m);
if (ret == 0)
- *val = sign_extend32(((st->buf[0] & 0xF) << 8) | st->buf[1], 11);
- mutex_unlock(&st->buf_lock);
+ *val = sign_extend32(be16_to_cpu(st->buf), 11);
return ret;
}
int *val2,
long mask)
{
- int ret = -EINVAL;
- u16 ut = 0;
- /* Take the iio_dev status lock */
+ struct adis16080_state *st = iio_priv(indio_dev);
+ int ret;
- mutex_lock(&indio_dev->mlock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = adis16080_spi_write(indio_dev,
- chan->address |
- ADIS16080_DIN_WRITE);
- if (ret < 0)
- break;
- ret = adis16080_spi_read(indio_dev, &ut);
- if (ret < 0)
- break;
- *val = ut;
- ret = IIO_VAL_INT;
+ mutex_lock(&indio_dev->mlock);
+ ret = adis16080_read_sample(indio_dev, chan->address, val);
+ mutex_unlock(&indio_dev->mlock);
+ return ret ? ret : IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ *val = st->info->scale_val;
+ *val2 = st->info->scale_val2;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_VOLTAGE:
+ /* VREF = 5V, 12 bits */
+ *val = 5000;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_TEMP:
+ /* 85 C = 585, 25 C = 0 */
+ *val = 85000 - 25000;
+ *val2 = 585;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ /* 2.5 V = 0 */
+ *val = 2048;
+ return IIO_VAL_INT;
+ case IIO_TEMP:
+ /* 85 C = 585, 25 C = 0 */
+ *val = DIV_ROUND_CLOSEST(25 * 585, 85 - 25);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
break;
}
- mutex_unlock(&indio_dev->mlock);
- return ret;
+ return -EINVAL;
}
static const struct iio_chan_spec adis16080_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = ADIS16080_DIN_GYRO,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.address = ADIS16080_DIN_AIN1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.address = ADIS16080_DIN_AIN2,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.address = ADIS16080_DIN_TEMP,
}
};
.driver_module = THIS_MODULE,
};
+enum {
+ ID_ADIS16080,
+ ID_ADIS16100,
+};
+
+static const struct adis16080_chip_info adis16080_chip_info[] = {
+ [ID_ADIS16080] = {
+ /* 80 degree = 819, 819 rad = 46925 degree */
+ .scale_val = 80,
+ .scale_val2 = 46925,
+ },
+ [ID_ADIS16100] = {
+ /* 300 degree = 1230, 1230 rad = 70474 degree */
+ .scale_val = 300,
+ .scale_val2 = 70474,
+ },
+};
+
static int adis16080_probe(struct spi_device *spi)
{
+ const struct spi_device_id *id = spi_get_device_id(spi);
int ret;
struct adis16080_state *st;
struct iio_dev *indio_dev;
/* Allocate the comms buffers */
st->us = spi;
- mutex_init(&st->buf_lock);
+ st->info = &adis16080_chip_info[id->driver_data];
indio_dev->name = spi->dev.driver->name;
indio_dev->channels = adis16080_channels;
return ret;
}
-/* fixme, confirm ordering in this function */
static int adis16080_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
return 0;
}
+static const struct spi_device_id adis16080_ids[] = {
+ { "adis16080", ID_ADIS16080 },
+ { "adis16100", ID_ADIS16100 },
+ {},
+};
+MODULE_DEVICE_TABLE(spi, adis16080_ids);
+
static struct spi_driver adis16080_driver = {
.driver = {
.name = "adis16080",
},
.probe = adis16080_probe,
.remove = adis16080_remove,
+ .id_table = adis16080_ids,
};
module_spi_driver(adis16080_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope Driver");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:adis16080");
#
menu "Inertial measurement units"
+config ADIS16400
+ tristate "Analog Devices ADIS16400 and similar IMU SPI driver"
+ depends on SPI
+ select IIO_ADIS_LIB
+ select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
+ help
+ Say yes here to build support for Analog Devices adis16300, adis16344,
+ adis16350, adis16354, adis16355, adis16360, adis16362, adis16364,
+ adis16365, adis16400 and adis16405 triaxial inertial sensors
+ (adis16400 series also have magnetometers).
+
config ADIS16480
tristate "Analog Devices ADIS16480 and similar IMU driver"
depends on SPI
# Makefile for Inertial Measurement Units
#
+adis16400-y := adis16400_core.o
+adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o
+obj-$(CONFIG_ADIS16400) += adis16400.o
obj-$(CONFIG_ADIS16480) += adis16480.o
adis_lib-y += adis.o
#ifndef SPI_ADIS16400_H_
#define SPI_ADIS16400_H_
+#include <linux/iio/imu/adis.h>
+
#define ADIS16400_STARTUP_DELAY 290 /* ms */
#define ADIS16400_MTEST_DELAY 90 /* ms */
-#define ADIS16400_READ_REG(a) a
-#define ADIS16400_WRITE_REG(a) ((a) | 0x80)
-
#define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */
#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */
#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */
#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */
#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */
+#define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */
+#define ADIS16448_TEMP_OUT 0x18 /* Temperature output */
+
/* Calibration parameters */
#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */
#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */
#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */
#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */
+#define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */
+#define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */
#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */
+#define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */
#define ADIS16400_ERROR_ACTIVE (1<<14)
#define ADIS16400_NEW_DATA (1<<14)
#define ADIS16400_SMPL_PRD_DIV_MASK 0x7F
/* DIAG_STAT */
-#define ADIS16400_DIAG_STAT_ZACCL_FAIL (1<<15)
-#define ADIS16400_DIAG_STAT_YACCL_FAIL (1<<14)
-#define ADIS16400_DIAG_STAT_XACCL_FAIL (1<<13)
-#define ADIS16400_DIAG_STAT_XGYRO_FAIL (1<<12)
-#define ADIS16400_DIAG_STAT_YGYRO_FAIL (1<<11)
-#define ADIS16400_DIAG_STAT_ZGYRO_FAIL (1<<10)
-#define ADIS16400_DIAG_STAT_ALARM2 (1<<9)
-#define ADIS16400_DIAG_STAT_ALARM1 (1<<8)
-#define ADIS16400_DIAG_STAT_FLASH_CHK (1<<6)
-#define ADIS16400_DIAG_STAT_SELF_TEST (1<<5)
-#define ADIS16400_DIAG_STAT_OVERFLOW (1<<4)
-#define ADIS16400_DIAG_STAT_SPI_FAIL (1<<3)
-#define ADIS16400_DIAG_STAT_FLASH_UPT (1<<2)
-#define ADIS16400_DIAG_STAT_POWER_HIGH (1<<1)
-#define ADIS16400_DIAG_STAT_POWER_LOW (1<<0)
+#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15
+#define ADIS16400_DIAG_STAT_YACCL_FAIL 14
+#define ADIS16400_DIAG_STAT_XACCL_FAIL 13
+#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12
+#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11
+#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10
+#define ADIS16400_DIAG_STAT_ALARM2 9
+#define ADIS16400_DIAG_STAT_ALARM1 8
+#define ADIS16400_DIAG_STAT_FLASH_CHK 6
+#define ADIS16400_DIAG_STAT_SELF_TEST 5
+#define ADIS16400_DIAG_STAT_OVERFLOW 4
+#define ADIS16400_DIAG_STAT_SPI_FAIL 3
+#define ADIS16400_DIAG_STAT_FLASH_UPT 2
+#define ADIS16400_DIAG_STAT_POWER_HIGH 1
+#define ADIS16400_DIAG_STAT_POWER_LOW 0
/* GLOB_CMD */
#define ADIS16400_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16334_RATE_DIV_SHIFT 8
#define ADIS16334_RATE_INT_CLK BIT(0)
-#define ADIS16400_MAX_TX 24
-#define ADIS16400_MAX_RX 24
-
#define ADIS16400_SPI_SLOW (u32)(300 * 1000)
#define ADIS16400_SPI_BURST (u32)(1000 * 1000)
#define ADIS16400_SPI_FAST (u32)(2000 * 1000)
#define ADIS16400_HAS_PROD_ID BIT(0)
#define ADIS16400_NO_BURST BIT(1)
#define ADIS16400_HAS_SLOW_MODE BIT(2)
+#define ADIS16400_HAS_SERIAL_NUMBER BIT(3)
+
+struct adis16400_state;
struct adis16400_chip_info {
const struct iio_chan_spec *channels;
unsigned int accel_scale_micro;
int temp_scale_nano;
int temp_offset;
- unsigned long default_scan_mask;
- int (*set_freq)(struct iio_dev *indio_dev, unsigned int freq);
- int (*get_freq)(struct iio_dev *indio_dev);
+ int (*set_freq)(struct adis16400_state *st, unsigned int freq);
+ int (*get_freq)(struct adis16400_state *st);
};
/**
* struct adis16400_state - device instance specific data
- * @us: actual spi_device
- * @trig: data ready trigger registered with iio
- * @tx: transmit buffer
- * @rx: receive buffer
- * @buf_lock: mutex to protect tx and rx
- * @filt_int: integer part of requested filter frequency
+ * @variant: chip variant info
+ * @filt_int: integer part of requested filter frequency
+ * @adis: adis device
**/
struct adis16400_state {
- struct spi_device *us;
- struct iio_trigger *trig;
- struct mutex buf_lock;
struct adis16400_chip_info *variant;
int filt_int;
- u8 tx[ADIS16400_MAX_TX] ____cacheline_aligned;
- u8 rx[ADIS16400_MAX_RX] ____cacheline_aligned;
+ struct adis adis;
};
-int adis16400_set_irq(struct iio_dev *indio_dev, bool enable);
-
/* At the moment triggers are only used for ring buffer
* filling. This may change!
*/
-#define ADIS16400_SCAN_SUPPLY 0
-#define ADIS16400_SCAN_GYRO_X 1
-#define ADIS16400_SCAN_GYRO_Y 2
-#define ADIS16400_SCAN_GYRO_Z 3
-#define ADIS16400_SCAN_ACC_X 4
-#define ADIS16400_SCAN_ACC_Y 5
-#define ADIS16400_SCAN_ACC_Z 6
-#define ADIS16400_SCAN_MAGN_X 7
-#define ADIS16350_SCAN_TEMP_X 7
-#define ADIS16400_SCAN_MAGN_Y 8
-#define ADIS16350_SCAN_TEMP_Y 8
-#define ADIS16400_SCAN_MAGN_Z 9
-#define ADIS16350_SCAN_TEMP_Z 9
-#define ADIS16400_SCAN_TEMP 10
-#define ADIS16350_SCAN_ADC_0 10
-#define ADIS16400_SCAN_ADC_0 11
-#define ADIS16300_SCAN_INCLI_X 12
-#define ADIS16300_SCAN_INCLI_Y 13
+enum {
+ ADIS16400_SCAN_SUPPLY,
+ ADIS16400_SCAN_GYRO_X,
+ ADIS16400_SCAN_GYRO_Y,
+ ADIS16400_SCAN_GYRO_Z,
+ ADIS16400_SCAN_ACC_X,
+ ADIS16400_SCAN_ACC_Y,
+ ADIS16400_SCAN_ACC_Z,
+ ADIS16400_SCAN_MAGN_X,
+ ADIS16400_SCAN_MAGN_Y,
+ ADIS16400_SCAN_MAGN_Z,
+ ADIS16400_SCAN_BARO,
+ ADIS16350_SCAN_TEMP_X,
+ ADIS16350_SCAN_TEMP_Y,
+ ADIS16350_SCAN_TEMP_Z,
+ ADIS16300_SCAN_INCLI_X,
+ ADIS16300_SCAN_INCLI_Y,
+ ADIS16400_SCAN_ADC,
+};
#ifdef CONFIG_IIO_BUFFER
-void adis16400_remove_trigger(struct iio_dev *indio_dev);
-int adis16400_probe_trigger(struct iio_dev *indio_dev);
ssize_t adis16400_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf);
-int adis16400_configure_ring(struct iio_dev *indio_dev);
-void adis16400_unconfigure_ring(struct iio_dev *indio_dev);
+int adis16400_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask);
+irqreturn_t adis16400_trigger_handler(int irq, void *p);
#else /* CONFIG_IIO_BUFFER */
-static inline void adis16400_remove_trigger(struct iio_dev *indio_dev)
-{
-}
-
-static inline int adis16400_probe_trigger(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline ssize_t
-adis16400_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-static int adis16400_configure_ring(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline void adis16400_unconfigure_ring(struct iio_dev *indio_dev)
-{
-}
+#define adis16400_update_scan_mode NULL
+#define adis16400_trigger_handler NULL
#endif /* CONFIG_IIO_BUFFER */
+
#endif /* SPI_ADIS16400_H_ */
--- /dev/null
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/export.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#include "adis16400.h"
+
+int adis16400_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ struct adis *adis = &st->adis;
+ uint16_t *tx, *rx;
+
+ if (st->variant->flags & ADIS16400_NO_BURST)
+ return adis_update_scan_mode(indio_dev, scan_mask);
+
+ kfree(adis->xfer);
+ kfree(adis->buffer);
+
+ adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL);
+ if (!adis->xfer)
+ return -ENOMEM;
+
+ adis->buffer = kzalloc(indio_dev->scan_bytes + sizeof(u16),
+ GFP_KERNEL);
+ if (!adis->buffer)
+ return -ENOMEM;
+
+ rx = adis->buffer;
+ tx = adis->buffer + indio_dev->scan_bytes;
+
+ tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD);
+ tx[1] = 0;
+
+ adis->xfer[0].tx_buf = tx;
+ adis->xfer[0].bits_per_word = 8;
+ adis->xfer[0].len = 2;
+ adis->xfer[1].tx_buf = tx;
+ adis->xfer[1].bits_per_word = 8;
+ adis->xfer[1].len = indio_dev->scan_bytes;
+
+ spi_message_init(&adis->msg);
+ spi_message_add_tail(&adis->xfer[0], &adis->msg);
+ spi_message_add_tail(&adis->xfer[1], &adis->msg);
+
+ return 0;
+}
+
+irqreturn_t adis16400_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct adis16400_state *st = iio_priv(indio_dev);
+ struct adis *adis = &st->adis;
+ u32 old_speed_hz = st->adis.spi->max_speed_hz;
+ int ret;
+
+ if (!adis->buffer)
+ return -ENOMEM;
+
+ if (!(st->variant->flags & ADIS16400_NO_BURST) &&
+ st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) {
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST;
+ spi_setup(st->adis.spi);
+ }
+
+ ret = spi_sync(adis->spi, &adis->msg);
+ if (ret)
+ dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret);
+
+ if (!(st->variant->flags & ADIS16400_NO_BURST)) {
+ st->adis.spi->max_speed_hz = old_speed_hz;
+ spi_setup(st->adis.spi);
+ }
+
+ /* Guaranteed to be aligned with 8 byte boundary */
+ if (indio_dev->scan_timestamp) {
+ void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64);
+ *(s64 *)b = pf->timestamp;
+ }
+
+ iio_push_to_buffers(indio_dev, adis->buffer);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
--- /dev/null
+/*
+ * adis16400.c support Analog Devices ADIS16400/5
+ * 3d 2g Linear Accelerometers,
+ * 3d Gyroscopes,
+ * 3d Magnetometers via SPI
+ *
+ * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
+ * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * 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/interrupt.h>
+#include <linux/irq.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/list.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+
+#include "adis16400.h"
+
+#ifdef CONFIG_DEBUG_FS
+
+static ssize_t adis16400_show_serial_number(struct file *file,
+ char __user *userbuf, size_t count, loff_t *ppos)
+{
+ struct adis16400_state *st = file->private_data;
+ u16 lot1, lot2, serial_number;
+ char buf[16];
+ size_t len;
+ int ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID1, &lot1);
+ if (ret < 0)
+ return ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID2, &lot2);
+ if (ret < 0)
+ return ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16334_SERIAL_NUMBER,
+ &serial_number);
+ if (ret < 0)
+ return ret;
+
+ len = snprintf(buf, sizeof(buf), "%.4x-%.4x-%.4x\n", lot1, lot2,
+ serial_number);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations adis16400_serial_number_fops = {
+ .open = simple_open,
+ .read = adis16400_show_serial_number,
+ .llseek = default_llseek,
+ .owner = THIS_MODULE,
+};
+
+static int adis16400_show_product_id(void *arg, u64 *val)
+{
+ struct adis16400_state *st = arg;
+ uint16_t prod_id;
+ int ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16400_PRODUCT_ID, &prod_id);
+ if (ret < 0)
+ return ret;
+
+ *val = prod_id;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16400_product_id_fops,
+ adis16400_show_product_id, NULL, "%lld\n");
+
+static int adis16400_show_flash_count(void *arg, u64 *val)
+{
+ struct adis16400_state *st = arg;
+ uint16_t flash_count;
+ int ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16400_FLASH_CNT, &flash_count);
+ if (ret < 0)
+ return ret;
+
+ *val = flash_count;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16400_flash_count_fops,
+ adis16400_show_flash_count, NULL, "%lld\n");
+
+static int adis16400_debugfs_init(struct iio_dev *indio_dev)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+
+ if (st->variant->flags & ADIS16400_HAS_SERIAL_NUMBER)
+ debugfs_create_file("serial_number", 0400,
+ indio_dev->debugfs_dentry, st,
+ &adis16400_serial_number_fops);
+ if (st->variant->flags & ADIS16400_HAS_PROD_ID)
+ debugfs_create_file("product_id", 0400,
+ indio_dev->debugfs_dentry, st,
+ &adis16400_product_id_fops);
+ debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
+ st, &adis16400_flash_count_fops);
+
+ return 0;
+}
+
+#else
+
+static int adis16400_debugfs_init(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+#endif
+
+enum adis16400_chip_variant {
+ ADIS16300,
+ ADIS16334,
+ ADIS16350,
+ ADIS16360,
+ ADIS16362,
+ ADIS16364,
+ ADIS16400,
+ ADIS16448,
+};
+
+static int adis16334_get_freq(struct adis16400_state *st)
+{
+ int ret;
+ uint16_t t;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
+ if (ret < 0)
+ return ret;
+
+ t >>= ADIS16334_RATE_DIV_SHIFT;
+
+ return 819200 >> t;
+}
+
+static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq)
+{
+ unsigned int t;
+
+ if (freq < 819200)
+ t = ilog2(819200 / freq);
+ else
+ t = 0;
+
+ if (t > 0x31)
+ t = 0x31;
+
+ t <<= ADIS16334_RATE_DIV_SHIFT;
+ t |= ADIS16334_RATE_INT_CLK;
+
+ return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t);
+}
+
+static int adis16400_get_freq(struct adis16400_state *st)
+{
+ int sps, ret;
+ uint16_t t;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
+ if (ret < 0)
+ return ret;
+
+ sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 52851 : 1638404;
+ sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1;
+
+ return sps;
+}
+
+static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq)
+{
+ unsigned int t;
+ uint8_t val = 0;
+
+ t = 1638404 / freq;
+ if (t >= 128) {
+ val |= ADIS16400_SMPL_PRD_TIME_BASE;
+ t = 52851 / freq;
+ if (t >= 128)
+ t = 127;
+ } else if (t != 0) {
+ t--;
+ }
+
+ val |= t;
+
+ if (t >= 0x0A || (val & ADIS16400_SMPL_PRD_TIME_BASE))
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW;
+ else
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST;
+
+ return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val);
+}
+
+static ssize_t adis16400_read_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adis16400_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = st->variant->get_freq(st);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d.%.3d\n", ret / 1000, ret % 1000);
+}
+
+static const unsigned adis16400_3db_divisors[] = {
+ [0] = 2, /* Special case */
+ [1] = 6,
+ [2] = 12,
+ [3] = 25,
+ [4] = 50,
+ [5] = 100,
+ [6] = 200,
+ [7] = 200, /* Not a valid setting */
+};
+
+static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ uint16_t val16;
+ int i, ret;
+
+ for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 1; i--) {
+ if (sps / adis16400_3db_divisors[i] >= val)
+ break;
+ }
+
+ ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16);
+ if (ret < 0)
+ return ret;
+
+ ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG,
+ (val16 & ~0x07) | i);
+ return ret;
+}
+
+static ssize_t adis16400_write_frequency(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adis16400_state *st = iio_priv(indio_dev);
+ int i, f, val;
+ int ret;
+
+ ret = iio_str_to_fixpoint(buf, 100, &i, &f);
+ if (ret)
+ return ret;
+
+ val = i * 1000 + f;
+
+ if (val <= 0)
+ return -EINVAL;
+
+ mutex_lock(&indio_dev->mlock);
+ st->variant->set_freq(st, val);
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : len;
+}
+
+/* Power down the device */
+static int adis16400_stop_device(struct iio_dev *indio_dev)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = adis_write_reg_16(&st->adis, ADIS16400_SLP_CNT,
+ ADIS16400_SLP_CNT_POWER_OFF);
+ if (ret)
+ dev_err(&indio_dev->dev,
+ "problem with turning device off: SLP_CNT");
+
+ return ret;
+}
+
+static int adis16400_initial_setup(struct iio_dev *indio_dev)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ uint16_t prod_id, smp_prd;
+ unsigned int device_id;
+ int ret;
+
+ /* use low spi speed for init if the device has a slow mode */
+ if (st->variant->flags & ADIS16400_HAS_SLOW_MODE)
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW;
+ else
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST;
+ st->adis.spi->mode = SPI_MODE_3;
+ spi_setup(st->adis.spi);
+
+ ret = adis_initial_startup(&st->adis);
+ if (ret)
+ return ret;
+
+ if (st->variant->flags & ADIS16400_HAS_PROD_ID) {
+ ret = adis_read_reg_16(&st->adis,
+ ADIS16400_PRODUCT_ID, &prod_id);
+ if (ret)
+ goto err_ret;
+
+ sscanf(indio_dev->name, "adis%u\n", &device_id);
+
+ if (prod_id != device_id)
+ dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
+ device_id, prod_id);
+
+ dev_info(&indio_dev->dev, "%s: prod_id 0x%04x at CS%d (irq %d)\n",
+ indio_dev->name, prod_id,
+ st->adis.spi->chip_select, st->adis.spi->irq);
+ }
+ /* use high spi speed if possible */
+ if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) {
+ ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &smp_prd);
+ if (ret)
+ goto err_ret;
+
+ if ((smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) {
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST;
+ spi_setup(st->adis.spi);
+ }
+ }
+
+err_ret:
+ return ret;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ adis16400_read_frequency,
+ adis16400_write_frequency);
+
+static const uint8_t adis16400_addresses[] = {
+ [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF,
+ [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF,
+ [ADIS16400_SCAN_GYRO_Z] = ADIS16400_ZGYRO_OFF,
+ [ADIS16400_SCAN_ACC_X] = ADIS16400_XACCL_OFF,
+ [ADIS16400_SCAN_ACC_Y] = ADIS16400_YACCL_OFF,
+ [ADIS16400_SCAN_ACC_Z] = ADIS16400_ZACCL_OFF,
+};
+
+static int adis16400_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long info)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ int ret, sps;
+
+ switch (info) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ mutex_lock(&indio_dev->mlock);
+ ret = adis_write_reg_16(&st->adis,
+ adis16400_addresses[chan->scan_index], val);
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ /*
+ * Need to cache values so we can update if the frequency
+ * changes.
+ */
+ mutex_lock(&indio_dev->mlock);
+ st->filt_int = val;
+ /* Work out update to current value */
+ sps = st->variant->get_freq(st);
+ if (sps < 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return sps;
+ }
+
+ ret = adis16400_set_filter(indio_dev, sps,
+ val * 1000 + val2 / 1000);
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adis16400_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2, long info)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ int16_t val16;
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ return adis_single_conversion(indio_dev, chan, 0, val);
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ *val = 0;
+ *val2 = st->variant->gyro_scale_micro;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_VOLTAGE:
+ *val = 0;
+ if (chan->channel == 0) {
+ *val = 2;
+ *val2 = 418000; /* 2.418 mV */
+ } else {
+ *val = 0;
+ *val2 = 805800; /* 805.8 uV */
+ }
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_ACCEL:
+ *val = 0;
+ *val2 = st->variant->accel_scale_micro;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_MAGN:
+ *val = 0;
+ *val2 = 500; /* 0.5 mgauss */
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_TEMP:
+ *val = st->variant->temp_scale_nano / 1000000;
+ *val2 = (st->variant->temp_scale_nano % 1000000);
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_CALIBBIAS:
+ mutex_lock(&indio_dev->mlock);
+ ret = adis_read_reg_16(&st->adis,
+ adis16400_addresses[chan->scan_index], &val16);
+ mutex_unlock(&indio_dev->mlock);
+ if (ret)
+ return ret;
+ val16 = ((val16 & 0xFFF) << 4) >> 4;
+ *val = val16;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_OFFSET:
+ /* currently only temperature */
+ *val = st->variant->temp_offset;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ mutex_lock(&indio_dev->mlock);
+ /* Need both the number of taps and the sampling frequency */
+ ret = adis_read_reg_16(&st->adis,
+ ADIS16400_SENS_AVG,
+ &val16);
+ if (ret < 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ }
+ ret = st->variant->get_freq(st);
+ if (ret >= 0) {
+ ret /= adis16400_3db_divisors[val16 & 0x07];
+ *val = ret / 1000;
+ *val2 = (ret % 1000) * 1000;
+ }
+ mutex_unlock(&indio_dev->mlock);
+ if (ret < 0)
+ return ret;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = 0, \
+ .extend_name = name, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = (addr), \
+ .scan_index = (si), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_SUPPLY_CHAN(addr, bits) \
+ ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY)
+
+#define ADIS16400_AUX_ADC_CHAN(addr, bits) \
+ ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC)
+
+#define ADIS16400_GYRO_CHAN(mod, addr, bits) { \
+ .type = IIO_ANGL_VEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .address = addr, \
+ .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_ACCEL_CHAN(mod, addr, bits) { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .address = (addr), \
+ .scan_index = ADIS16400_SCAN_ACC_ ## mod, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_MAGN_CHAN(mod, addr, bits) { \
+ .type = IIO_MAGN, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .address = (addr), \
+ .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_MOD_TEMP_NAME_X "x"
+#define ADIS16400_MOD_TEMP_NAME_Y "y"
+#define ADIS16400_MOD_TEMP_NAME_Z "z"
+
+#define ADIS16400_MOD_TEMP_CHAN(mod, addr, bits) { \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .channel = 0, \
+ .extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .address = (addr), \
+ .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_TEMP_CHAN(addr, bits) { \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .channel = 0, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = (addr), \
+ .scan_index = ADIS16350_SCAN_TEMP_X, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_INCLI_CHAN(mod, addr, bits) { \
+ .type = IIO_INCLI, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .address = (addr), \
+ .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+static const struct iio_chan_spec adis16400_channels[] = {
+ ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 14),
+ ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14),
+ ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14),
+ ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14),
+ ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14),
+ ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14),
+ ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12),
+ ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(12)
+};
+
+static const struct iio_chan_spec adis16448_channels[] = {
+ ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16),
+ ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16),
+ ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16),
+ ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16),
+ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16),
+ ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16),
+ ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 16),
+ ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 16),
+ ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 16),
+ {
+ .type = IIO_PRESSURE,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = ADIS16448_BARO_OUT,
+ .scan_index = ADIS16400_SCAN_BARO,
+ .scan_type = IIO_ST('s', 16, 16, 0),
+ },
+ ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(11)
+};
+
+static const struct iio_chan_spec adis16350_channels[] = {
+ ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12),
+ ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14),
+ ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14),
+ ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14),
+ ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14),
+ ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14),
+ ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12),
+ ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12),
+ ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12),
+ ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(11)
+};
+
+static const struct iio_chan_spec adis16300_channels[] = {
+ ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12),
+ ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14),
+ ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14),
+ ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12),
+ ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12),
+ ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13),
+ ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13),
+ IIO_CHAN_SOFT_TIMESTAMP(14)
+};
+
+static const struct iio_chan_spec adis16334_channels[] = {
+ ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14),
+ ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14),
+ ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(8)
+};
+
+static struct attribute *adis16400_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adis16400_attribute_group = {
+ .attrs = adis16400_attributes,
+};
+
+static struct adis16400_chip_info adis16400_chips[] = {
+ [ADIS16300] = {
+ .channels = adis16300_channels,
+ .num_channels = ARRAY_SIZE(adis16300_channels),
+ .flags = ADIS16400_HAS_SLOW_MODE,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = 5884,
+ .temp_scale_nano = 140000000, /* 0.14 C */
+ .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16334] = {
+ .channels = adis16334_channels,
+ .num_channels = ARRAY_SIZE(adis16334_channels),
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_NO_BURST |
+ ADIS16400_HAS_SERIAL_NUMBER,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */
+ .temp_scale_nano = 67850000, /* 0.06785 C */
+ .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */
+ .set_freq = adis16334_set_freq,
+ .get_freq = adis16334_get_freq,
+ },
+ [ADIS16350] = {
+ .channels = adis16350_channels,
+ .num_channels = ARRAY_SIZE(adis16350_channels),
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */
+ .temp_scale_nano = 145300000, /* 0.1453 C */
+ .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */
+ .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE,
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16360] = {
+ .channels = adis16350_channels,
+ .num_channels = ARRAY_SIZE(adis16350_channels),
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
+ ADIS16400_HAS_SERIAL_NUMBER,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
+ .temp_scale_nano = 136000000, /* 0.136 C */
+ .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16362] = {
+ .channels = adis16350_channels,
+ .num_channels = ARRAY_SIZE(adis16350_channels),
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
+ ADIS16400_HAS_SERIAL_NUMBER,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */
+ .temp_scale_nano = 136000000, /* 0.136 C */
+ .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16364] = {
+ .channels = adis16350_channels,
+ .num_channels = ARRAY_SIZE(adis16350_channels),
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
+ ADIS16400_HAS_SERIAL_NUMBER,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */
+ .temp_scale_nano = 136000000, /* 0.136 C */
+ .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16400] = {
+ .channels = adis16400_channels,
+ .num_channels = ARRAY_SIZE(adis16400_channels),
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
+ .temp_scale_nano = 140000000, /* 0.14 C */
+ .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16448] = {
+ .channels = adis16448_channels,
+ .num_channels = ARRAY_SIZE(adis16448_channels),
+ .flags = ADIS16400_HAS_PROD_ID |
+ ADIS16400_HAS_SERIAL_NUMBER,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */
+ .temp_scale_nano = 73860000, /* 0.07386 C */
+ .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
+ .set_freq = adis16334_set_freq,
+ .get_freq = adis16334_get_freq,
+ }
+};
+
+static const struct iio_info adis16400_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &adis16400_read_raw,
+ .write_raw = &adis16400_write_raw,
+ .attrs = &adis16400_attribute_group,
+ .update_scan_mode = adis16400_update_scan_mode,
+ .debugfs_reg_access = adis_debugfs_reg_access,
+};
+
+static const unsigned long adis16400_burst_scan_mask[] = {
+ ~0UL,
+ 0,
+};
+
+static const char * const adis16400_status_error_msgs[] = {
+ [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
+ [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
+ [ADIS16400_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure",
+ [ADIS16400_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure",
+ [ADIS16400_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure",
+ [ADIS16400_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure",
+ [ADIS16400_DIAG_STAT_ALARM2] = "Alarm 2 active",
+ [ADIS16400_DIAG_STAT_ALARM1] = "Alarm 1 active",
+ [ADIS16400_DIAG_STAT_FLASH_CHK] = "Flash checksum error",
+ [ADIS16400_DIAG_STAT_SELF_TEST] = "Self test error",
+ [ADIS16400_DIAG_STAT_OVERFLOW] = "Sensor overrange",
+ [ADIS16400_DIAG_STAT_SPI_FAIL] = "SPI failure",
+ [ADIS16400_DIAG_STAT_FLASH_UPT] = "Flash update failed",
+ [ADIS16400_DIAG_STAT_POWER_HIGH] = "Power supply above 5.25V",
+ [ADIS16400_DIAG_STAT_POWER_LOW] = "Power supply below 4.75V",
+};
+
+static const struct adis_data adis16400_data = {
+ .msc_ctrl_reg = ADIS16400_MSC_CTRL,
+ .glob_cmd_reg = ADIS16400_GLOB_CMD,
+ .diag_stat_reg = ADIS16400_DIAG_STAT,
+
+ .read_delay = 50,
+ .write_delay = 50,
+
+ .self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST,
+ .startup_delay = ADIS16400_STARTUP_DELAY,
+
+ .status_error_msgs = adis16400_status_error_msgs,
+ .status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_YACCL_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_XACCL_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_XGYRO_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_YGYRO_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_ZGYRO_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_ALARM2) |
+ BIT(ADIS16400_DIAG_STAT_ALARM1) |
+ BIT(ADIS16400_DIAG_STAT_FLASH_CHK) |
+ BIT(ADIS16400_DIAG_STAT_SELF_TEST) |
+ BIT(ADIS16400_DIAG_STAT_OVERFLOW) |
+ BIT(ADIS16400_DIAG_STAT_SPI_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_FLASH_UPT) |
+ BIT(ADIS16400_DIAG_STAT_POWER_HIGH) |
+ BIT(ADIS16400_DIAG_STAT_POWER_LOW),
+};
+
+static int adis16400_probe(struct spi_device *spi)
+{
+ struct adis16400_state *st;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = iio_device_alloc(sizeof(*st));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, indio_dev);
+
+ /* setup the industrialio driver allocated elements */
+ st->variant = &adis16400_chips[spi_get_device_id(spi)->driver_data];
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->channels = st->variant->channels;
+ indio_dev->num_channels = st->variant->num_channels;
+ indio_dev->info = &adis16400_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ if (!(st->variant->flags & ADIS16400_NO_BURST))
+ indio_dev->available_scan_masks = adis16400_burst_scan_mask;
+
+ ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data);
+ if (ret)
+ goto error_free_dev;
+
+ ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev,
+ adis16400_trigger_handler);
+ if (ret)
+ goto error_free_dev;
+
+ /* Get the device into a sane initial state */
+ ret = adis16400_initial_setup(indio_dev);
+ if (ret)
+ goto error_cleanup_buffer;
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_cleanup_buffer;
+
+ adis16400_debugfs_init(indio_dev);
+ return 0;
+
+error_cleanup_buffer:
+ adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
+error_free_dev:
+ iio_device_free(indio_dev);
+ return ret;
+}
+
+static int adis16400_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct adis16400_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ adis16400_stop_device(indio_dev);
+
+ adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
+
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct spi_device_id adis16400_id[] = {
+ {"adis16300", ADIS16300},
+ {"adis16334", ADIS16334},
+ {"adis16350", ADIS16350},
+ {"adis16354", ADIS16350},
+ {"adis16355", ADIS16350},
+ {"adis16360", ADIS16360},
+ {"adis16362", ADIS16362},
+ {"adis16364", ADIS16364},
+ {"adis16365", ADIS16360},
+ {"adis16400", ADIS16400},
+ {"adis16405", ADIS16400},
+ {"adis16448", ADIS16448},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, adis16400_id);
+
+static struct spi_driver adis16400_driver = {
+ .driver = {
+ .name = "adis16400",
+ .owner = THIS_MODULE,
+ },
+ .id_table = adis16400_id,
+ .probe = adis16400_probe,
+ .remove = adis16400_remove,
+};
+module_spi_driver(adis16400_driver);
+
+MODULE_AUTHOR("Manuel Stahl <manuel.stahl@iis.fraunhofer.de>");
+MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver");
+MODULE_LICENSE("GPL v2");
changes. The ALS-control output values can be set per zone for the
three current output channels.
+config SENSORS_TSL2563
+ tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors"
+ depends on I2C
+ help
+ If you say yes here you get support for the Taos TSL2560,
+ TSL2561, TSL2562 and TSL2563 ambient light sensors.
+
+ This driver can also be built as a module. If so, the module
+ will be called tsl2563.
+
config VCNL4000
tristate "VCNL4000 combined ALS and proximity sensor"
depends on I2C
obj-$(CONFIG_ADJD_S311) += adjd_s311.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
+obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
/*
- * drivers/i2c/chips/tsl2563.c
+ * drivers/iio/light/tsl2563.c
*
* Copyright (C) 2008 Nokia Corporation
*
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
-#include "tsl2563.h"
+#include <linux/platform_data/tsl2563.h>
/* Use this many bits for fraction part. */
-#define ADC_FRAC_BITS (14)
+#define ADC_FRAC_BITS 14
/* Given number of 1/10000's in ADC_FRAC_BITS precision. */
#define FRAC10K(f) (((f) * (1L << (ADC_FRAC_BITS))) / (10000))
/* Bits used for fraction in calibration coefficients.*/
-#define CALIB_FRAC_BITS (10)
+#define CALIB_FRAC_BITS 10
/* 0.5 in CALIB_FRAC_BITS precision */
#define CALIB_FRAC_HALF (1 << (CALIB_FRAC_BITS - 1))
/* Make a fraction from a number n that was multiplied with b. */
#define CALIB_FRAC(n, b) (((n) << CALIB_FRAC_BITS) / (b))
/* Decimal 10^(digits in sysfs presentation) */
-#define CALIB_BASE_SYSFS (1000)
-
-#define TSL2563_CMD (0x80)
-#define TSL2563_CLEARINT (0x40)
-
-#define TSL2563_REG_CTRL (0x00)
-#define TSL2563_REG_TIMING (0x01)
-#define TSL2563_REG_LOWLOW (0x02) /* data0 low threshold, 2 bytes */
-#define TSL2563_REG_LOWHIGH (0x03)
-#define TSL2563_REG_HIGHLOW (0x04) /* data0 high threshold, 2 bytes */
-#define TSL2563_REG_HIGHHIGH (0x05)
-#define TSL2563_REG_INT (0x06)
-#define TSL2563_REG_ID (0x0a)
-#define TSL2563_REG_DATA0LOW (0x0c) /* broadband sensor value, 2 bytes */
-#define TSL2563_REG_DATA0HIGH (0x0d)
-#define TSL2563_REG_DATA1LOW (0x0e) /* infrared sensor value, 2 bytes */
-#define TSL2563_REG_DATA1HIGH (0x0f)
-
-#define TSL2563_CMD_POWER_ON (0x03)
-#define TSL2563_CMD_POWER_OFF (0x00)
-#define TSL2563_CTRL_POWER_MASK (0x03)
-
-#define TSL2563_TIMING_13MS (0x00)
-#define TSL2563_TIMING_100MS (0x01)
-#define TSL2563_TIMING_400MS (0x02)
-#define TSL2563_TIMING_MASK (0x03)
-#define TSL2563_TIMING_GAIN16 (0x10)
-#define TSL2563_TIMING_GAIN1 (0x00)
-
-#define TSL2563_INT_DISBLED (0x00)
-#define TSL2563_INT_LEVEL (0x10)
+#define CALIB_BASE_SYSFS 1000
+
+#define TSL2563_CMD 0x80
+#define TSL2563_CLEARINT 0x40
+
+#define TSL2563_REG_CTRL 0x00
+#define TSL2563_REG_TIMING 0x01
+#define TSL2563_REG_LOWLOW 0x02 /* data0 low threshold, 2 bytes */
+#define TSL2563_REG_LOWHIGH 0x03
+#define TSL2563_REG_HIGHLOW 0x04 /* data0 high threshold, 2 bytes */
+#define TSL2563_REG_HIGHHIGH 0x05
+#define TSL2563_REG_INT 0x06
+#define TSL2563_REG_ID 0x0a
+#define TSL2563_REG_DATA0LOW 0x0c /* broadband sensor value, 2 bytes */
+#define TSL2563_REG_DATA0HIGH 0x0d
+#define TSL2563_REG_DATA1LOW 0x0e /* infrared sensor value, 2 bytes */
+#define TSL2563_REG_DATA1HIGH 0x0f
+
+#define TSL2563_CMD_POWER_ON 0x03
+#define TSL2563_CMD_POWER_OFF 0x00
+#define TSL2563_CTRL_POWER_MASK 0x03
+
+#define TSL2563_TIMING_13MS 0x00
+#define TSL2563_TIMING_100MS 0x01
+#define TSL2563_TIMING_400MS 0x02
+#define TSL2563_TIMING_MASK 0x03
+#define TSL2563_TIMING_GAIN16 0x10
+#define TSL2563_TIMING_GAIN1 0x00
+
+#define TSL2563_INT_DISBLED 0x00
+#define TSL2563_INT_LEVEL 0x10
#define TSL2563_INT_PERSIST(n) ((n) & 0x0F)
struct tsl2563_gainlevel_coeff {
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_LOWHIGH,
(chip->low_thres >> 8) & 0xFF);
-/* Interrupt register is automatically written anyway if it is relevant
- so is not here */
+/*
+ * Interrupt register is automatically written anyway if it is relevant
+ * so is not here.
+ */
error_ret:
return ret;
}
},
};
-/*
- * Convert normalized, scaled ADC values to lux.
- */
+/* Convert normalized, scaled ADC values to lux. */
static unsigned int adc_to_lux(u32 adc0, u32 adc1)
{
const struct tsl2563_lux_coeff *lp = lux_table;
return (unsigned int) (lux >> ADC_FRAC_BITS);
}
-/*--------------------------------------------------------------*/
-/* Sysfs interface */
-/*--------------------------------------------------------------*/
-
-
/* Apply calibration coefficient to ADC count. */
static u32 calib_adc(u32 adc, u32 calib)
{
TSL2563_CMD | TSL2563_REG_INT);
mutex_unlock(&chip->lock);
if (ret < 0)
- goto error_ret;
- ret = !!(ret & 0x30);
-error_ret:
+ return ret;
- return ret;
+ return !!(ret & 0x30);
}
-/*--------------------------------------------------------------*/
-/* Probe, Attach, Remove */
-/*--------------------------------------------------------------*/
-static struct i2c_driver tsl2563_i2c_driver;
-
static const struct iio_info tsl2563_info_no_irq = {
.driver_module = THIS_MODULE,
.read_raw = &tsl2563_read_raw,
platform_set_drvdata(pdev, time_state);
+ spin_lock_init(&time_state->lock_last_time);
init_completion(&time_state->comp_last_time);
time_state->common_attributes.hsdev = hsdev;
time_state->common_attributes.pdev = pdev;
map allows IIO devices to provide basic hwmon functionality
for those channels specified in the map.
-if IIO_BUFFER
-
-config IIO_SW_RING
- select IIO_TRIGGER
- tristate "Industrial I/O lock free software ring"
- help
- Example software ring buffer implementation. The design aim
- of this particular realization was to minimize write locking
- with the intention that some devices would be able to write
- in interrupt context.
-
-endif # IIO_BUFFER
-
source "drivers/staging/iio/accel/Kconfig"
source "drivers/staging/iio/adc/Kconfig"
source "drivers/staging/iio/addac/Kconfig"
source "drivers/staging/iio/frequency/Kconfig"
source "drivers/staging/iio/gyro/Kconfig"
source "drivers/staging/iio/impedance-analyzer/Kconfig"
-source "drivers/staging/iio/imu/Kconfig"
source "drivers/staging/iio/light/Kconfig"
source "drivers/staging/iio/magnetometer/Kconfig"
source "drivers/staging/iio/meter/Kconfig"
# Makefile for the industrial I/O core.
#
-obj-$(CONFIG_IIO_SW_RING) += ring_sw.o
-
obj-$(CONFIG_IIO_SIMPLE_DUMMY) += iio_dummy.o
iio_dummy-y := iio_simple_dummy.o
iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_EVENTS) += iio_simple_dummy_events.o
obj-y += frequency/
obj-y += gyro/
obj-y += impedance-analyzer/
-obj-y += imu/
obj-y += light/
obj-y += magnetometer/
obj-y += meter/
Say yes here to build support for Analog Devices adis16240 programmable
impact Sensor and recorder.
-config KXSD9
- tristate "Kionix KXSD9 Accelerometer Driver"
- depends on SPI
- help
- Say yes here to build support for the Kionix KXSD9 accelerometer.
- Currently this only supports the device via an SPI interface.
-
config LIS3L02DQ
tristate "ST Microelectronics LIS3L02DQ Accelerometer Driver"
depends on SPI
select IIO_TRIGGER if IIO_BUFFER
- depends on !IIO_BUFFER || IIO_KFIFO_BUF || IIO_SW_RING
+ depends on !IIO_BUFFER || IIO_KFIFO_BUF
depends on GENERIC_GPIO
help
Say yes here to build SPI support for the ST microelectronics
accelerometer. The driver supplies direct access via sysfs files
and an event interface via a character device.
-choice
- prompt "Buffer type"
- depends on LIS3L02DQ && IIO_BUFFER
-
-config LIS3L02DQ_BUF_KFIFO
- depends on IIO_KFIFO_BUF
- bool "Simple FIFO"
- help
- Kfifo based FIFO. Does not provide any events so it is up
- to userspace to ensure it reads often enough that data is not
- lost.
-
-config LIS3L02DQ_BUF_RING_SW
- depends on IIO_SW_RING
- bool "IIO Software Ring"
- help
- Original IIO ring buffer implementation. Provides simple
- buffer events, half full etc.
-
-endchoice
-
config SCA3000
depends on IIO_BUFFER
depends on SPI
adis16240-y := adis16240_core.o
obj-$(CONFIG_ADIS16240) += adis16240.o
-obj-$(CONFIG_KXSD9) += kxsd9.o
-
lis3l02dq-y := lis3l02dq_core.o
lis3l02dq-$(CONFIG_IIO_BUFFER) += lis3l02dq_ring.o
obj-$(CONFIG_LIS3L02DQ) += lis3l02dq.o
int lis3l02dq_configure_buffer(struct iio_dev *indio_dev);
void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev);
-#ifdef CONFIG_LIS3L02DQ_BUF_RING_SW
-#define lis3l02dq_free_buf iio_sw_rb_free
-#define lis3l02dq_alloc_buf iio_sw_rb_allocate
-#endif
-#ifdef CONFIG_LIS3L02DQ_BUF_KFIFO
-#define lis3l02dq_free_buf iio_kfifo_free
-#define lis3l02dq_alloc_buf iio_kfifo_allocate
-#endif
irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private);
#define lis3l02dq_th lis3l02dq_data_rdy_trig_poll
#include <linux/export.h>
#include <linux/iio/iio.h>
-#include "../ring_sw.h"
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- lis3l02dq_free_buf(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
static int lis3l02dq_buffer_postenable(struct iio_dev *indio_dev)
int ret;
struct iio_buffer *buffer;
- buffer = lis3l02dq_alloc_buf(indio_dev);
+ buffer = iio_kfifo_allocate(indio_dev);
if (!buffer)
return -ENOMEM;
return 0;
error_iio_sw_rb_free:
- lis3l02dq_free_buf(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
return ret;
}
via sysfs.
config MXS_LRADC
- tristate "Freescale i.MX28 LRADC"
+ tristate "Freescale i.MX23/i.MX28 LRADC"
depends on ARCH_MXS
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
- Say yes here to build support for i.MX28 LRADC convertor
+ Say yes here to build support for i.MX23/i.MX28 LRADC convertor
built into these chips.
To compile this driver as a module, choose M here: the
#include <linux/stmp_device.h>
#include <linux/bitops.h>
#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/input.h>
#include <mach/mxs.h>
#include <mach/common.h>
#define LRADC_DELAY_TIMER_PER 200
#define LRADC_DELAY_TIMER_LOOP 5
-static const char * const mxs_lradc_irq_name[] = {
+/*
+ * Once the pen touches the touchscreen, the touchscreen switches from
+ * IRQ-driven mode to polling mode to prevent interrupt storm. The polling
+ * is realized by worker thread, which is called every 20 or so milliseconds.
+ * This gives the touchscreen enough fluence and does not strain the system
+ * too much.
+ */
+#define LRADC_TS_SAMPLE_DELAY_MS 5
+
+/*
+ * The LRADC reads the following amount of samples from each touchscreen
+ * channel and the driver then computes avarage of these.
+ */
+#define LRADC_TS_SAMPLE_AMOUNT 4
+
+enum mxs_lradc_id {
+ IMX23_LRADC,
+ IMX28_LRADC,
+};
+
+static const char * const mx23_lradc_irq_names[] = {
+ "mxs-lradc-touchscreen",
+ "mxs-lradc-channel0",
+ "mxs-lradc-channel1",
+ "mxs-lradc-channel2",
+ "mxs-lradc-channel3",
+ "mxs-lradc-channel4",
+ "mxs-lradc-channel5",
+ "mxs-lradc-channel6",
+ "mxs-lradc-channel7",
+};
+
+static const char * const mx28_lradc_irq_names[] = {
"mxs-lradc-touchscreen",
"mxs-lradc-thresh0",
"mxs-lradc-thresh1",
"mxs-lradc-button1",
};
+struct mxs_lradc_of_config {
+ const int irq_count;
+ const char * const *irq_name;
+};
+
+static const struct mxs_lradc_of_config const mxs_lradc_of_config[] = {
+ [IMX23_LRADC] = {
+ .irq_count = ARRAY_SIZE(mx23_lradc_irq_names),
+ .irq_name = mx23_lradc_irq_names,
+ },
+ [IMX28_LRADC] = {
+ .irq_count = ARRAY_SIZE(mx28_lradc_irq_names),
+ .irq_name = mx28_lradc_irq_names,
+ },
+};
+
+enum mxs_lradc_ts {
+ MXS_LRADC_TOUCHSCREEN_NONE = 0,
+ MXS_LRADC_TOUCHSCREEN_4WIRE,
+ MXS_LRADC_TOUCHSCREEN_5WIRE,
+};
+
struct mxs_lradc {
struct device *dev;
void __iomem *base;
struct mutex lock;
struct completion completion;
+
+ /*
+ * Touchscreen LRADC channels receives a private slot in the CTRL4
+ * register, the slot #7. Therefore only 7 slots instead of 8 in the
+ * CTRL4 register can be mapped to LRADC channels when using the
+ * touchscreen.
+ *
+ * Furthermore, certain LRADC channels are shared between touchscreen
+ * and/or touch-buttons and generic LRADC block. Therefore when using
+ * either of these, these channels are not available for the regular
+ * sampling. The shared channels are as follows:
+ *
+ * CH0 -- Touch button #0
+ * CH1 -- Touch button #1
+ * CH2 -- Touch screen XPUL
+ * CH3 -- Touch screen YPLL
+ * CH4 -- Touch screen XNUL
+ * CH5 -- Touch screen YNLR
+ * CH6 -- Touch screen WIPER (5-wire only)
+ *
+ * The bitfields below represents which parts of the LRADC block are
+ * switched into special mode of operation. These channels can not
+ * be sampled as regular LRADC channels. The driver will refuse any
+ * attempt to sample these channels.
+ */
+#define CHAN_MASK_TOUCHBUTTON (0x3 << 0)
+#define CHAN_MASK_TOUCHSCREEN_4WIRE (0xf << 2)
+#define CHAN_MASK_TOUCHSCREEN_5WIRE (0x1f << 2)
+ enum mxs_lradc_ts use_touchscreen;
+ bool stop_touchscreen;
+ bool use_touchbutton;
+
+ struct input_dev *ts_input;
+ struct work_struct ts_work;
};
#define LRADC_CTRL0 0x00
-#define LRADC_CTRL0_TOUCH_DETECT_ENABLE (1 << 23)
-#define LRADC_CTRL0_TOUCH_SCREEN_TYPE (1 << 22)
+#define LRADC_CTRL0_TOUCH_DETECT_ENABLE (1 << 23)
+#define LRADC_CTRL0_TOUCH_SCREEN_TYPE (1 << 22)
+#define LRADC_CTRL0_YNNSW /* YM */ (1 << 21)
+#define LRADC_CTRL0_YPNSW /* YP */ (1 << 20)
+#define LRADC_CTRL0_YPPSW /* YP */ (1 << 19)
+#define LRADC_CTRL0_XNNSW /* XM */ (1 << 18)
+#define LRADC_CTRL0_XNPSW /* XM */ (1 << 17)
+#define LRADC_CTRL0_XPPSW /* XP */ (1 << 16)
+#define LRADC_CTRL0_PLATE_MASK (0x3f << 16)
#define LRADC_CTRL1 0x10
-#define LRADC_CTRL1_LRADC_IRQ(n) (1 << (n))
-#define LRADC_CTRL1_LRADC_IRQ_MASK 0x1fff
+#define LRADC_CTRL1_TOUCH_DETECT_IRQ_EN (1 << 24)
#define LRADC_CTRL1_LRADC_IRQ_EN(n) (1 << ((n) + 16))
#define LRADC_CTRL1_LRADC_IRQ_EN_MASK (0x1fff << 16)
+#define LRADC_CTRL1_LRADC_IRQ_EN_OFFSET 16
+#define LRADC_CTRL1_TOUCH_DETECT_IRQ (1 << 8)
+#define LRADC_CTRL1_LRADC_IRQ(n) (1 << (n))
+#define LRADC_CTRL1_LRADC_IRQ_MASK 0x1fff
+#define LRADC_CTRL1_LRADC_IRQ_OFFSET 0
#define LRADC_CTRL2 0x20
#define LRADC_CTRL2_TEMPSENSE_PWD (1 << 15)
+#define LRADC_STATUS 0x40
+#define LRADC_STATUS_TOUCH_DETECT_RAW (1 << 0)
+
#define LRADC_CH(n) (0x50 + (0x10 * (n)))
#define LRADC_CH_ACCUMULATE (1 << 29)
#define LRADC_CH_NUM_SAMPLES_MASK (0x1f << 24)
{
struct mxs_lradc *lradc = iio_priv(iio_dev);
int ret;
+ unsigned long mask;
if (m != IIO_CHAN_INFO_RAW)
return -EINVAL;
if (chan->channel > LRADC_MAX_TOTAL_CHANS)
return -EINVAL;
+ /* Validate the channel if it doesn't intersect with reserved chans. */
+ bitmap_set(&mask, chan->channel, 1);
+ ret = iio_validate_scan_mask_onehot(iio_dev, &mask);
+ if (ret)
+ return -EINVAL;
+
/*
* See if there is no buffered operation in progess. If there is, simply
* bail out. This can be improved to support both buffered and raw IO at
lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
- writel(chan->channel, lradc->base + LRADC_CTRL4);
+ /* Clean the slot's previous content, then set new one. */
+ writel(LRADC_CTRL4_LRADCSELECT_MASK(0),
+ lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR);
+ writel(chan->channel, lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET);
+
writel(0, lradc->base + LRADC_CH(0));
/* Enable the IRQ and start sampling the channel. */
};
/*
+ * Touchscreen handling
+ */
+enum lradc_ts_plate {
+ LRADC_SAMPLE_X,
+ LRADC_SAMPLE_Y,
+ LRADC_SAMPLE_PRESSURE,
+};
+
+static int mxs_lradc_ts_touched(struct mxs_lradc *lradc)
+{
+ uint32_t reg;
+
+ /* Enable touch detection. */
+ writel(LRADC_CTRL0_PLATE_MASK,
+ lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+ writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE,
+ lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+ msleep(LRADC_TS_SAMPLE_DELAY_MS);
+
+ reg = readl(lradc->base + LRADC_STATUS);
+
+ return reg & LRADC_STATUS_TOUCH_DETECT_RAW;
+}
+
+static int32_t mxs_lradc_ts_sample(struct mxs_lradc *lradc,
+ enum lradc_ts_plate plate, int change)
+{
+ unsigned long delay, jiff;
+ uint32_t reg, ctrl0 = 0, chan = 0;
+ /* The touchscreen always uses CTRL4 slot #7. */
+ const uint8_t slot = 7;
+ uint32_t val;
+
+ /*
+ * There are three correct configurations of the controller sampling
+ * the touchscreen, each of these configuration provides different
+ * information from the touchscreen.
+ *
+ * The following table describes the sampling configurations:
+ * +-------------+-------+-------+-------+
+ * | Wire \ Axis | X | Y | Z |
+ * +---------------------+-------+-------+
+ * | X+ (CH2) | HI | TS | TS |
+ * +-------------+-------+-------+-------+
+ * | X- (CH4) | LO | SH | HI |
+ * +-------------+-------+-------+-------+
+ * | Y+ (CH3) | SH | HI | HI |
+ * +-------------+-------+-------+-------+
+ * | Y- (CH5) | TS | LO | SH |
+ * +-------------+-------+-------+-------+
+ *
+ * HI ... strong '1' ; LO ... strong '0'
+ * SH ... sample here ; TS ... tri-state
+ *
+ * There are a few other ways of obtaining the Z coordinate
+ * (aka. pressure), but the one in the table seems to be the
+ * most reliable one.
+ */
+ switch (plate) {
+ case LRADC_SAMPLE_X:
+ ctrl0 = LRADC_CTRL0_XPPSW | LRADC_CTRL0_XNNSW;
+ chan = 3;
+ break;
+ case LRADC_SAMPLE_Y:
+ ctrl0 = LRADC_CTRL0_YPPSW | LRADC_CTRL0_YNNSW;
+ chan = 4;
+ break;
+ case LRADC_SAMPLE_PRESSURE:
+ ctrl0 = LRADC_CTRL0_YPPSW | LRADC_CTRL0_XNNSW;
+ chan = 5;
+ break;
+ }
+
+ if (change) {
+ writel(LRADC_CTRL0_PLATE_MASK,
+ lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+ writel(ctrl0, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+ writel(LRADC_CTRL4_LRADCSELECT_MASK(slot),
+ lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR);
+ writel(chan << LRADC_CTRL4_LRADCSELECT_OFFSET(slot),
+ lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET);
+ }
+
+ writel(0xffffffff, lradc->base + LRADC_CH(slot) + STMP_OFFSET_REG_CLR);
+ writel(1 << slot, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+ delay = jiffies + msecs_to_jiffies(LRADC_TS_SAMPLE_DELAY_MS);
+ do {
+ jiff = jiffies;
+ reg = readl_relaxed(lradc->base + LRADC_CTRL1);
+ if (reg & LRADC_CTRL1_LRADC_IRQ(slot))
+ break;
+ } while (time_before(jiff, delay));
+
+ writel(LRADC_CTRL1_LRADC_IRQ(slot),
+ lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+ if (time_after_eq(jiff, delay))
+ return -ETIMEDOUT;
+
+ val = readl(lradc->base + LRADC_CH(slot));
+ val &= LRADC_CH_VALUE_MASK;
+
+ return val;
+}
+
+static int32_t mxs_lradc_ts_sample_filter(struct mxs_lradc *lradc,
+ enum lradc_ts_plate plate)
+{
+ int32_t val, tot = 0;
+ int i;
+
+ val = mxs_lradc_ts_sample(lradc, plate, 1);
+
+ /* Delay a bit so the touchscreen is stable. */
+ mdelay(2);
+
+ for (i = 0; i < LRADC_TS_SAMPLE_AMOUNT; i++) {
+ val = mxs_lradc_ts_sample(lradc, plate, 0);
+ tot += val;
+ }
+
+ return tot / LRADC_TS_SAMPLE_AMOUNT;
+}
+
+static void mxs_lradc_ts_work(struct work_struct *ts_work)
+{
+ struct mxs_lradc *lradc = container_of(ts_work,
+ struct mxs_lradc, ts_work);
+ int val_x, val_y, val_p;
+ bool valid = false;
+
+ while (mxs_lradc_ts_touched(lradc)) {
+ /* Disable touch detector so we can sample the touchscreen. */
+ writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE,
+ lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+ if (likely(valid)) {
+ input_report_abs(lradc->ts_input, ABS_X, val_x);
+ input_report_abs(lradc->ts_input, ABS_Y, val_y);
+ input_report_abs(lradc->ts_input, ABS_PRESSURE, val_p);
+ input_report_key(lradc->ts_input, BTN_TOUCH, 1);
+ input_sync(lradc->ts_input);
+ }
+
+ valid = false;
+
+ val_x = mxs_lradc_ts_sample_filter(lradc, LRADC_SAMPLE_X);
+ if (val_x < 0)
+ continue;
+ val_y = mxs_lradc_ts_sample_filter(lradc, LRADC_SAMPLE_Y);
+ if (val_y < 0)
+ continue;
+ val_p = mxs_lradc_ts_sample_filter(lradc, LRADC_SAMPLE_PRESSURE);
+ if (val_p < 0)
+ continue;
+
+ valid = true;
+ }
+
+ input_report_abs(lradc->ts_input, ABS_PRESSURE, 0);
+ input_report_key(lradc->ts_input, BTN_TOUCH, 0);
+ input_sync(lradc->ts_input);
+
+ /* Do not restart the TS IRQ if the driver is shutting down. */
+ if (lradc->stop_touchscreen)
+ return;
+
+ /* Restart the touchscreen interrupts. */
+ writel(LRADC_CTRL1_TOUCH_DETECT_IRQ,
+ lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+ writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+ lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+}
+
+static int mxs_lradc_ts_open(struct input_dev *dev)
+{
+ struct mxs_lradc *lradc = input_get_drvdata(dev);
+
+ /* The touchscreen is starting. */
+ lradc->stop_touchscreen = false;
+
+ /* Enable the touch-detect circuitry. */
+ writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE,
+ lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+ /* Enable the touch-detect IRQ. */
+ writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+ lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+
+ return 0;
+}
+
+static void mxs_lradc_ts_close(struct input_dev *dev)
+{
+ struct mxs_lradc *lradc = input_get_drvdata(dev);
+
+ /* Indicate the touchscreen is stopping. */
+ lradc->stop_touchscreen = true;
+ mb();
+
+ /* Wait until touchscreen thread finishes any possible remnants. */
+ cancel_work_sync(&lradc->ts_work);
+
+ /* Disable touchscreen touch-detect IRQ. */
+ writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+ lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+ /* Power-down touchscreen touch-detect circuitry. */
+ writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE,
+ lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+}
+
+static int mxs_lradc_ts_register(struct mxs_lradc *lradc)
+{
+ struct input_dev *input;
+ struct device *dev = lradc->dev;
+ int ret;
+
+ if (!lradc->use_touchscreen)
+ return 0;
+
+ input = input_allocate_device();
+ if (!input) {
+ dev_err(dev, "Failed to allocate TS device!\n");
+ return -ENOMEM;
+ }
+
+ input->name = DRIVER_NAME;
+ input->id.bustype = BUS_HOST;
+ input->dev.parent = dev;
+ input->open = mxs_lradc_ts_open;
+ input->close = mxs_lradc_ts_close;
+
+ __set_bit(EV_ABS, input->evbit);
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(BTN_TOUCH, input->keybit);
+ input_set_abs_params(input, ABS_X, 0, LRADC_CH_VALUE_MASK, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, LRADC_CH_VALUE_MASK, 0, 0);
+ input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_CH_VALUE_MASK, 0, 0);
+
+ lradc->ts_input = input;
+ input_set_drvdata(input, lradc);
+ ret = input_register_device(input);
+ if (ret)
+ input_free_device(lradc->ts_input);
+
+ return ret;
+}
+
+static void mxs_lradc_ts_unregister(struct mxs_lradc *lradc)
+{
+ if (!lradc->use_touchscreen)
+ return;
+
+ cancel_work_sync(&lradc->ts_work);
+
+ input_unregister_device(lradc->ts_input);
+}
+
+/*
* IRQ Handling
*/
static irqreturn_t mxs_lradc_handle_irq(int irq, void *data)
struct iio_dev *iio = data;
struct mxs_lradc *lradc = iio_priv(iio);
unsigned long reg = readl(lradc->base + LRADC_CTRL1);
+ const uint32_t ts_irq_mask =
+ LRADC_CTRL1_TOUCH_DETECT_IRQ_EN |
+ LRADC_CTRL1_TOUCH_DETECT_IRQ;
if (!(reg & LRADC_CTRL1_LRADC_IRQ_MASK))
return IRQ_NONE;
/*
- * Touchscreen IRQ handling code shall probably have priority
- * and therefore shall be placed here.
+ * Touchscreen IRQ handling code has priority and therefore
+ * is placed here. In case touchscreen IRQ arrives, disable
+ * it ASAP
*/
+ if (reg & LRADC_CTRL1_TOUCH_DETECT_IRQ) {
+ writel(ts_irq_mask,
+ lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+ if (!lradc->stop_touchscreen)
+ schedule_work(&lradc->ts_work);
+ }
if (iio_buffer_enabled(iio))
iio_trigger_poll(iio->trig, iio_get_time_ns());
{
struct mxs_lradc *lradc = iio_priv(iio);
struct iio_buffer *buffer = iio->buffer;
- int ret = 0, chan, ofs = 0, enable = 0;
- uint32_t ctrl4 = 0;
+ int ret = 0, chan, ofs = 0;
+ unsigned long enable = 0;
+ uint32_t ctrl4_set = 0;
+ uint32_t ctrl4_clr = 0;
uint32_t ctrl1_irq = 0;
const uint32_t chan_value = LRADC_CH_ACCUMULATE |
((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
for_each_set_bit(chan, buffer->scan_mask, LRADC_MAX_TOTAL_CHANS) {
- ctrl4 |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
+ ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
+ ctrl4_clr |= LRADC_CTRL4_LRADCSELECT_MASK(ofs);
ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs);
writel(chan_value, lradc->base + LRADC_CH(ofs));
- enable |= 1 << ofs;
+ bitmap_set(&enable, ofs, 1);
ofs++;
}
writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK,
lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR);
- writel(ctrl4, lradc->base + LRADC_CTRL4);
+ writel(ctrl4_clr, lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR);
+ writel(ctrl4_set, lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET);
+
writel(ctrl1_irq, lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
writel(enable << LRADC_DELAY_TRIGGER_LRADCS_OFFSET,
static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio,
const unsigned long *mask)
{
- const int mw = bitmap_weight(mask, iio->masklength);
-
- return mw <= LRADC_MAX_MAPPED_CHANS;
+ struct mxs_lradc *lradc = iio_priv(iio);
+ const int len = iio->masklength;
+ const int map_chans = bitmap_weight(mask, len);
+ int rsvd_chans = 0;
+ unsigned long rsvd_mask = 0;
+
+ if (lradc->use_touchbutton)
+ rsvd_mask |= CHAN_MASK_TOUCHBUTTON;
+ if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_4WIRE)
+ rsvd_mask |= CHAN_MASK_TOUCHSCREEN_4WIRE;
+ if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_5WIRE)
+ rsvd_mask |= CHAN_MASK_TOUCHSCREEN_5WIRE;
+
+ if (lradc->use_touchbutton)
+ rsvd_chans++;
+ if (lradc->use_touchscreen)
+ rsvd_chans++;
+
+ /* Test for attempts to map channels with special mode of operation. */
+ if (bitmap_intersects(mask, &rsvd_mask, len))
+ return false;
+
+ /* Test for attempts to map more channels then available slots. */
+ if (map_chans + rsvd_chans > LRADC_MAX_MAPPED_CHANS)
+ return false;
+
+ return true;
}
static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
static void mxs_lradc_hw_init(struct mxs_lradc *lradc)
{
- int i;
- const uint32_t cfg =
+ /* The ADC always uses DELAY CHANNEL 0. */
+ const uint32_t adc_cfg =
+ (1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + 0)) |
(LRADC_DELAY_TIMER_PER << LRADC_DELAY_DELAY_OFFSET);
stmp_reset_block(lradc->base);
- for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++)
- writel(cfg | (1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + i)),
- lradc->base + LRADC_DELAY(i));
+ /* Configure DELAY CHANNEL 0 for generic ADC sampling. */
+ writel(adc_cfg, lradc->base + LRADC_DELAY(0));
+
+ /* Disable remaining DELAY CHANNELs */
+ writel(0, lradc->base + LRADC_DELAY(1));
+ writel(0, lradc->base + LRADC_DELAY(2));
+ writel(0, lradc->base + LRADC_DELAY(3));
+
+ /* Configure the touchscreen type */
+ writel(LRADC_CTRL0_TOUCH_SCREEN_TYPE,
+ lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+ if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_5WIRE) {
+ writel(LRADC_CTRL0_TOUCH_SCREEN_TYPE,
+ lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+ }
/* Start internal temperature sensing. */
writel(0, lradc->base + LRADC_CTRL2);
writel(0, lradc->base + LRADC_DELAY(i));
}
+static const struct of_device_id mxs_lradc_dt_ids[] = {
+ { .compatible = "fsl,imx23-lradc", .data = (void *)IMX23_LRADC, },
+ { .compatible = "fsl,imx28-lradc", .data = (void *)IMX28_LRADC, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids);
+
static int mxs_lradc_probe(struct platform_device *pdev)
{
+ const struct of_device_id *of_id =
+ of_match_device(mxs_lradc_dt_ids, &pdev->dev);
+ const struct mxs_lradc_of_config *of_cfg =
+ &mxs_lradc_of_config[(enum mxs_lradc_id)of_id->data];
struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
struct mxs_lradc *lradc;
struct iio_dev *iio;
struct resource *iores;
+ uint32_t ts_wires = 0;
int ret = 0;
int i;
goto err_addr;
}
+ INIT_WORK(&lradc->ts_work, mxs_lradc_ts_work);
+
+ /* Check if touchscreen is enabled in DT. */
+ ret = of_property_read_u32(node, "fsl,lradc-touchscreen-wires",
+ &ts_wires);
+ if (ret)
+ dev_info(dev, "Touchscreen not enabled.\n");
+ else if (ts_wires == 4)
+ lradc->use_touchscreen = MXS_LRADC_TOUCHSCREEN_4WIRE;
+ else if (ts_wires == 5)
+ lradc->use_touchscreen = MXS_LRADC_TOUCHSCREEN_5WIRE;
+ else
+ dev_warn(dev, "Unsupported number of touchscreen wires (%d)\n",
+ ts_wires);
+
/* Grab all IRQ sources */
- for (i = 0; i < 13; i++) {
+ for (i = 0; i < of_cfg->irq_count; i++) {
lradc->irq[i] = platform_get_irq(pdev, i);
if (lradc->irq[i] < 0) {
ret = -EINVAL;
ret = devm_request_irq(dev, lradc->irq[i],
mxs_lradc_handle_irq, 0,
- mxs_lradc_irq_name[i], iio);
+ of_cfg->irq_name[i], iio);
if (ret)
goto err_addr;
}
if (ret)
goto err_trig;
+ /* Register the touchscreen input device. */
+ ret = mxs_lradc_ts_register(lradc);
+ if (ret)
+ goto err_dev;
+
/* Register IIO device. */
ret = iio_device_register(iio);
if (ret) {
dev_err(dev, "Failed to register IIO device\n");
- goto err_dev;
+ goto err_ts;
}
/* Configure the hardware. */
return 0;
+err_ts:
+ mxs_lradc_ts_unregister(lradc);
err_dev:
mxs_lradc_trigger_remove(iio);
err_trig:
struct iio_dev *iio = platform_get_drvdata(pdev);
struct mxs_lradc *lradc = iio_priv(iio);
+ mxs_lradc_ts_unregister(lradc);
+
mxs_lradc_hw_stop(lradc);
iio_device_unregister(iio);
return 0;
}
-static const struct of_device_id mxs_lradc_dt_ids[] = {
- { .compatible = "fsl,imx28-lradc", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids);
-
static struct platform_driver mxs_lradc_driver = {
.driver = {
.name = DRIVER_NAME,
Say yes here to build support for Analog Devices adis16060 wide bandwidth
yaw rate gyroscope with SPI.
-config ADIS16080
- tristate "Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver"
- depends on SPI
- help
- Say yes here to build support for Analog Devices adis16080/100 Yaw Rate
- Gyroscope with SPI.
-
config ADIS16130
tristate "Analog Devices ADIS16130 High Precision Angular Rate Sensor driver"
depends on SPI
adis16060-y := adis16060_core.o
obj-$(CONFIG_ADIS16060) += adis16060.o
-adis16080-y := adis16080_core.o
-obj-$(CONFIG_ADIS16080) += adis16080.o
-
adis16130-y := adis16130_core.o
obj-$(CONFIG_ADIS16130) += adis16130.o
adis16260-y := adis16260_core.o
obj-$(CONFIG_ADIS16260) += adis16260.o
-adis16251-y := adis16251_core.o
-obj-$(CONFIG_ADIS16251) += adis16251.o
-
adxrs450-y := adxrs450_core.o
obj-$(CONFIG_ADXRS450) += adxrs450.o
while (st->channels[st->num_channels].indio_dev)
st->num_channels++;
- st->attrs = kzalloc(sizeof(st->attrs) * (st->num_channels + 1),
+ st->attrs = kzalloc(sizeof(*st->attrs) * (st->num_channels + 1),
GFP_KERNEL);
if (st->attrs == NULL) {
ret = -ENOMEM;
tristate "Analog Devices AD5933, AD5934 driver"
depends on I2C
select IIO_BUFFER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
help
Say yes here to build support for Analog Devices Impedance Converter,
Network Analyzer, AD5933/4, provides direct access via sysfs.
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
-#include "../ring_sw.h"
+#include <linux/iio/kfifo_buf.h>
#include "ad5933.h"
static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer)
return -ENOMEM;
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring:
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
iio_device_unregister(indio_dev);
iio_buffer_unregister(indio_dev);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
if (!IS_ERR(st->reg)) {
regulator_disable(st->reg);
regulator_put(st->reg);
+++ /dev/null
-#
-# IIO imu drivers configuration
-#
-menu "Inertial measurement units"
-
-config ADIS16400
- tristate "Analog Devices ADIS16400 and similar IMU SPI driver"
- depends on SPI
- select IIO_SW_RING if IIO_BUFFER
- select IIO_TRIGGER if IIO_BUFFER
- help
- Say yes here to build support for Analog Devices adis16300, adis16344,
- adis16350, adis16354, adis16355, adis16360, adis16362, adis16364,
- adis16365, adis16400 and adis16405 triaxial inertial sensors
- (adis16400 series also have magnetometers).
-
-endmenu
+++ /dev/null
-#
-# Makefile for Inertial Measurement Units
-#
-
-adis16400-y := adis16400_core.o
-adis16400-$(CONFIG_IIO_BUFFER) += adis16400_ring.o adis16400_trigger.o
-obj-$(CONFIG_ADIS16400) += adis16400.o
+++ /dev/null
-/*
- * adis16400.c support Analog Devices ADIS16400/5
- * 3d 2g Linear Accelerometers,
- * 3d Gyroscopes,
- * 3d Magnetometers via SPI
- *
- * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
- * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
- * Copyright (c) 2011 Analog Devices Inc.
- *
- * 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/interrupt.h>
-#include <linux/irq.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/list.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
-#include "adis16400.h"
-
-enum adis16400_chip_variant {
- ADIS16300,
- ADIS16334,
- ADIS16350,
- ADIS16360,
- ADIS16362,
- ADIS16364,
- ADIS16400,
-};
-
-/**
- * adis16400_spi_write_reg_8() - write single byte to a register
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
- * @reg_address: the address of the register to be written
- * @val: the value to write
- */
-static int adis16400_spi_write_reg_8(struct iio_dev *indio_dev,
- u8 reg_address,
- u8 val)
-{
- int ret;
- struct adis16400_state *st = iio_priv(indio_dev);
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADIS16400_WRITE_REG(reg_address);
- st->tx[1] = val;
-
- ret = spi_write(st->us, st->tx, 2);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-/**
- * adis16400_spi_write_reg_16() - write 2 bytes to a pair of registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
- * @reg_address: the address of the lower of the two registers. Second register
- * is assumed to have address one greater.
- * @val: value to be written
- *
- * At the moment the spi framework doesn't allow global setting of cs_change.
- * This means that use cannot be made of spi_write.
- */
-static int adis16400_spi_write_reg_16(struct iio_dev *indio_dev,
- u8 lower_reg_address,
- u16 value)
-{
- int ret;
- struct spi_message msg;
- struct adis16400_state *st = iio_priv(indio_dev);
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 2,
- .cs_change = 1,
- }, {
- .tx_buf = st->tx + 2,
- .bits_per_word = 8,
- .len = 2,
- },
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADIS16400_WRITE_REG(lower_reg_address);
- st->tx[1] = value & 0xFF;
- st->tx[2] = ADIS16400_WRITE_REG(lower_reg_address + 1);
- st->tx[3] = (value >> 8) & 0xFF;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
- ret = spi_sync(st->us, &msg);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-/**
- * adis16400_spi_read_reg_16() - read 2 bytes from a 16-bit register
- * @indio_dev: iio device
- * @reg_address: the address of the lower of the two registers. Second register
- * is assumed to have address one greater.
- * @val: somewhere to pass back the value read
- *
- * At the moment the spi framework doesn't allow global setting of cs_change.
- * This means that use cannot be made of spi_read.
- **/
-static int adis16400_spi_read_reg_16(struct iio_dev *indio_dev,
- u8 lower_reg_address,
- u16 *val)
-{
- struct spi_message msg;
- struct adis16400_state *st = iio_priv(indio_dev);
- int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 2,
- .cs_change = 1,
- }, {
- .rx_buf = st->rx,
- .bits_per_word = 8,
- .len = 2,
- },
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADIS16400_READ_REG(lower_reg_address);
- st->tx[1] = 0;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
- ret = spi_sync(st->us, &msg);
- if (ret) {
- dev_err(&st->us->dev,
- "problem when reading 16 bit register 0x%02X",
- lower_reg_address);
- goto error_ret;
- }
- *val = (st->rx[0] << 8) | st->rx[1];
-
-error_ret:
- mutex_unlock(&st->buf_lock);
- return ret;
-}
-
-static int adis16334_get_freq(struct iio_dev *indio_dev)
-{
- int ret;
- u16 t;
-
- ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_SMPL_PRD, &t);
- if (ret < 0)
- return ret;
-
- t >>= ADIS16334_RATE_DIV_SHIFT;
-
- return (8192 >> t) / 10;
-}
-
-static int adis16334_set_freq(struct iio_dev *indio_dev, unsigned int freq)
-{
- unsigned int t;
-
- t = ilog2(8192 / (freq * 10));
-
- if (t > 0x31)
- t = 0x31;
-
- t <<= ADIS16334_RATE_DIV_SHIFT;
- t |= ADIS16334_RATE_INT_CLK;
-
- return adis16400_spi_write_reg_16(indio_dev, ADIS16400_SMPL_PRD, t);
-}
-
-static int adis16400_get_freq(struct iio_dev *indio_dev)
-{
- int sps, ret;
- u16 t;
-
- ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_SMPL_PRD, &t);
- if (ret < 0)
- return ret;
- sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638;
- sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1;
-
- return sps;
-}
-
-static int adis16400_set_freq(struct iio_dev *indio_dev, unsigned int freq)
-{
- struct adis16400_state *st = iio_priv(indio_dev);
- unsigned int t;
-
- t = 1638 / freq;
- if (t > 0)
- t--;
- t &= ADIS16400_SMPL_PRD_DIV_MASK;
- if ((t & ADIS16400_SMPL_PRD_DIV_MASK) >= 0x0A)
- st->us->max_speed_hz = ADIS16400_SPI_SLOW;
- else
- st->us->max_speed_hz = ADIS16400_SPI_FAST;
-
- return adis16400_spi_write_reg_8(indio_dev,
- ADIS16400_SMPL_PRD, t);
-}
-
-static ssize_t adis16400_read_frequency(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct adis16400_state *st = iio_priv(indio_dev);
- int ret, len = 0;
-
- ret = st->variant->get_freq(indio_dev);
- if (ret < 0)
- return ret;
- len = sprintf(buf, "%d SPS\n", ret);
- return len;
-}
-
-static const unsigned adis16400_3db_divisors[] = {
- [0] = 2, /* Special case */
- [1] = 5,
- [2] = 10,
- [3] = 50,
- [4] = 200,
-};
-
-static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
-{
- int i, ret;
- u16 val16;
- for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 0; i--)
- if (sps/adis16400_3db_divisors[i] > val)
- break;
- if (i == -1)
- ret = -EINVAL;
- else {
- ret = adis16400_spi_read_reg_16(indio_dev,
- ADIS16400_SENS_AVG,
- &val16);
- if (ret < 0)
- goto error_ret;
-
- ret = adis16400_spi_write_reg_16(indio_dev,
- ADIS16400_SENS_AVG,
- (val16 & ~0x03) | i);
- }
-error_ret:
- return ret;
-}
-
-static ssize_t adis16400_write_frequency(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct adis16400_state *st = iio_priv(indio_dev);
- long val;
- int ret;
-
- ret = strict_strtol(buf, 10, &val);
- if (ret)
- return ret;
- if (val == 0)
- return -EINVAL;
-
- mutex_lock(&indio_dev->mlock);
-
- st->variant->set_freq(indio_dev, val);
-
- /* Also update the filter */
- mutex_unlock(&indio_dev->mlock);
-
- return ret ? ret : len;
-}
-
-static int adis16400_reset(struct iio_dev *indio_dev)
-{
- int ret;
- ret = adis16400_spi_write_reg_8(indio_dev,
- ADIS16400_GLOB_CMD,
- ADIS16400_GLOB_CMD_SW_RESET);
- if (ret)
- dev_err(&indio_dev->dev, "problem resetting device");
-
- return ret;
-}
-
-int adis16400_set_irq(struct iio_dev *indio_dev, bool enable)
-{
- int ret;
- u16 msc;
-
- ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_MSC_CTRL, &msc);
- if (ret)
- goto error_ret;
-
- msc |= ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH;
- if (enable)
- msc |= ADIS16400_MSC_CTRL_DATA_RDY_EN;
- else
- msc &= ~ADIS16400_MSC_CTRL_DATA_RDY_EN;
-
- ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_MSC_CTRL, msc);
- if (ret)
- goto error_ret;
-
-error_ret:
- return ret;
-}
-
-/* Power down the device */
-static int adis16400_stop_device(struct iio_dev *indio_dev)
-{
- int ret;
- u16 val = ADIS16400_SLP_CNT_POWER_OFF;
-
- ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_SLP_CNT, val);
- if (ret)
- dev_err(&indio_dev->dev,
- "problem with turning device off: SLP_CNT");
-
- return ret;
-}
-
-static int adis16400_check_status(struct iio_dev *indio_dev)
-{
- u16 status;
- int ret;
- struct device *dev = &indio_dev->dev;
-
- ret = adis16400_spi_read_reg_16(indio_dev,
- ADIS16400_DIAG_STAT, &status);
-
- if (ret < 0) {
- dev_err(dev, "Reading status failed\n");
- goto error_ret;
- }
- ret = status;
- if (status & ADIS16400_DIAG_STAT_ZACCL_FAIL)
- dev_err(dev, "Z-axis accelerometer self-test failure\n");
- if (status & ADIS16400_DIAG_STAT_YACCL_FAIL)
- dev_err(dev, "Y-axis accelerometer self-test failure\n");
- if (status & ADIS16400_DIAG_STAT_XACCL_FAIL)
- dev_err(dev, "X-axis accelerometer self-test failure\n");
- if (status & ADIS16400_DIAG_STAT_XGYRO_FAIL)
- dev_err(dev, "X-axis gyroscope self-test failure\n");
- if (status & ADIS16400_DIAG_STAT_YGYRO_FAIL)
- dev_err(dev, "Y-axis gyroscope self-test failure\n");
- if (status & ADIS16400_DIAG_STAT_ZGYRO_FAIL)
- dev_err(dev, "Z-axis gyroscope self-test failure\n");
- if (status & ADIS16400_DIAG_STAT_ALARM2)
- dev_err(dev, "Alarm 2 active\n");
- if (status & ADIS16400_DIAG_STAT_ALARM1)
- dev_err(dev, "Alarm 1 active\n");
- if (status & ADIS16400_DIAG_STAT_FLASH_CHK)
- dev_err(dev, "Flash checksum error\n");
- if (status & ADIS16400_DIAG_STAT_SELF_TEST)
- dev_err(dev, "Self test error\n");
- if (status & ADIS16400_DIAG_STAT_OVERFLOW)
- dev_err(dev, "Sensor overrange\n");
- if (status & ADIS16400_DIAG_STAT_SPI_FAIL)
- dev_err(dev, "SPI failure\n");
- if (status & ADIS16400_DIAG_STAT_FLASH_UPT)
- dev_err(dev, "Flash update failed\n");
- if (status & ADIS16400_DIAG_STAT_POWER_HIGH)
- dev_err(dev, "Power supply above 5.25V\n");
- if (status & ADIS16400_DIAG_STAT_POWER_LOW)
- dev_err(dev, "Power supply below 4.75V\n");
-
-error_ret:
- return ret;
-}
-
-static int adis16400_self_test(struct iio_dev *indio_dev)
-{
- int ret;
- ret = adis16400_spi_write_reg_16(indio_dev,
- ADIS16400_MSC_CTRL,
- ADIS16400_MSC_CTRL_MEM_TEST);
- if (ret) {
- dev_err(&indio_dev->dev, "problem starting self test");
- goto err_ret;
- }
-
- msleep(ADIS16400_MTEST_DELAY);
- adis16400_check_status(indio_dev);
-
-err_ret:
- return ret;
-}
-
-static int adis16400_initial_setup(struct iio_dev *indio_dev)
-{
- int ret;
- u16 prod_id, smp_prd;
- unsigned int device_id;
- struct adis16400_state *st = iio_priv(indio_dev);
-
- /* use low spi speed for init if the device has a slow mode */
- if (st->variant->flags & ADIS16400_HAS_SLOW_MODE)
- st->us->max_speed_hz = ADIS16400_SPI_SLOW;
- else
- st->us->max_speed_hz = ADIS16400_SPI_FAST;
- st->us->mode = SPI_MODE_3;
- spi_setup(st->us);
-
- ret = adis16400_set_irq(indio_dev, false);
- if (ret) {
- dev_err(&indio_dev->dev, "disable irq failed");
- goto err_ret;
- }
-
- ret = adis16400_self_test(indio_dev);
- if (ret) {
- dev_err(&indio_dev->dev, "self test failure");
- goto err_ret;
- }
-
- ret = adis16400_check_status(indio_dev);
- if (ret) {
- adis16400_reset(indio_dev);
- dev_err(&indio_dev->dev, "device not playing ball -> reset");
- msleep(ADIS16400_STARTUP_DELAY);
- ret = adis16400_check_status(indio_dev);
- if (ret) {
- dev_err(&indio_dev->dev, "giving up");
- goto err_ret;
- }
- }
- if (st->variant->flags & ADIS16400_HAS_PROD_ID) {
- ret = adis16400_spi_read_reg_16(indio_dev,
- ADIS16400_PRODUCT_ID, &prod_id);
- if (ret)
- goto err_ret;
-
- sscanf(indio_dev->name, "adis%u\n", &device_id);
-
- if (prod_id != device_id)
- dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
- device_id, prod_id);
-
- dev_info(&indio_dev->dev, "%s: prod_id 0x%04x at CS%d (irq %d)\n",
- indio_dev->name, prod_id,
- st->us->chip_select, st->us->irq);
- }
- /* use high spi speed if possible */
- if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) {
- ret = adis16400_spi_read_reg_16(indio_dev,
- ADIS16400_SMPL_PRD, &smp_prd);
- if (ret)
- goto err_ret;
-
- if ((smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) {
- st->us->max_speed_hz = ADIS16400_SPI_FAST;
- spi_setup(st->us);
- }
- }
-
-err_ret:
- return ret;
-}
-
-static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
- adis16400_read_frequency,
- adis16400_write_frequency);
-
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("409 546 819 1638");
-
-enum adis16400_chan {
- in_supply,
- gyro_x,
- gyro_y,
- gyro_z,
- accel_x,
- accel_y,
- accel_z,
- magn_x,
- magn_y,
- magn_z,
- temp,
- temp0, temp1, temp2,
- in1,
- in2,
- incli_x,
- incli_y,
-};
-
-static u8 adis16400_addresses[18][2] = {
- [in_supply] = { ADIS16400_SUPPLY_OUT },
- [gyro_x] = { ADIS16400_XGYRO_OUT, ADIS16400_XGYRO_OFF },
- [gyro_y] = { ADIS16400_YGYRO_OUT, ADIS16400_YGYRO_OFF },
- [gyro_z] = { ADIS16400_ZGYRO_OUT, ADIS16400_ZGYRO_OFF },
- [accel_x] = { ADIS16400_XACCL_OUT, ADIS16400_XACCL_OFF },
- [accel_y] = { ADIS16400_YACCL_OUT, ADIS16400_YACCL_OFF },
- [accel_z] = { ADIS16400_ZACCL_OUT, ADIS16400_ZACCL_OFF },
- [magn_x] = { ADIS16400_XMAGN_OUT },
- [magn_y] = { ADIS16400_YMAGN_OUT },
- [magn_z] = { ADIS16400_ZMAGN_OUT },
- [temp] = { ADIS16400_TEMP_OUT },
- [temp0] = { ADIS16350_XTEMP_OUT },
- [temp1] = { ADIS16350_YTEMP_OUT },
- [temp2] = { ADIS16350_ZTEMP_OUT },
- [in1] = { ADIS16300_AUX_ADC },
- [in2] = { ADIS16400_AUX_ADC },
- [incli_x] = { ADIS16300_PITCH_OUT },
- [incli_y] = { ADIS16300_ROLL_OUT }
-};
-
-
-static int adis16400_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
-{
- struct adis16400_state *st = iio_priv(indio_dev);
- int ret, sps;
-
- switch (mask) {
- case IIO_CHAN_INFO_CALIBBIAS:
- mutex_lock(&indio_dev->mlock);
- ret = adis16400_spi_write_reg_16(indio_dev,
- adis16400_addresses[chan->address][1],
- val);
- mutex_unlock(&indio_dev->mlock);
- return ret;
- case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- /* Need to cache values so we can update if the frequency
- changes */
- mutex_lock(&indio_dev->mlock);
- st->filt_int = val;
- /* Work out update to current value */
- sps = st->variant->get_freq(indio_dev);
- if (sps < 0) {
- mutex_unlock(&indio_dev->mlock);
- return sps;
- }
-
- ret = adis16400_set_filter(indio_dev, sps, val);
- mutex_unlock(&indio_dev->mlock);
- return ret;
- default:
- return -EINVAL;
- }
-}
-
-static int adis16400_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val,
- int *val2,
- long mask)
-{
- struct adis16400_state *st = iio_priv(indio_dev);
- int ret, shift;
- s16 val16;
-
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
- ret = adis16400_spi_read_reg_16(indio_dev,
- adis16400_addresses[chan->address][0],
- &val16);
- if (ret) {
- mutex_unlock(&indio_dev->mlock);
- return ret;
- }
- val16 &= (1 << chan->scan_type.realbits) - 1;
- if (chan->scan_type.sign == 's') {
- shift = 16 - chan->scan_type.realbits;
- val16 = (s16)(val16 << shift) >> shift;
- }
- *val = val16;
- mutex_unlock(&indio_dev->mlock);
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_SCALE:
- switch (chan->type) {
- case IIO_ANGL_VEL:
- *val = 0;
- *val2 = st->variant->gyro_scale_micro;
- return IIO_VAL_INT_PLUS_MICRO;
- case IIO_VOLTAGE:
- *val = 0;
- if (chan->channel == 0) {
- *val = 2;
- *val2 = 418000; /* 2.418 mV */
- } else {
- *val = 0;
- *val2 = 805800; /* 805.8 uV */
- }
- return IIO_VAL_INT_PLUS_MICRO;
- case IIO_ACCEL:
- *val = 0;
- *val2 = st->variant->accel_scale_micro;
- return IIO_VAL_INT_PLUS_MICRO;
- case IIO_MAGN:
- *val = 0;
- *val2 = 500; /* 0.5 mgauss */
- return IIO_VAL_INT_PLUS_MICRO;
- case IIO_TEMP:
- *val = st->variant->temp_scale_nano / 1000000;
- *val2 = (st->variant->temp_scale_nano % 1000000);
- return IIO_VAL_INT_PLUS_MICRO;
- default:
- return -EINVAL;
- }
- case IIO_CHAN_INFO_CALIBBIAS:
- mutex_lock(&indio_dev->mlock);
- ret = adis16400_spi_read_reg_16(indio_dev,
- adis16400_addresses[chan->address][1],
- &val16);
- mutex_unlock(&indio_dev->mlock);
- if (ret)
- return ret;
- val16 = ((val16 & 0xFFF) << 4) >> 4;
- *val = val16;
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_OFFSET:
- /* currently only temperature */
- *val = st->variant->temp_offset;
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- mutex_lock(&indio_dev->mlock);
- /* Need both the number of taps and the sampling frequency */
- ret = adis16400_spi_read_reg_16(indio_dev,
- ADIS16400_SENS_AVG,
- &val16);
- if (ret < 0) {
- mutex_unlock(&indio_dev->mlock);
- return ret;
- }
- val16 = st->variant->get_freq(indio_dev);
- if (ret > 0)
- *val = ret/adis16400_3db_divisors[val16 & 0x03];
- *val2 = 0;
- mutex_unlock(&indio_dev->mlock);
- if (ret < 0)
- return ret;
- return IIO_VAL_INT_PLUS_MICRO;
- default:
- return -EINVAL;
- }
-}
-
-static const struct iio_chan_spec adis16400_channels[] = {
- {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- .address = in_supply,
- .scan_index = ADIS16400_SCAN_SUPPLY,
- .scan_type = IIO_ST('u', 14, 16, 0),
- }, {
- .type = IIO_ANGL_VEL,
- .modified = 1,
- .channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = gyro_x,
- .scan_index = ADIS16400_SCAN_GYRO_X,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ANGL_VEL,
- .modified = 1,
- .channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = gyro_y,
- .scan_index = ADIS16400_SCAN_GYRO_Y,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ANGL_VEL,
- .modified = 1,
- .channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = gyro_z,
- .scan_index = ADIS16400_SCAN_GYRO_Z,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_x,
- .scan_index = ADIS16400_SCAN_ACC_X,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_y,
- .scan_index = ADIS16400_SCAN_ACC_Y,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_z,
- .scan_index = ADIS16400_SCAN_ACC_Z,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_MAGN,
- .modified = 1,
- .channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = magn_x,
- .scan_index = ADIS16400_SCAN_MAGN_X,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_MAGN,
- .modified = 1,
- .channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = magn_y,
- .scan_index = ADIS16400_SCAN_MAGN_Y,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_MAGN,
- .modified = 1,
- .channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = magn_z,
- .scan_index = ADIS16400_SCAN_MAGN_Z,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_TEMP,
- .indexed = 1,
- .channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- .address = temp,
- .scan_index = ADIS16400_SCAN_TEMP,
- .scan_type = IIO_ST('s', 12, 16, 0),
- }, {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- .address = in2,
- .scan_index = ADIS16400_SCAN_ADC_0,
- .scan_type = IIO_ST('s', 12, 16, 0),
- },
- IIO_CHAN_SOFT_TIMESTAMP(12)
-};
-
-static const struct iio_chan_spec adis16350_channels[] = {
- {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- .address = in_supply,
- .scan_index = ADIS16400_SCAN_SUPPLY,
- .scan_type = IIO_ST('u', 12, 16, 0),
- }, {
- .type = IIO_ANGL_VEL,
- .modified = 1,
- .channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = gyro_x,
- .scan_index = ADIS16400_SCAN_GYRO_X,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ANGL_VEL,
- .modified = 1,
- .channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = gyro_y,
- .scan_index = ADIS16400_SCAN_GYRO_Y,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ANGL_VEL,
- .modified = 1,
- .channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = gyro_z,
- .scan_index = ADIS16400_SCAN_GYRO_Z,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_x,
- .scan_index = ADIS16400_SCAN_ACC_X,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_y,
- .scan_index = ADIS16400_SCAN_ACC_Y,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_z,
- .scan_index = ADIS16400_SCAN_ACC_Z,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_TEMP,
- .indexed = 1,
- .channel = 0,
- .extend_name = "x",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = temp0,
- .scan_index = ADIS16350_SCAN_TEMP_X,
- .scan_type = IIO_ST('s', 12, 16, 0),
- }, {
- .type = IIO_TEMP,
- .indexed = 1,
- .channel = 1,
- .extend_name = "y",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = temp1,
- .scan_index = ADIS16350_SCAN_TEMP_Y,
- .scan_type = IIO_ST('s', 12, 16, 0),
- }, {
- .type = IIO_TEMP,
- .indexed = 1,
- .channel = 2,
- .extend_name = "z",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- .address = temp2,
- .scan_index = ADIS16350_SCAN_TEMP_Z,
- .scan_type = IIO_ST('s', 12, 16, 0),
- }, {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- .address = in1,
- .scan_index = ADIS16350_SCAN_ADC_0,
- .scan_type = IIO_ST('s', 12, 16, 0),
- },
- IIO_CHAN_SOFT_TIMESTAMP(11)
-};
-
-static const struct iio_chan_spec adis16300_channels[] = {
- {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- .address = in_supply,
- .scan_index = ADIS16400_SCAN_SUPPLY,
- .scan_type = IIO_ST('u', 12, 16, 0),
- }, {
- .type = IIO_ANGL_VEL,
- .modified = 1,
- .channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = gyro_x,
- .scan_index = ADIS16400_SCAN_GYRO_X,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_x,
- .scan_index = ADIS16400_SCAN_ACC_X,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_y,
- .scan_index = ADIS16400_SCAN_ACC_Y,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_z,
- .scan_index = ADIS16400_SCAN_ACC_Z,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_TEMP,
- .indexed = 1,
- .channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- .address = temp0,
- .scan_index = ADIS16400_SCAN_TEMP,
- .scan_type = IIO_ST('s', 12, 16, 0),
- }, {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- .address = in1,
- .scan_index = ADIS16350_SCAN_ADC_0,
- .scan_type = IIO_ST('s', 12, 16, 0),
- }, {
- .type = IIO_INCLI,
- .modified = 1,
- .channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- .address = incli_x,
- .scan_index = ADIS16300_SCAN_INCLI_X,
- .scan_type = IIO_ST('s', 13, 16, 0),
- }, {
- .type = IIO_INCLI,
- .modified = 1,
- .channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- .address = incli_y,
- .scan_index = ADIS16300_SCAN_INCLI_Y,
- .scan_type = IIO_ST('s', 13, 16, 0),
- },
- IIO_CHAN_SOFT_TIMESTAMP(14)
-};
-
-static const struct iio_chan_spec adis16334_channels[] = {
- {
- .type = IIO_ANGL_VEL,
- .modified = 1,
- .channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = gyro_x,
- .scan_index = ADIS16400_SCAN_GYRO_X,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ANGL_VEL,
- .modified = 1,
- .channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = gyro_y,
- .scan_index = ADIS16400_SCAN_GYRO_Y,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ANGL_VEL,
- .modified = 1,
- .channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = gyro_z,
- .scan_index = ADIS16400_SCAN_GYRO_Z,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_x,
- .scan_index = ADIS16400_SCAN_ACC_X,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_y,
- .scan_index = ADIS16400_SCAN_ACC_Y,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
- .address = accel_z,
- .scan_index = ADIS16400_SCAN_ACC_Z,
- .scan_type = IIO_ST('s', 14, 16, 0),
- }, {
- .type = IIO_TEMP,
- .indexed = 1,
- .channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- .address = temp0,
- .scan_index = ADIS16400_SCAN_TEMP,
- .scan_type = IIO_ST('s', 14, 16, 0),
- },
- IIO_CHAN_SOFT_TIMESTAMP(12)
-};
-
-static struct attribute *adis16400_attributes[] = {
- &iio_dev_attr_sampling_frequency.dev_attr.attr,
- &iio_const_attr_sampling_frequency_available.dev_attr.attr,
- NULL
-};
-
-static const struct attribute_group adis16400_attribute_group = {
- .attrs = adis16400_attributes,
-};
-
-static struct adis16400_chip_info adis16400_chips[] = {
- [ADIS16300] = {
- .channels = adis16300_channels,
- .num_channels = ARRAY_SIZE(adis16300_channels),
- .flags = ADIS16400_HAS_SLOW_MODE,
- .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
- .accel_scale_micro = 5884,
- .temp_scale_nano = 140000000, /* 0.14 C */
- .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
- .default_scan_mask = (1 << ADIS16400_SCAN_SUPPLY) |
- (1 << ADIS16400_SCAN_GYRO_X) | (1 << ADIS16400_SCAN_ACC_X) |
- (1 << ADIS16400_SCAN_ACC_Y) | (1 << ADIS16400_SCAN_ACC_Z) |
- (1 << ADIS16400_SCAN_TEMP) | (1 << ADIS16400_SCAN_ADC_0) |
- (1 << ADIS16300_SCAN_INCLI_X) | (1 << ADIS16300_SCAN_INCLI_Y) |
- (1 << 14),
- .set_freq = adis16400_set_freq,
- .get_freq = adis16400_get_freq,
- },
- [ADIS16334] = {
- .channels = adis16334_channels,
- .num_channels = ARRAY_SIZE(adis16334_channels),
- .flags = ADIS16400_HAS_PROD_ID,
- .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
- .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */
- .temp_scale_nano = 67850000, /* 0.06785 C */
- .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */
- .default_scan_mask = (1 << ADIS16400_SCAN_GYRO_X) |
- (1 << ADIS16400_SCAN_GYRO_Y) | (1 << ADIS16400_SCAN_GYRO_Z) |
- (1 << ADIS16400_SCAN_ACC_X) | (1 << ADIS16400_SCAN_ACC_Y) |
- (1 << ADIS16400_SCAN_ACC_Z),
- .set_freq = adis16334_set_freq,
- .get_freq = adis16334_get_freq,
- },
- [ADIS16350] = {
- .channels = adis16350_channels,
- .num_channels = ARRAY_SIZE(adis16350_channels),
- .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */
- .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */
- .temp_scale_nano = 145300000, /* 0.1453 C */
- .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */
- .default_scan_mask = 0x7FF,
- .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE,
- .set_freq = adis16400_set_freq,
- .get_freq = adis16400_get_freq,
- },
- [ADIS16360] = {
- .channels = adis16350_channels,
- .num_channels = ARRAY_SIZE(adis16350_channels),
- .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE,
- .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
- .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
- .temp_scale_nano = 136000000, /* 0.136 C */
- .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
- .default_scan_mask = 0x7FF,
- .set_freq = adis16400_set_freq,
- .get_freq = adis16400_get_freq,
- },
- [ADIS16362] = {
- .channels = adis16350_channels,
- .num_channels = ARRAY_SIZE(adis16350_channels),
- .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE,
- .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
- .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */
- .temp_scale_nano = 136000000, /* 0.136 C */
- .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
- .default_scan_mask = 0x7FF,
- .set_freq = adis16400_set_freq,
- .get_freq = adis16400_get_freq,
- },
- [ADIS16364] = {
- .channels = adis16350_channels,
- .num_channels = ARRAY_SIZE(adis16350_channels),
- .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE,
- .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
- .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */
- .temp_scale_nano = 136000000, /* 0.136 C */
- .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
- .default_scan_mask = 0x7FF,
- .set_freq = adis16400_set_freq,
- .get_freq = adis16400_get_freq,
- },
- [ADIS16400] = {
- .channels = adis16400_channels,
- .num_channels = ARRAY_SIZE(adis16400_channels),
- .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE,
- .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
- .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
- .default_scan_mask = 0xFFF,
- .temp_scale_nano = 140000000, /* 0.14 C */
- .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
- .set_freq = adis16400_set_freq,
- .get_freq = adis16400_get_freq,
- }
-};
-
-static const struct iio_info adis16400_info = {
- .driver_module = THIS_MODULE,
- .read_raw = &adis16400_read_raw,
- .write_raw = &adis16400_write_raw,
- .attrs = &adis16400_attribute_group,
-};
-
-static int adis16400_probe(struct spi_device *spi)
-{
- int ret;
- struct adis16400_state *st;
- struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
- st = iio_priv(indio_dev);
- /* this is only used for removal purposes */
- spi_set_drvdata(spi, indio_dev);
-
- st->us = spi;
- mutex_init(&st->buf_lock);
-
- /* setup the industrialio driver allocated elements */
- st->variant = &adis16400_chips[spi_get_device_id(spi)->driver_data];
- indio_dev->dev.parent = &spi->dev;
- indio_dev->name = spi_get_device_id(spi)->name;
- indio_dev->channels = st->variant->channels;
- indio_dev->num_channels = st->variant->num_channels;
- indio_dev->info = &adis16400_info;
- indio_dev->modes = INDIO_DIRECT_MODE;
-
- ret = adis16400_configure_ring(indio_dev);
- if (ret)
- goto error_free_dev;
-
- ret = iio_buffer_register(indio_dev,
- st->variant->channels,
- st->variant->num_channels);
- if (ret) {
- dev_err(&spi->dev, "failed to initialize the ring\n");
- goto error_unreg_ring_funcs;
- }
-
- if (spi->irq) {
- ret = adis16400_probe_trigger(indio_dev);
- if (ret)
- goto error_uninitialize_ring;
- }
-
- /* Get the device into a sane initial state */
- ret = adis16400_initial_setup(indio_dev);
- if (ret)
- goto error_remove_trigger;
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_remove_trigger;
-
- return 0;
-
-error_remove_trigger:
- if (spi->irq)
- adis16400_remove_trigger(indio_dev);
-error_uninitialize_ring:
- iio_buffer_unregister(indio_dev);
-error_unreg_ring_funcs:
- adis16400_unconfigure_ring(indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
- return ret;
-}
-
-/* fixme, confirm ordering in this function */
-static int adis16400_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
-
- iio_device_unregister(indio_dev);
- adis16400_stop_device(indio_dev);
-
- adis16400_remove_trigger(indio_dev);
- iio_buffer_unregister(indio_dev);
- adis16400_unconfigure_ring(indio_dev);
- iio_device_free(indio_dev);
-
- return 0;
-}
-
-static const struct spi_device_id adis16400_id[] = {
- {"adis16300", ADIS16300},
- {"adis16334", ADIS16334},
- {"adis16350", ADIS16350},
- {"adis16354", ADIS16350},
- {"adis16355", ADIS16350},
- {"adis16360", ADIS16360},
- {"adis16362", ADIS16362},
- {"adis16364", ADIS16364},
- {"adis16365", ADIS16360},
- {"adis16400", ADIS16400},
- {"adis16405", ADIS16400},
- {}
-};
-MODULE_DEVICE_TABLE(spi, adis16400_id);
-
-static struct spi_driver adis16400_driver = {
- .driver = {
- .name = "adis16400",
- .owner = THIS_MODULE,
- },
- .id_table = adis16400_id,
- .probe = adis16400_probe,
- .remove = adis16400_remove,
-};
-module_spi_driver(adis16400_driver);
-
-MODULE_AUTHOR("Manuel Stahl <manuel.stahl@iis.fraunhofer.de>");
-MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver");
-MODULE_LICENSE("GPL v2");
+++ /dev/null
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/bitops.h>
-#include <linux/export.h>
-
-#include <linux/iio/iio.h>
-#include "../ring_sw.h"
-#include <linux/iio/trigger_consumer.h>
-#include "adis16400.h"
-
-/**
- * adis16400_spi_read_burst() - read all data registers
- * @indio_dev: the IIO device
- * @rx: somewhere to pass back the value read (min size is 24 bytes)
- **/
-static int adis16400_spi_read_burst(struct iio_dev *indio_dev, u8 *rx)
-{
- struct spi_message msg;
- struct adis16400_state *st = iio_priv(indio_dev);
- u32 old_speed_hz = st->us->max_speed_hz;
- int ret;
-
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 2,
- }, {
- .rx_buf = rx,
- .bits_per_word = 8,
- .len = 24,
- },
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADIS16400_READ_REG(ADIS16400_GLOB_CMD);
- st->tx[1] = 0;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
-
- st->us->max_speed_hz = min(ADIS16400_SPI_BURST, old_speed_hz);
- spi_setup(st->us);
-
- ret = spi_sync(st->us, &msg);
- if (ret)
- dev_err(&st->us->dev, "problem when burst reading");
-
- st->us->max_speed_hz = old_speed_hz;
- spi_setup(st->us);
- mutex_unlock(&st->buf_lock);
- return ret;
-}
-
-static const u16 read_all_tx_array[] = {
- cpu_to_be16(ADIS16400_READ_REG(ADIS16400_SUPPLY_OUT)),
- cpu_to_be16(ADIS16400_READ_REG(ADIS16400_XGYRO_OUT)),
- cpu_to_be16(ADIS16400_READ_REG(ADIS16400_YGYRO_OUT)),
- cpu_to_be16(ADIS16400_READ_REG(ADIS16400_ZGYRO_OUT)),
- cpu_to_be16(ADIS16400_READ_REG(ADIS16400_XACCL_OUT)),
- cpu_to_be16(ADIS16400_READ_REG(ADIS16400_YACCL_OUT)),
- cpu_to_be16(ADIS16400_READ_REG(ADIS16400_ZACCL_OUT)),
- cpu_to_be16(ADIS16400_READ_REG(ADIS16350_XTEMP_OUT)),
- cpu_to_be16(ADIS16400_READ_REG(ADIS16350_YTEMP_OUT)),
- cpu_to_be16(ADIS16400_READ_REG(ADIS16350_ZTEMP_OUT)),
- cpu_to_be16(ADIS16400_READ_REG(ADIS16400_AUX_ADC)),
-};
-
-static int adis16350_spi_read_all(struct iio_dev *indio_dev, u8 *rx)
-{
- struct adis16400_state *st = iio_priv(indio_dev);
-
- struct spi_message msg;
- int i, j = 0, ret;
- struct spi_transfer *xfers;
- int scan_count = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength);
-
- xfers = kzalloc(sizeof(*xfers)*(scan_count + 1),
- GFP_KERNEL);
- if (xfers == NULL)
- return -ENOMEM;
-
- for (i = 0; i < ARRAY_SIZE(read_all_tx_array); i++)
- if (test_bit(i, indio_dev->active_scan_mask)) {
- xfers[j].tx_buf = &read_all_tx_array[i];
- xfers[j].bits_per_word = 16;
- xfers[j].len = 2;
- xfers[j + 1].rx_buf = rx + j*2;
- j++;
- }
- xfers[j].bits_per_word = 16;
- xfers[j].len = 2;
-
- spi_message_init(&msg);
- for (j = 0; j < scan_count + 1; j++)
- spi_message_add_tail(&xfers[j], &msg);
-
- ret = spi_sync(st->us, &msg);
- kfree(xfers);
-
- return ret;
-}
-
-/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
- * specific to be rolled into the core.
- */
-static irqreturn_t adis16400_trigger_handler(int irq, void *p)
-{
- struct iio_poll_func *pf = p;
- struct iio_dev *indio_dev = pf->indio_dev;
- struct adis16400_state *st = iio_priv(indio_dev);
- int i = 0, j, ret = 0;
- s16 *data;
-
- /* Asumption that long is enough for maximum channels */
- unsigned long mask = *indio_dev->active_scan_mask;
- int scan_count = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength);
- data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
- if (data == NULL) {
- dev_err(&st->us->dev, "memory alloc failed in ring bh");
- goto done;
- }
-
- if (scan_count) {
- if (st->variant->flags & ADIS16400_NO_BURST) {
- ret = adis16350_spi_read_all(indio_dev, st->rx);
- if (ret < 0)
- goto done;
- for (; i < scan_count; i++)
- data[i] = *(s16 *)(st->rx + i*2);
- } else {
- ret = adis16400_spi_read_burst(indio_dev, st->rx);
- if (ret < 0)
- goto done;
- for (; i < scan_count; i++) {
- j = __ffs(mask);
- mask &= ~(1 << j);
- data[i] = be16_to_cpup(
- (__be16 *)&(st->rx[j*2]));
- }
- }
- }
- /* Guaranteed to be aligned with 8 byte boundary */
- if (indio_dev->scan_timestamp)
- *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffers(indio_dev, (u8 *) data);
-
-done:
- kfree(data);
- iio_trigger_notify_done(indio_dev->trig);
-
- return IRQ_HANDLED;
-}
-
-void adis16400_unconfigure_ring(struct iio_dev *indio_dev)
-{
- iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
-}
-
-static const struct iio_buffer_setup_ops adis16400_ring_setup_ops = {
- .preenable = &iio_sw_buffer_preenable,
- .postenable = &iio_triggered_buffer_postenable,
- .predisable = &iio_triggered_buffer_predisable,
-};
-
-int adis16400_configure_ring(struct iio_dev *indio_dev)
-{
- int ret = 0;
- struct iio_buffer *ring;
-
- ring = iio_sw_rb_allocate(indio_dev);
- if (!ring) {
- ret = -ENOMEM;
- return ret;
- }
- indio_dev->buffer = ring;
- ring->scan_timestamp = true;
- indio_dev->setup_ops = &adis16400_ring_setup_ops;
-
- indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
- &adis16400_trigger_handler,
- IRQF_ONESHOT,
- indio_dev,
- "%s_consumer%d",
- indio_dev->name,
- indio_dev->id);
- if (indio_dev->pollfunc == NULL) {
- ret = -ENOMEM;
- goto error_iio_sw_rb_free;
- }
-
- indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
- return 0;
-error_iio_sw_rb_free:
- iio_sw_rb_free(indio_dev->buffer);
- return ret;
-}
+++ /dev/null
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/export.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/trigger.h>
-#include "adis16400.h"
-
-/**
- * adis16400_data_rdy_trigger_set_state() set datardy interrupt state
- **/
-static int adis16400_data_rdy_trigger_set_state(struct iio_trigger *trig,
- bool state)
-{
- struct iio_dev *indio_dev = trig->private_data;
-
- dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
- return adis16400_set_irq(indio_dev, state);
-}
-
-static const struct iio_trigger_ops adis16400_trigger_ops = {
- .owner = THIS_MODULE,
- .set_trigger_state = &adis16400_data_rdy_trigger_set_state,
-};
-
-int adis16400_probe_trigger(struct iio_dev *indio_dev)
-{
- int ret;
- struct adis16400_state *st = iio_priv(indio_dev);
-
- st->trig = iio_trigger_alloc("%s-dev%d",
- indio_dev->name,
- indio_dev->id);
- if (st->trig == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
-
- ret = request_irq(st->us->irq,
- &iio_trigger_generic_data_rdy_poll,
- IRQF_TRIGGER_RISING,
- "adis16400",
- st->trig);
- if (ret)
- goto error_free_trig;
- st->trig->dev.parent = &st->us->dev;
- st->trig->private_data = indio_dev;
- st->trig->ops = &adis16400_trigger_ops;
- ret = iio_trigger_register(st->trig);
-
- /* select default trigger */
- indio_dev->trig = st->trig;
- if (ret)
- goto error_free_irq;
-
- return 0;
-
-error_free_irq:
- free_irq(st->us->irq, st->trig);
-error_free_trig:
- iio_trigger_free(st->trig);
-error_ret:
- return ret;
-}
-
-void adis16400_remove_trigger(struct iio_dev *indio_dev)
-{
- struct adis16400_state *st = iio_priv(indio_dev);
-
- iio_trigger_unregister(st->trig);
- free_irq(st->us->irq, st->trig);
- iio_trigger_free(st->trig);
-}
Proximity value via iio. The ISL29028 provides the concurrent sensing
of ambient light and proximity.
-config SENSORS_TSL2563
- tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors"
- depends on I2C
- help
- If you say yes here you get support for the Taos TSL2560,
- TSL2561, TSL2562 and TSL2563 ambient light sensors.
-
- This driver can also be built as a module. If so, the module
- will be called tsl2563.
-
config TSL2583
tristate "TAOS TSL2580, TSL2581 and TSL2583 light-to-digital converters"
depends on I2C
# Makefile for industrial I/O Light sensors
#
-obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
obj-$(CONFIG_TSL2583) += tsl2583.o
};
/**
- * tsl2x7x_parse_buffer() - parse a decimal result from a buffer.
- * @*buf: pointer to char buffer to parse
- * @*result: pointer to buffer to contain
- * resulting interger / decimal as ints.
- *
- */
-static int
-tsl2x7x_parse_buffer(const char *buf, struct tsl2x7x_parse_result *result)
-{
- int integer = 0, fract = 0, fract_mult = 100000;
- bool integer_part = true, negative = false;
-
- if (buf[0] == '-') {
- negative = true;
- buf++;
- }
-
- while (*buf) {
- if ('0' <= *buf && *buf <= '9') {
- if (integer_part)
- integer = integer*10 + *buf - '0';
- else {
- fract += fract_mult*(*buf - '0');
- if (fract_mult == 1)
- break;
- fract_mult /= 10;
- }
- } else if (*buf == '\n') {
- if (*(buf + 1) == '\0')
- break;
- else
- return -EINVAL;
- } else if (*buf == '.') {
- integer_part = false;
- } else {
- return -EINVAL;
- }
- buf++;
- }
- if (negative) {
- if (integer)
- integer = -integer;
- else
- fract = -fract;
- }
-
- result->integer = integer;
- result->fract = fract;
-
- return 0;
-}
-
-/**
* tsl2x7x_i2c_read() - Read a byte from a register.
* @client: i2c client
* @reg: device register to read from
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
struct tsl2x7x_parse_result result;
+ int ret;
- result.integer = 0;
- result.fract = 0;
-
- tsl2x7x_parse_buffer(buf, &result);
+ ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract);
+ if (ret)
+ return ret;
- result.fract /= 1000;
result.fract /= 3;
chip->tsl2x7x_settings.als_time =
(TSL2X7X_MAX_TIMER_CNT - (u8)result.fract);
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
struct tsl2x7x_parse_result result;
int y, z, filter_delay;
+ int ret;
- result.integer = 0;
- result.fract = 0;
- tsl2x7x_parse_buffer(buf, &result);
+ ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract);
+ if (ret)
+ return ret;
- result.fract /= 1000;
y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
z = y * TSL2X7X_MIN_ITIME;
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
struct tsl2x7x_parse_result result;
int y, z, filter_delay;
+ int ret;
- result.integer = 0;
- result.fract = 0;
- tsl2x7x_parse_buffer(buf, &result);
+ ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract);
+ if (ret)
+ return ret;
- result.fract /= 1000;
y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
z = y * TSL2X7X_MIN_ITIME;
tristate "Analog Devices ADE7758 Poly Phase Multifunction Energy Metering IC Driver"
depends on SPI
select IIO_TRIGGER if IIO_BUFFER
- select IIO_SW_RING if IIO_BUFFER
+ select IIO_KFIFO_BUF if IIO_BUFFER
help
Say yes here to build support for Analog Devices ADE7758 Polyphase
Multifunction Energy Metering IC with Per Phase Information Driver.
#include <asm/unaligned.h>
#include <linux/iio/iio.h>
-#include "../ring_sw.h"
+#include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger_consumer.h>
#include "ade7758.h"
void ade7758_unconfigure_ring(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
int ade7758_configure_ring(struct iio_dev *indio_dev)
struct ade7758_state *st = iio_priv(indio_dev);
int ret = 0;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
return ret;
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_iio_sw_rb_free;
+ goto error_iio_kfifo_free;
}
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_iio_sw_rb_free:
- iio_sw_rb_free(indio_dev->buffer);
+error_iio_kfifo_free:
+ iio_kfifo_free(indio_dev->buffer);
return ret;
}
+++ /dev/null
-/* The industrial I/O simple minimally locked ring buffer.
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-#include <linux/poll.h>
-#include "ring_sw.h"
-#include <linux/iio/trigger.h>
-
-/**
- * struct iio_sw_ring_buffer - software ring buffer
- * @buf: generic ring buffer elements
- * @data: the ring buffer memory
- * @read_p: read pointer (oldest available)
- * @write_p: write pointer
- * @half_p: half buffer length behind write_p (event generation)
- * @update_needed: flag to indicate change in size requested
- *
- * Note that the first element of all ring buffers must be a
- * struct iio_buffer.
-**/
-struct iio_sw_ring_buffer {
- struct iio_buffer buf;
- unsigned char *data;
- unsigned char *read_p;
- unsigned char *write_p;
- /* used to act as a point at which to signal an event */
- unsigned char *half_p;
- int update_needed;
-};
-
-#define iio_to_sw_ring(r) container_of(r, struct iio_sw_ring_buffer, buf)
-
-static inline int __iio_allocate_sw_ring_buffer(struct iio_sw_ring_buffer *ring,
- int bytes_per_datum, int length)
-{
- if ((length == 0) || (bytes_per_datum == 0))
- return -EINVAL;
- __iio_update_buffer(&ring->buf, bytes_per_datum, length);
- ring->data = kmalloc(length*ring->buf.bytes_per_datum, GFP_ATOMIC);
- ring->read_p = NULL;
- ring->write_p = NULL;
- ring->half_p = NULL;
- return ring->data ? 0 : -ENOMEM;
-}
-
-static inline void __iio_free_sw_ring_buffer(struct iio_sw_ring_buffer *ring)
-{
- kfree(ring->data);
-}
-
-/* Ring buffer related functionality */
-/* Store to ring is typically called in the bh of a data ready interrupt handler
- * in the device driver */
-/* Lock always held if their is a chance this may be called */
-/* Only one of these per ring may run concurrently - enforced by drivers */
-static int iio_store_to_sw_ring(struct iio_sw_ring_buffer *ring,
- unsigned char *data)
-{
- int ret = 0;
- unsigned char *temp_ptr, *change_test_ptr;
-
- /* initial store */
- if (unlikely(ring->write_p == NULL)) {
- ring->write_p = ring->data;
- /* Doesn't actually matter if this is out of the set
- * as long as the read pointer is valid before this
- * passes it - guaranteed as set later in this function.
- */
- ring->half_p = ring->data - ring->buf.length*ring->buf.bytes_per_datum/2;
- }
- /* Copy data to where ever the current write pointer says */
- memcpy(ring->write_p, data, ring->buf.bytes_per_datum);
- barrier();
- /* Update the pointer used to get most recent value.
- * Always valid as either points to latest or second latest value.
- * Before this runs it is null and read attempts fail with -EAGAIN.
- */
- barrier();
- /* temp_ptr used to ensure we never have an invalid pointer
- * it may be slightly lagging, but never invalid
- */
- temp_ptr = ring->write_p + ring->buf.bytes_per_datum;
- /* End of ring, back to the beginning */
- if (temp_ptr == ring->data + ring->buf.length*ring->buf.bytes_per_datum)
- temp_ptr = ring->data;
- /* Update the write pointer
- * always valid as long as this is the only function able to write.
- * Care needed with smp systems to ensure more than one ring fill
- * is never scheduled.
- */
- ring->write_p = temp_ptr;
-
- if (ring->read_p == NULL)
- ring->read_p = ring->data;
- /* Buffer full - move the read pointer and create / escalate
- * ring event */
- /* Tricky case - if the read pointer moves before we adjust it.
- * Handle by not pushing if it has moved - may result in occasional
- * unnecessary buffer full events when it wasn't quite true.
- */
- else if (ring->write_p == ring->read_p) {
- change_test_ptr = ring->read_p;
- temp_ptr = change_test_ptr + ring->buf.bytes_per_datum;
- if (temp_ptr
- == ring->data + ring->buf.length*ring->buf.bytes_per_datum) {
- temp_ptr = ring->data;
- }
- /* We are moving pointer on one because the ring is full. Any
- * change to the read pointer will be this or greater.
- */
- if (change_test_ptr == ring->read_p)
- ring->read_p = temp_ptr;
- }
- /* investigate if our event barrier has been passed */
- /* There are definite 'issues' with this and chances of
- * simultaneous read */
- /* Also need to use loop count to ensure this only happens once */
- ring->half_p += ring->buf.bytes_per_datum;
- if (ring->half_p == ring->data + ring->buf.length*ring->buf.bytes_per_datum)
- ring->half_p = ring->data;
- if (ring->half_p == ring->read_p) {
- ring->buf.stufftoread = true;
- wake_up_interruptible(&ring->buf.pollq);
- }
- return ret;
-}
-
-static int iio_read_first_n_sw_rb(struct iio_buffer *r,
- size_t n, char __user *buf)
-{
- struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r);
-
- u8 *initial_read_p, *initial_write_p, *current_read_p, *end_read_p;
- u8 *data;
- int ret, max_copied, bytes_to_rip, dead_offset;
- size_t data_available, buffer_size;
-
- /* A userspace program has probably made an error if it tries to
- * read something that is not a whole number of bpds.
- * Return an error.
- */
- if (n % ring->buf.bytes_per_datum) {
- ret = -EINVAL;
- printk(KERN_INFO "Ring buffer read request not whole number of"
- "samples: Request bytes %zd, Current bytes per datum %d\n",
- n, ring->buf.bytes_per_datum);
- goto error_ret;
- }
-
- buffer_size = ring->buf.bytes_per_datum*ring->buf.length;
-
- /* Limit size to whole of ring buffer */
- bytes_to_rip = min_t(size_t, buffer_size, n);
-
- data = kmalloc(bytes_to_rip, GFP_KERNEL);
- if (data == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
-
- /* build local copy */
- initial_read_p = ring->read_p;
- if (unlikely(initial_read_p == NULL)) { /* No data here as yet */
- ret = 0;
- goto error_free_data_cpy;
- }
-
- initial_write_p = ring->write_p;
-
- /* Need a consistent pair */
- while ((initial_read_p != ring->read_p)
- || (initial_write_p != ring->write_p)) {
- initial_read_p = ring->read_p;
- initial_write_p = ring->write_p;
- }
- if (initial_write_p == initial_read_p) {
- /* No new data available.*/
- ret = 0;
- goto error_free_data_cpy;
- }
-
- if (initial_write_p >= initial_read_p)
- data_available = initial_write_p - initial_read_p;
- else
- data_available = buffer_size - (initial_read_p - initial_write_p);
-
- if (data_available < bytes_to_rip)
- bytes_to_rip = data_available;
-
- if (initial_read_p + bytes_to_rip >= ring->data + buffer_size) {
- max_copied = ring->data + buffer_size - initial_read_p;
- memcpy(data, initial_read_p, max_copied);
- memcpy(data + max_copied, ring->data, bytes_to_rip - max_copied);
- end_read_p = ring->data + bytes_to_rip - max_copied;
- } else {
- memcpy(data, initial_read_p, bytes_to_rip);
- end_read_p = initial_read_p + bytes_to_rip;
- }
-
- /* Now to verify which section was cleanly copied - i.e. how far
- * read pointer has been pushed */
- current_read_p = ring->read_p;
-
- if (initial_read_p <= current_read_p)
- dead_offset = current_read_p - initial_read_p;
- else
- dead_offset = buffer_size - (initial_read_p - current_read_p);
-
- /* possible issue if the initial write has been lapped or indeed
- * the point we were reading to has been passed */
- /* No valid data read.
- * In this case the read pointer is already correct having been
- * pushed further than we would look. */
- if (bytes_to_rip - dead_offset < 0) {
- ret = 0;
- goto error_free_data_cpy;
- }
-
- /* setup the next read position */
- /* Beware, this may fail due to concurrency fun and games.
- * Possible that sufficient fill commands have run to push the read
- * pointer past where we would be after the rip. If this occurs, leave
- * it be.
- */
- /* Tricky - deal with loops */
-
- while (ring->read_p != end_read_p)
- ring->read_p = end_read_p;
-
- ret = bytes_to_rip - dead_offset;
-
- if (copy_to_user(buf, data + dead_offset, ret)) {
- ret = -EFAULT;
- goto error_free_data_cpy;
- }
-
- if (bytes_to_rip >= ring->buf.length*ring->buf.bytes_per_datum/2)
- ring->buf.stufftoread = 0;
-
-error_free_data_cpy:
- kfree(data);
-error_ret:
-
- return ret;
-}
-
-static int iio_store_to_sw_rb(struct iio_buffer *r,
- u8 *data)
-{
- struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r);
- return iio_store_to_sw_ring(ring, data);
-}
-
-static int iio_request_update_sw_rb(struct iio_buffer *r)
-{
- int ret = 0;
- struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r);
-
- r->stufftoread = false;
- if (!ring->update_needed)
- goto error_ret;
- __iio_free_sw_ring_buffer(ring);
- ret = __iio_allocate_sw_ring_buffer(ring, ring->buf.bytes_per_datum,
- ring->buf.length);
-error_ret:
- return ret;
-}
-
-static int iio_get_bytes_per_datum_sw_rb(struct iio_buffer *r)
-{
- struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r);
- return ring->buf.bytes_per_datum;
-}
-
-static int iio_mark_update_needed_sw_rb(struct iio_buffer *r)
-{
- struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r);
- ring->update_needed = true;
- return 0;
-}
-
-static int iio_set_bytes_per_datum_sw_rb(struct iio_buffer *r, size_t bpd)
-{
- if (r->bytes_per_datum != bpd) {
- r->bytes_per_datum = bpd;
- iio_mark_update_needed_sw_rb(r);
- }
- return 0;
-}
-
-static int iio_get_length_sw_rb(struct iio_buffer *r)
-{
- return r->length;
-}
-
-static int iio_set_length_sw_rb(struct iio_buffer *r, int length)
-{
- if (r->length != length) {
- r->length = length;
- iio_mark_update_needed_sw_rb(r);
- }
- return 0;
-}
-
-static IIO_BUFFER_ENABLE_ATTR;
-static IIO_BUFFER_LENGTH_ATTR;
-
-/* Standard set of ring buffer attributes */
-static struct attribute *iio_ring_attributes[] = {
- &dev_attr_length.attr,
- &dev_attr_enable.attr,
- NULL,
-};
-
-static struct attribute_group iio_ring_attribute_group = {
- .attrs = iio_ring_attributes,
- .name = "buffer",
-};
-
-static const struct iio_buffer_access_funcs ring_sw_access_funcs = {
- .store_to = &iio_store_to_sw_rb,
- .read_first_n = &iio_read_first_n_sw_rb,
- .request_update = &iio_request_update_sw_rb,
- .get_bytes_per_datum = &iio_get_bytes_per_datum_sw_rb,
- .set_bytes_per_datum = &iio_set_bytes_per_datum_sw_rb,
- .get_length = &iio_get_length_sw_rb,
- .set_length = &iio_set_length_sw_rb,
-};
-
-struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev)
-{
- struct iio_buffer *buf;
- struct iio_sw_ring_buffer *ring;
-
- ring = kzalloc(sizeof *ring, GFP_KERNEL);
- if (!ring)
- return NULL;
- ring->update_needed = true;
- buf = &ring->buf;
- iio_buffer_init(buf);
- buf->attrs = &iio_ring_attribute_group;
- buf->access = &ring_sw_access_funcs;
-
- return buf;
-}
-EXPORT_SYMBOL(iio_sw_rb_allocate);
-
-void iio_sw_rb_free(struct iio_buffer *r)
-{
- kfree(iio_to_sw_ring(r));
-}
-EXPORT_SYMBOL(iio_sw_rb_free);
-
-MODULE_DESCRIPTION("Industrial I/O software ring buffer");
-MODULE_LICENSE("GPL");
+++ /dev/null
-/* The industrial I/O simple minimally locked ring buffer.
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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.
- *
- * This code is deliberately kept separate from the main industrialio I/O core
- * as it is intended that in the future a number of different software ring
- * buffer implementations will exist with different characteristics to suit
- * different applications.
- *
- * This particular one was designed for a data capture application where it was
- * particularly important that no userspace reads would interrupt the capture
- * process. To this end the ring is not locked during a read.
- *
- * Comments on this buffer design welcomed. It's far from efficient and some of
- * my understanding of the effects of scheduling on this are somewhat limited.
- * Frankly, to my mind, this is the current weak point in the industrial I/O
- * patch set.
- */
-
-#ifndef _IIO_RING_SW_H_
-#define _IIO_RING_SW_H_
-#include <linux/iio/buffer.h>
-
-struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev);
-void iio_sw_rb_free(struct iio_buffer *ring);
-#endif /* _IIO_RING_SW_H_ */
};
#endif /* __LINUX_TSL2563_H */
-