diff options
Diffstat (limited to 'drivers/staging/iio')
47 files changed, 588 insertions, 4548 deletions
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index ca56c75a35fc..dc267175a2b5 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -12,19 +12,6 @@ config IIO_ST_HWMON 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" @@ -32,7 +19,6 @@ source "drivers/staging/iio/cdc/Kconfig" source "drivers/staging/iio/frequency/Kconfig" source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/impedance-analyzer/Kconfig" -source "drivers/staging/iio/imu/Kconfig" source "drivers/staging/iio/light/Kconfig" source "drivers/staging/iio/magnetometer/Kconfig" source "drivers/staging/iio/meter/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index fa6937d92ee3..158e0a017e7b 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -2,8 +2,6 @@ # 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 @@ -20,7 +18,6 @@ obj-y += cdc/ obj-y += frequency/ obj-y += gyro/ obj-y += impedance-analyzer/ -obj-y += imu/ obj-y += light/ obj-y += magnetometer/ obj-y += meter/ diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index 2b54430f2d99..e2e786dc9c7b 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -56,45 +56,17 @@ config ADIS16240 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 diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index 8e7ee0368519..1ed137f1a506 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -20,8 +20,6 @@ obj-$(CONFIG_ADIS16220) += adis16220.o 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 diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/staging/iio/accel/kxsd9.c deleted file mode 100644 index 318331f08d9c..000000000000 --- a/drivers/staging/iio/accel/kxsd9.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * kxsd9.c simple support for the Kionix KXSD9 3D - * accelerometer. - * - * Copyright (c) 2008-2009 Jonathan Cameron <jic23@kernel.org> - * - * 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. - * - * The i2c interface is very similar, so shouldn't be a problem once - * I have a suitable wire made up. - * - * TODO: Support the motion detector - * Uses register address incrementing so could have a - * heavily optimized ring buffer access function. - */ - -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/spi/spi.h> -#include <linux/sysfs.h> -#include <linux/slab.h> -#include <linux/module.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> - -#define KXSD9_REG_X 0x00 -#define KXSD9_REG_Y 0x02 -#define KXSD9_REG_Z 0x04 -#define KXSD9_REG_AUX 0x06 -#define KXSD9_REG_RESET 0x0a -#define KXSD9_REG_CTRL_C 0x0c - -#define KXSD9_FS_MASK 0x03 - -#define KXSD9_REG_CTRL_B 0x0d -#define KXSD9_REG_CTRL_A 0x0e - -#define KXSD9_READ(a) (0x80 | (a)) -#define KXSD9_WRITE(a) (a) - -#define KXSD9_STATE_RX_SIZE 2 -#define KXSD9_STATE_TX_SIZE 2 -/** - * struct kxsd9_state - device related storage - * @buf_lock: protect the rx and tx buffers. - * @us: spi device - * @rx: single rx buffer storage - * @tx: single tx buffer storage - **/ -struct kxsd9_state { - struct mutex buf_lock; - struct spi_device *us; - u8 rx[KXSD9_STATE_RX_SIZE] ____cacheline_aligned; - u8 tx[KXSD9_STATE_TX_SIZE]; -}; - -#define KXSD9_SCALE_2G "0.011978" -#define KXSD9_SCALE_4G "0.023927" -#define KXSD9_SCALE_6G "0.035934" -#define KXSD9_SCALE_8G "0.047853" - -/* reverse order */ -static const int kxsd9_micro_scales[4] = { 47853, 35934, 23927, 11978 }; - -static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro) -{ - int ret, i; - struct kxsd9_state *st = iio_priv(indio_dev); - bool foundit = false; - - for (i = 0; i < 4; i++) - if (micro == kxsd9_micro_scales[i]) { - foundit = true; - break; - } - if (!foundit) - return -EINVAL; - - mutex_lock(&st->buf_lock); - ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C)); - if (ret) - goto error_ret; - st->tx[0] = KXSD9_WRITE(KXSD9_REG_CTRL_C); - st->tx[1] = (ret & ~KXSD9_FS_MASK) | i; - - ret = spi_write(st->us, st->tx, 2); -error_ret: - mutex_unlock(&st->buf_lock); - return ret; -} - -static int kxsd9_read(struct iio_dev *indio_dev, u8 address) -{ - struct spi_message msg; - int ret; - struct kxsd9_state *st = iio_priv(indio_dev); - struct spi_transfer xfers[] = { - { - .bits_per_word = 8, - .len = 1, - .delay_usecs = 200, - .tx_buf = st->tx, - }, { - .bits_per_word = 8, - .len = 2, - .rx_buf = st->rx, - }, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = KXSD9_READ(address); - 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) - return ret; - return (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0); -} - -static IIO_CONST_ATTR(accel_scale_available, - KXSD9_SCALE_2G " " - KXSD9_SCALE_4G " " - KXSD9_SCALE_6G " " - KXSD9_SCALE_8G); - -static struct attribute *kxsd9_attributes[] = { - &iio_const_attr_accel_scale_available.dev_attr.attr, - NULL, -}; - -static int kxsd9_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - int ret = -EINVAL; - - if (mask == IIO_CHAN_INFO_SCALE) { - /* Check no integer component */ - if (val) - return -EINVAL; - ret = kxsd9_write_scale(indio_dev, val2); - } - - return ret; -} - -static int kxsd9_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) -{ - int ret = -EINVAL; - struct kxsd9_state *st = iio_priv(indio_dev); - - switch (mask) { - case IIO_CHAN_INFO_RAW: - ret = kxsd9_read(indio_dev, chan->address); - if (ret < 0) - goto error_ret; - *val = ret; - break; - case IIO_CHAN_INFO_SCALE: - ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C)); - if (ret) - goto error_ret; - *val2 = kxsd9_micro_scales[ret & KXSD9_FS_MASK]; - ret = IIO_VAL_INT_PLUS_MICRO; - break; - } - -error_ret: - return ret; -}; -#define KXSD9_ACCEL_CHAN(axis) \ - { \ - .type = IIO_ACCEL, \ - .modified = 1, \ - .channel2 = IIO_MOD_##axis, \ - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ - IIO_CHAN_INFO_SCALE_SHARED_BIT, \ - .address = KXSD9_REG_##axis, \ - } - -static const struct iio_chan_spec kxsd9_channels[] = { - KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z), - { - .type = IIO_VOLTAGE, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, - .indexed = 1, - .address = KXSD9_REG_AUX, - } -}; - -static const struct attribute_group kxsd9_attribute_group = { - .attrs = kxsd9_attributes, -}; - -static int kxsd9_power_up(struct kxsd9_state *st) -{ - int ret; - - st->tx[0] = 0x0d; - st->tx[1] = 0x40; - ret = spi_write(st->us, st->tx, 2); - if (ret) - return ret; - - st->tx[0] = 0x0c; - st->tx[1] = 0x9b; - return spi_write(st->us, st->tx, 2); -}; - -static const struct iio_info kxsd9_info = { - .read_raw = &kxsd9_read_raw, - .write_raw = &kxsd9_write_raw, - .attrs = &kxsd9_attribute_group, - .driver_module = THIS_MODULE, -}; - -static int kxsd9_probe(struct spi_device *spi) -{ - struct iio_dev *indio_dev; - struct kxsd9_state *st; - int ret = 0; - - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } - st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); - - st->us = spi; - mutex_init(&st->buf_lock); - indio_dev->channels = kxsd9_channels; - indio_dev->num_channels = ARRAY_SIZE(kxsd9_channels); - indio_dev->name = spi_get_device_id(spi)->name; - indio_dev->dev.parent = &spi->dev; - 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); - - return 0; - -error_free_dev: - iio_device_free(indio_dev); -error_ret: - return ret; -} - -static int kxsd9_remove(struct spi_device *spi) -{ - iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); - - return 0; -} - -static const struct spi_device_id kxsd9_id[] = { - {"kxsd9", 0}, - { }, -}; -MODULE_DEVICE_TABLE(spi, kxsd9_id); - -static struct spi_driver kxsd9_driver = { - .driver = { - .name = "kxsd9", - .owner = THIS_MODULE, - }, - .probe = kxsd9_probe, - .remove = kxsd9_remove, - .id_table = kxsd9_id, -}; -module_spi_driver(kxsd9_driver); - -MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); -MODULE_DESCRIPTION("Kionix KXSD9 SPI driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h index 2bac7221837c..0a8ea8270866 100644 --- a/drivers/staging/iio/accel/lis3l02dq.h +++ b/drivers/staging/iio/accel/lis3l02dq.h @@ -185,14 +185,6 @@ int lis3l02dq_probe_trigger(struct iio_dev *indio_dev); 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 diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index 37ed1b8ebb6f..0e019306439c 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -53,7 +53,6 @@ int lis3l02dq_spi_read_reg_8(struct iio_dev *indio_dev, u8 reg_address, u8 *val) { struct lis3l02dq_state *st = iio_priv(indio_dev); - struct spi_message msg; int ret; struct spi_transfer xfer = { .tx_buf = st->tx, @@ -66,9 +65,7 @@ int lis3l02dq_spi_read_reg_8(struct iio_dev *indio_dev, st->tx[0] = LIS3L02DQ_READ_REG(reg_address); st->tx[1] = 0; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, &xfer, 1); *val = st->rx[1]; mutex_unlock(&st->buf_lock); @@ -109,7 +106,6 @@ static int lis3l02dq_spi_write_reg_s16(struct iio_dev *indio_dev, s16 value) { int ret; - struct spi_message msg; struct lis3l02dq_state *st = iio_priv(indio_dev); struct spi_transfer xfers[] = { { .tx_buf = st->tx, @@ -129,10 +125,7 @@ static int lis3l02dq_spi_write_reg_s16(struct iio_dev *indio_dev, st->tx[2] = LIS3L02DQ_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); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); mutex_unlock(&st->buf_lock); return ret; @@ -143,8 +136,6 @@ static int lis3l02dq_read_reg_s16(struct iio_dev *indio_dev, int *val) { struct lis3l02dq_state *st = iio_priv(indio_dev); - - struct spi_message msg; int ret; s16 tempval; struct spi_transfer xfers[] = { { @@ -167,10 +158,7 @@ static int lis3l02dq_read_reg_s16(struct iio_dev *indio_dev, st->tx[2] = LIS3L02DQ_READ_REG(lower_reg_address + 1); st->tx[3] = 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); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 16 bit register"); goto error_ret; diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index bc38651c315e..e676403ea3ea 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -7,7 +7,6 @@ #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> @@ -141,11 +140,8 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p) char *data; data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (data == NULL) { - dev_err(indio_dev->dev.parent, - "memory alloc failed in buffer bh"); + if (data == NULL) goto done; - } if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) len = lis3l02dq_get_buffer_element(indio_dev, data); @@ -318,7 +314,7 @@ void lis3l02dq_remove_trigger(struct iio_dev *indio_dev) 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) @@ -401,7 +397,7 @@ int lis3l02dq_configure_buffer(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; @@ -427,6 +423,6 @@ int lis3l02dq_configure_buffer(struct iio_dev *indio_dev) return 0; error_iio_sw_rb_free: - lis3l02dq_free_buf(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); return ret; } diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index 414d3cad55a7..14683f583ccf 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -90,7 +90,6 @@ int sca3000_read_data_short(struct sca3000_state *st, uint8_t reg_address_high, int len) { - struct spi_message msg; struct spi_transfer xfer[2] = { { .len = 1, @@ -101,11 +100,8 @@ int sca3000_read_data_short(struct sca3000_state *st, } }; st->tx[0] = SCA3000_READ_REG(reg_address_high); - spi_message_init(&msg); - spi_message_add_tail(&xfer[0], &msg); - spi_message_add_tail(&xfer[1], &msg); - return spi_sync(st->us, &msg); + return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); } /** @@ -133,7 +129,6 @@ static int sca3000_reg_lock_on(struct sca3000_state *st) **/ static int __sca3000_unlock_reg_lock(struct sca3000_state *st) { - struct spi_message msg; struct spi_transfer xfer[3] = { { .len = 2, @@ -154,12 +149,8 @@ static int __sca3000_unlock_reg_lock(struct sca3000_state *st) st->tx[3] = 0x50; st->tx[4] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); st->tx[5] = 0xA0; - spi_message_init(&msg); - spi_message_add_tail(&xfer[0], &msg); - spi_message_add_tail(&xfer[1], &msg); - spi_message_add_tail(&xfer[2], &msg); - return spi_sync(st->us, &msg); + return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); } /** diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index cbec2f1665e5..3e5e860aa38e 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -39,7 +39,6 @@ static int sca3000_read_data(struct sca3000_state *st, int len) { int ret; - struct spi_message msg; struct spi_transfer xfer[2] = { { .len = 1, @@ -55,10 +54,7 @@ static int sca3000_read_data(struct sca3000_state *st, } xfer[1].rx_buf = *rx_p; st->tx[0] = SCA3000_READ_REG(reg_address_high); - spi_message_init(&msg); - spi_message_add_tail(&xfer[0], &msg); - spi_message_add_tail(&xfer[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); if (ret) { dev_err(get_device(&st->us->dev), "problem reading register"); goto error_free_rx; diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index fb8c239b0c88..7b2a01d64f5e 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -119,12 +119,12 @@ config LPC32XX_ADC 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 diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index fa81a491e790..1f190c1b12a6 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -199,12 +199,8 @@ static int __ad7280_read32(struct spi_device *spi, unsigned *val) .rx_buf = &rx_buf, .len = 4, }; - struct spi_message m; - spi_message_init(&m); - spi_message_add_tail(&t, &m); - - ret = spi_sync(spi, &m); + ret = spi_sync_transfer(spi, &t, 1); if (ret) return ret; diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 3d562da039db..55a459b61907 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -33,6 +33,8 @@ #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> @@ -60,7 +62,39 @@ #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", @@ -76,9 +110,26 @@ static const char * const mxs_lradc_irq_name[] = { "mxs-lradc-button1", }; -struct mxs_lradc_chan { - uint8_t slot; - uint8_t flags; +struct mxs_lradc_of_config { + const int irq_count; + const char * const *irq_name; +}; + +static const struct mxs_lradc_of_config 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 { @@ -91,24 +142,70 @@ struct mxs_lradc { struct mutex lock; - uint8_t enable; - 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) @@ -140,6 +237,7 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, { struct mxs_lradc *lradc = iio_priv(iio_dev); int ret; + unsigned long mask; if (m != IIO_CHAN_INFO_RAW) return -EINVAL; @@ -148,6 +246,12 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, 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 @@ -169,7 +273,11 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, 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. */ @@ -203,6 +311,269 @@ static const struct iio_info mxs_lradc_iio_info = { }; /* + * 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) @@ -210,14 +581,24 @@ 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()); @@ -313,8 +694,10 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio) { 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); @@ -346,17 +729,20 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio) 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, @@ -391,9 +777,33 @@ static int mxs_lradc_buffer_postdisable(struct iio_dev *iio) 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 = { @@ -442,15 +852,29 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { 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); @@ -467,12 +891,25 @@ static void mxs_lradc_hw_stop(struct mxs_lradc *lradc) 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; @@ -494,8 +931,23 @@ static int mxs_lradc_probe(struct platform_device *pdev) 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; @@ -504,7 +956,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) 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; } @@ -531,11 +983,16 @@ static int mxs_lradc_probe(struct platform_device *pdev) 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. */ @@ -543,6 +1000,8 @@ static int mxs_lradc_probe(struct platform_device *pdev) return 0; +err_ts: + mxs_lradc_ts_unregister(lradc); err_dev: mxs_lradc_trigger_remove(iio); err_trig: @@ -557,6 +1016,8 @@ static int mxs_lradc_remove(struct platform_device *pdev) 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); @@ -567,12 +1028,6 @@ static int mxs_lradc_remove(struct platform_device *pdev) 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, diff --git a/drivers/staging/iio/frequency/ad5930.c b/drivers/staging/iio/frequency/ad5930.c index 23777be38b18..69e90e9e60ea 100644 --- a/drivers/staging/iio/frequency/ad5930.c +++ b/drivers/staging/iio/frequency/ad5930.c @@ -44,7 +44,6 @@ static ssize_t ad5930_set_parameter(struct device *dev, const char *buf, size_t len) { - struct spi_message msg; struct spi_transfer xfer; int ret; struct ad5903_config *config = (struct ad5903_config *)buf; @@ -64,9 +63,7 @@ static ssize_t ad5930_set_parameter(struct device *dev, xfer.tx_buf = config; mutex_lock(&st->lock); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; error_ret: diff --git a/drivers/staging/iio/frequency/ad9850.c b/drivers/staging/iio/frequency/ad9850.c index 104f7a4905a3..01a8a93031f5 100644 --- a/drivers/staging/iio/frequency/ad9850.c +++ b/drivers/staging/iio/frequency/ad9850.c @@ -39,7 +39,6 @@ static ssize_t ad9850_set_parameter(struct device *dev, const char *buf, size_t len) { - struct spi_message msg; struct spi_transfer xfer; int ret; struct ad9850_config *config = (struct ad9850_config *)buf; @@ -50,9 +49,7 @@ static ssize_t ad9850_set_parameter(struct device *dev, xfer.tx_buf = config; mutex_lock(&st->lock); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; error_ret: diff --git a/drivers/staging/iio/frequency/ad9852.c b/drivers/staging/iio/frequency/ad9852.c index 17ac825b3d26..1344031232bc 100644 --- a/drivers/staging/iio/frequency/ad9852.c +++ b/drivers/staging/iio/frequency/ad9852.c @@ -183,7 +183,6 @@ static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9852_set_parameter, 0); static void ad9852_init(struct ad9852_state *st) { - struct spi_message msg; struct spi_transfer xfer; int ret; u8 config[5]; @@ -199,9 +198,7 @@ static void ad9852_init(struct ad9852_state *st) xfer.len = 5; xfer.tx_buf = &config; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index 87979a0d03a9..836066287192 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig @@ -10,13 +10,6 @@ config ADIS16060 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 @@ -36,14 +29,4 @@ config ADIS16260 This driver can also be built as a module. If so, the module will be called adis16260. -config ADXRS450 - tristate "Analog Devices ADXRS450/3 Digital Output Gyroscope SPI driver" - depends on SPI - help - Say yes here to build support for Analog Devices ADXRS450 and ADXRS453 - programmable digital output gyroscope. - - This driver can also be built as a module. If so, the module - will be called adxrs450. - endmenu diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile index 1303569e5c8a..98e650061a3a 100644 --- a/drivers/staging/iio/gyro/Makefile +++ b/drivers/staging/iio/gyro/Makefile @@ -5,17 +5,8 @@ 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 diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c deleted file mode 100644 index 41d7350d030f..000000000000 --- a/drivers/staging/iio/gyro/adis16080_core.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * ADIS16080/100 Yaw Rate Gyroscope with SPI driver - * - * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ -#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/module.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> - -#define ADIS16080_DIN_GYRO (0 << 10) /* Gyroscope output */ -#define ADIS16080_DIN_TEMP (1 << 10) /* Temperature output */ -#define ADIS16080_DIN_AIN1 (2 << 10) -#define ADIS16080_DIN_AIN2 (3 << 10) - -/* - * 1: Write contents on DIN to control register. - * 0: No changes to control register. - */ - -#define ADIS16080_DIN_WRITE (1 << 15) - -/** - * struct adis16080_state - device instance specific data - * @us: actual spi_device to write data - * @buf: transmit or receive buffer - * @buf_lock: mutex to protect tx and rx - **/ -struct adis16080_state { - struct spi_device *us; - struct mutex buf_lock; - - u8 buf[2] ____cacheline_aligned; -}; - -static int adis16080_spi_write(struct iio_dev *indio_dev, - u16 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) -{ - int ret; - struct adis16080_state *st = iio_priv(indio_dev); - - mutex_lock(&st->buf_lock); - - ret = spi_read(st->us, st->buf, 2); - - if (ret == 0) - *val = sign_extend32(((st->buf[0] & 0xF) << 8) | st->buf[1], 11); - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int adis16080_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - int ret = -EINVAL; - u16 ut = 0; - /* Take the iio_dev status lock */ - - 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; - break; - } - mutex_unlock(&indio_dev->mlock); - - return ret; -} - -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, - .address = ADIS16080_DIN_GYRO, - }, { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, - .address = ADIS16080_DIN_AIN1, - }, { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 1, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, - .address = ADIS16080_DIN_AIN2, - }, { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, - .address = ADIS16080_DIN_TEMP, - } -}; - -static const struct iio_info adis16080_info = { - .read_raw = &adis16080_read_raw, - .driver_module = THIS_MODULE, -}; - -static int adis16080_probe(struct spi_device *spi) -{ - int ret; - struct adis16080_state *st; - struct iio_dev *indio_dev; - - /* setup the industrialio driver allocated elements */ - 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); - - /* Allocate the comms buffers */ - st->us = spi; - mutex_init(&st->buf_lock); - - indio_dev->name = spi->dev.driver->name; - indio_dev->channels = adis16080_channels; - indio_dev->num_channels = ARRAY_SIZE(adis16080_channels); - indio_dev->dev.parent = &spi->dev; - indio_dev->info = &adis16080_info; - indio_dev->modes = INDIO_DIRECT_MODE; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_free_dev; - return 0; - -error_free_dev: - iio_device_free(indio_dev); -error_ret: - return ret; -} - -/* fixme, confirm ordering in this function */ -static int adis16080_remove(struct spi_device *spi) -{ - iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); - - return 0; -} - -static struct spi_driver adis16080_driver = { - .driver = { - .name = "adis16080", - .owner = THIS_MODULE, - }, - .probe = adis16080_probe, - .remove = adis16080_remove, -}; -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"); diff --git a/drivers/staging/iio/gyro/adxrs450.h b/drivers/staging/iio/gyro/adxrs450.h deleted file mode 100644 index f8cf21f02943..000000000000 --- a/drivers/staging/iio/gyro/adxrs450.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef SPI_ADXRS450_H_ -#define SPI_ADXRS450_H_ - -#define ADXRS450_STARTUP_DELAY 50 /* ms */ - -/* The MSB for the spi commands */ -#define ADXRS450_SENSOR_DATA 0x20 -#define ADXRS450_WRITE_DATA 0x40 -#define ADXRS450_READ_DATA 0x80 - -#define ADXRS450_RATE1 0x00 /* Rate Registers */ -#define ADXRS450_TEMP1 0x02 /* Temperature Registers */ -#define ADXRS450_LOCST1 0x04 /* Low CST Memory Registers */ -#define ADXRS450_HICST1 0x06 /* High CST Memory Registers */ -#define ADXRS450_QUAD1 0x08 /* Quad Memory Registers */ -#define ADXRS450_FAULT1 0x0A /* Fault Registers */ -#define ADXRS450_PID1 0x0C /* Part ID Register 1 */ -#define ADXRS450_SNH 0x0E /* Serial Number Registers, 4 bytes */ -#define ADXRS450_SNL 0x10 -#define ADXRS450_DNC1 0x12 /* Dynamic Null Correction Registers */ -/* Check bits */ -#define ADXRS450_P 0x01 -#define ADXRS450_CHK 0x02 -#define ADXRS450_CST 0x04 -#define ADXRS450_PWR 0x08 -#define ADXRS450_POR 0x10 -#define ADXRS450_NVM 0x20 -#define ADXRS450_Q 0x40 -#define ADXRS450_PLL 0x80 -#define ADXRS450_UV 0x100 -#define ADXRS450_OV 0x200 -#define ADXRS450_AMP 0x400 -#define ADXRS450_FAIL 0x800 - -#define ADXRS450_WRERR_MASK (0x7 << 29) - -#define ADXRS450_MAX_RX 4 -#define ADXRS450_MAX_TX 4 - -#define ADXRS450_GET_ST(a) ((a >> 26) & 0x3) - -enum { - ID_ADXRS450, - ID_ADXRS453, -}; - -/** - * struct adxrs450_state - device instance specific data - * @us: actual spi_device - * @buf_lock: mutex to protect tx and rx - * @tx: transmit buffer - * @rx: receive buffer - **/ -struct adxrs450_state { - struct spi_device *us; - struct mutex buf_lock; - u8 tx[ADXRS450_MAX_RX] ____cacheline_aligned; - u8 rx[ADXRS450_MAX_TX]; - -}; - -#endif /* SPI_ADXRS450_H_ */ diff --git a/drivers/staging/iio/gyro/adxrs450_core.c b/drivers/staging/iio/gyro/adxrs450_core.c deleted file mode 100644 index f0ce81da8aca..000000000000 --- a/drivers/staging/iio/gyro/adxrs450_core.c +++ /dev/null @@ -1,440 +0,0 @@ -/* - * ADXRS450/ADXRS453 Digital Output Gyroscope Driver - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#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 "adxrs450.h" - -/** - * adxrs450_spi_read_reg_16() - read 2 bytes from a register pair - * @dev: device associated with child of actual iio_dev - * @reg_address: the address of the lower of the two registers,which should be an even address, - * Second register's address is reg_address + 1. - * @val: somewhere to pass back the value read - **/ -static int adxrs450_spi_read_reg_16(struct iio_dev *indio_dev, - u8 reg_address, - u16 *val) -{ - struct adxrs450_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADXRS450_READ_DATA | (reg_address >> 7); - st->tx[1] = reg_address << 1; - st->tx[2] = 0; - st->tx[3] = 0; - - if (!(hweight32(be32_to_cpu(*(u32 *)st->tx)) & 1)) - st->tx[3] |= ADXRS450_P; - - ret = spi_write(st->us, st->tx, 4); - if (ret) { - dev_err(&st->us->dev, "problem while reading 16 bit register 0x%02x\n", - reg_address); - goto error_ret; - } - ret = spi_read(st->us, st->rx, 4); - if (ret) { - dev_err(&st->us->dev, "problem while reading 16 bit register 0x%02x\n", - reg_address); - goto error_ret; - } - - *val = (be32_to_cpu(*(u32 *)st->rx) >> 5) & 0xFFFF; - -error_ret: - mutex_unlock(&st->buf_lock); - return ret; -} - -/** - * adxrs450_spi_write_reg_16() - write 2 bytes data to a register pair - * @dev: device associated with child of actual actual iio_dev - * @reg_address: the address of the lower of the two registers,which should be an even address, - * Second register's address is reg_address + 1. - * @val: value to be written. - **/ -static int adxrs450_spi_write_reg_16(struct iio_dev *indio_dev, - u8 reg_address, - u16 val) -{ - struct adxrs450_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADXRS450_WRITE_DATA | reg_address >> 7; - st->tx[1] = reg_address << 1 | val >> 15; - st->tx[2] = val >> 7; - st->tx[3] = val << 1; - - if (!(hweight32(be32_to_cpu(*(u32 *)st->tx)) & 1)) - st->tx[3] |= ADXRS450_P; - - ret = spi_write(st->us, st->tx, 4); - if (ret) - dev_err(&st->us->dev, "problem while writing 16 bit register 0x%02x\n", - reg_address); - msleep(1); /* enforce sequential transfer delay 0.1ms */ - mutex_unlock(&st->buf_lock); - return ret; -} - -/** - * adxrs450_spi_sensor_data() - read 2 bytes sensor data - * @dev: device associated with child of actual iio_dev - * @val: somewhere to pass back the value read - **/ -static int adxrs450_spi_sensor_data(struct iio_dev *indio_dev, s16 *val) -{ - struct adxrs450_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADXRS450_SENSOR_DATA; - st->tx[1] = 0; - st->tx[2] = 0; - st->tx[3] = 0; - - ret = spi_write(st->us, st->tx, 4); - if (ret) { - dev_err(&st->us->dev, "Problem while reading sensor data\n"); - goto error_ret; - } - - ret = spi_read(st->us, st->rx, 4); - if (ret) { - dev_err(&st->us->dev, "Problem while reading sensor data\n"); - goto error_ret; - } - - *val = (be32_to_cpu(*(u32 *)st->rx) >> 10) & 0xFFFF; - -error_ret: - mutex_unlock(&st->buf_lock); - return ret; -} - -/** - * adxrs450_spi_initial() - use for initializing procedure. - * @st: device instance specific data - * @val: somewhere to pass back the value read - **/ -static int adxrs450_spi_initial(struct adxrs450_state *st, - u32 *val, char chk) -{ - struct spi_message msg; - int ret; - struct spi_transfer xfers = { - .tx_buf = st->tx, - .rx_buf = st->rx, - .bits_per_word = 8, - .len = 4, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADXRS450_SENSOR_DATA; - st->tx[1] = 0; - st->tx[2] = 0; - st->tx[3] = 0; - if (chk) - st->tx[3] |= (ADXRS450_CHK | ADXRS450_P); - spi_message_init(&msg); - spi_message_add_tail(&xfers, &msg); - ret = spi_sync(st->us, &msg); - if (ret) { - dev_err(&st->us->dev, "Problem while reading initializing data\n"); - goto error_ret; - } - - *val = be32_to_cpu(*(u32 *)st->rx); - -error_ret: - mutex_unlock(&st->buf_lock); - return ret; -} - -/* Recommended Startup Sequence by spec */ -static int adxrs450_initial_setup(struct iio_dev *indio_dev) -{ - u32 t; - u16 data; - int ret; - struct adxrs450_state *st = iio_priv(indio_dev); - - msleep(ADXRS450_STARTUP_DELAY*2); - ret = adxrs450_spi_initial(st, &t, 1); - if (ret) - return ret; - if (t != 0x01) - dev_warn(&st->us->dev, "The initial power on response " - "is not correct! Restart without reset?\n"); - - msleep(ADXRS450_STARTUP_DELAY); - ret = adxrs450_spi_initial(st, &t, 0); - if (ret) - return ret; - - msleep(ADXRS450_STARTUP_DELAY); - ret = adxrs450_spi_initial(st, &t, 0); - if (ret) - return ret; - if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) { - dev_err(&st->us->dev, "The second response is not correct!\n"); - return -EIO; - - } - ret = adxrs450_spi_initial(st, &t, 0); - if (ret) - return ret; - if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) { - dev_err(&st->us->dev, "The third response is not correct!\n"); - return -EIO; - - } - ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_FAULT1, &data); - if (ret) - return ret; - if (data & 0x0fff) { - dev_err(&st->us->dev, "The device is not in normal status!\n"); - return -EINVAL; - } - ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_PID1, &data); - if (ret) - return ret; - dev_info(&st->us->dev, "The Part ID is 0x%x\n", data); - - ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_SNL, &data); - if (ret) - return ret; - t = data; - ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_SNH, &data); - if (ret) - return ret; - t |= data << 16; - dev_info(&st->us->dev, "The Serial Number is 0x%x\n", t); - - return 0; -} - -static int adxrs450_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - int ret; - switch (mask) { - case IIO_CHAN_INFO_CALIBBIAS: - ret = adxrs450_spi_write_reg_16(indio_dev, - ADXRS450_DNC1, - val & 0x3FF); - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -static int adxrs450_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - int ret; - s16 t; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - switch (chan->type) { - case IIO_ANGL_VEL: - ret = adxrs450_spi_sensor_data(indio_dev, &t); - if (ret) - break; - *val = t; - ret = IIO_VAL_INT; - break; - case IIO_TEMP: - ret = adxrs450_spi_read_reg_16(indio_dev, - ADXRS450_TEMP1, &t); - if (ret) - break; - *val = (t >> 6) + 225; - ret = IIO_VAL_INT; - break; - default: - ret = -EINVAL; - break; - } - break; - case IIO_CHAN_INFO_SCALE: - switch (chan->type) { - case IIO_ANGL_VEL: - *val = 0; - *val2 = 218166; - return IIO_VAL_INT_PLUS_NANO; - case IIO_TEMP: - *val = 200; - *val2 = 0; - return IIO_VAL_INT; - default: - return -EINVAL; - } - break; - case IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW: - ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_QUAD1, &t); - if (ret) - break; - *val = t; - ret = IIO_VAL_INT; - break; - case IIO_CHAN_INFO_CALIBBIAS: - ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_DNC1, &t); - if (ret) - break; - *val = t; - ret = IIO_VAL_INT; - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static const struct iio_chan_spec adxrs450_channels[2][2] = { - [ID_ADXRS450] = { - { - .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_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - }, { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - } - }, - [ID_ADXRS453] = { - { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | - IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT, - }, { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - } - }, -}; - -static const struct iio_info adxrs450_info = { - .driver_module = THIS_MODULE, - .read_raw = &adxrs450_read_raw, - .write_raw = &adxrs450_write_raw, -}; - -static int adxrs450_probe(struct spi_device *spi) -{ - int ret; - struct adxrs450_state *st; - struct iio_dev *indio_dev; - - /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } - st = iio_priv(indio_dev); - st->us = spi; - mutex_init(&st->buf_lock); - /* This is only used for removal purposes */ - spi_set_drvdata(spi, indio_dev); - - indio_dev->dev.parent = &spi->dev; - indio_dev->info = &adxrs450_info; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = - adxrs450_channels[spi_get_device_id(spi)->driver_data]; - indio_dev->num_channels = ARRAY_SIZE(adxrs450_channels); - indio_dev->name = spi->dev.driver->name; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_free_dev; - - /* Get the device into a sane initial state */ - ret = adxrs450_initial_setup(indio_dev); - if (ret) - goto error_initial; - return 0; -error_initial: - iio_device_unregister(indio_dev); -error_free_dev: - iio_device_free(indio_dev); - -error_ret: - return ret; -} - -static int adxrs450_remove(struct spi_device *spi) -{ - iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); - - return 0; -} - -static const struct spi_device_id adxrs450_id[] = { - {"adxrs450", ID_ADXRS450}, - {"adxrs453", ID_ADXRS453}, - {} -}; -MODULE_DEVICE_TABLE(spi, adxrs450_id); - -static struct spi_driver adxrs450_driver = { - .driver = { - .name = "adxrs450", - .owner = THIS_MODULE, - }, - .probe = adxrs450_probe, - .remove = adxrs450_remove, - .id_table = adxrs450_id, -}; -module_spi_driver(adxrs450_driver); - -MODULE_AUTHOR("Cliff Cai <cliff.cai@xxxxxxxxxx>"); -MODULE_DESCRIPTION("Analog Devices ADXRS450/ADXRS453 Gyroscope SPI driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/iio_hwmon.c b/drivers/staging/iio/iio_hwmon.c index c7a5f97576c7..93af756ba48c 100644 --- a/drivers/staging/iio/iio_hwmon.c +++ b/drivers/staging/iio/iio_hwmon.c @@ -55,63 +55,58 @@ static ssize_t iio_hwmon_read_val(struct device *dev, return sprintf(buf, "%d\n", result); } -static void iio_hwmon_free_attrs(struct iio_hwmon_state *st) +static ssize_t show_name(struct device *dev, struct device_attribute *attr, + char *buf) { - int i; - struct sensor_device_attribute *a; - for (i = 0; i < st->num_channels; i++) - if (st->attrs[i]) { - a = to_sensor_dev_attr( - container_of(st->attrs[i], - struct device_attribute, - attr)); - kfree(a); - } + return sprintf(buf, "iio_hwmon\n"); } +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + static int iio_hwmon_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct iio_hwmon_state *st; struct sensor_device_attribute *a; int ret, i; int in_i = 1, temp_i = 1, curr_i = 1; enum iio_chan_type type; + struct iio_channel *channels; - st = kzalloc(sizeof(*st), GFP_KERNEL); - if (st == NULL) { - ret = -ENOMEM; - goto error_ret; - } + channels = iio_channel_get_all(dev); + if (IS_ERR(channels)) + return PTR_ERR(channels); - st->channels = iio_channel_get_all(dev_name(&pdev->dev)); - if (IS_ERR(st->channels)) { - ret = PTR_ERR(st->channels); - goto error_free_state; - } + st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); + if (st == NULL) + return -ENOMEM; + + st->channels = channels; /* count how many attributes we have */ while (st->channels[st->num_channels].indio_dev) st->num_channels++; - st->attrs = kzalloc(sizeof(st->attrs) * (st->num_channels + 1), - GFP_KERNEL); + st->attrs = devm_kzalloc(dev, + sizeof(*st->attrs) * (st->num_channels + 2), + GFP_KERNEL); if (st->attrs == NULL) { ret = -ENOMEM; goto error_release_channels; } + for (i = 0; i < st->num_channels; i++) { - a = kzalloc(sizeof(*a), GFP_KERNEL); + a = devm_kzalloc(dev, sizeof(*a), GFP_KERNEL); if (a == NULL) { ret = -ENOMEM; - goto error_free_attrs; + goto error_release_channels; } sysfs_attr_init(&a->dev_attr.attr); ret = iio_get_channel_type(&st->channels[i], &type); - if (ret < 0) { - kfree(a); - goto error_free_attrs; - } + if (ret < 0) + goto error_release_channels; + switch (type) { case IIO_VOLTAGE: a->dev_attr.attr.name = kasprintf(GFP_KERNEL, @@ -130,27 +125,25 @@ static int iio_hwmon_probe(struct platform_device *pdev) break; default: ret = -EINVAL; - kfree(a); - goto error_free_attrs; + goto error_release_channels; } if (a->dev_attr.attr.name == NULL) { - kfree(a); ret = -ENOMEM; - goto error_free_attrs; + goto error_release_channels; } a->dev_attr.show = iio_hwmon_read_val; a->dev_attr.attr.mode = S_IRUGO; a->index = i; st->attrs[i] = &a->dev_attr.attr; } - + st->attrs[st->num_channels] = &dev_attr_name.attr; st->attr_group.attrs = st->attrs; platform_set_drvdata(pdev, st); - ret = sysfs_create_group(&pdev->dev.kobj, &st->attr_group); + ret = sysfs_create_group(&dev->kobj, &st->attr_group); if (ret < 0) - goto error_free_attrs; + goto error_release_channels; - st->hwmon_dev = hwmon_device_register(&pdev->dev); + st->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(st->hwmon_dev)) { ret = PTR_ERR(st->hwmon_dev); goto error_remove_group; @@ -158,15 +151,9 @@ static int iio_hwmon_probe(struct platform_device *pdev) return 0; error_remove_group: - sysfs_remove_group(&pdev->dev.kobj, &st->attr_group); -error_free_attrs: - iio_hwmon_free_attrs(st); - kfree(st->attrs); + sysfs_remove_group(&dev->kobj, &st->attr_group); error_release_channels: iio_channel_release_all(st->channels); -error_free_state: - kfree(st); -error_ret: return ret; } @@ -176,17 +163,21 @@ static int iio_hwmon_remove(struct platform_device *pdev) hwmon_device_unregister(st->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &st->attr_group); - iio_hwmon_free_attrs(st); - kfree(st->attrs); iio_channel_release_all(st->channels); return 0; } +static struct of_device_id iio_hwmon_of_match[] = { + { .compatible = "iio-hwmon", }, + { } +}; + static struct platform_driver __refdata iio_hwmon_driver = { .driver = { .name = "iio_hwmon", .owner = THIS_MODULE, + .of_match_table = iio_hwmon_of_match, }, .probe = iio_hwmon_probe, .remove = iio_hwmon_remove, diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c index a865adf81938..aee76c710a3b 100644 --- a/drivers/staging/iio/iio_simple_dummy.c +++ b/drivers/staging/iio/iio_simple_dummy.c @@ -54,7 +54,7 @@ struct iio_dummy_accel_calibscale { static const struct iio_dummy_accel_calibscale dummy_scales[] = { { 0, 100, 0x8 }, /* 0.000100 */ { 0, 133, 0x7 }, /* 0.000133 */ - { 733, 13, 0x9 }, /* 733.00013 */ + { 733, 13, 0x9 }, /* 733.000013 */ }; /* @@ -284,7 +284,7 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev, /** * iio_dummy_write_raw() - data write function. * @indio_dev: the struct iio_dev associated with this device instance - * @chan: the channel whose data is to be read + * @chan: the channel whose data is to be written * @val: first element of value to set (typically INT) * @val2: second element of value to set (typically MICRO) * @mask: what we actually want to write. 0 is the channel, everything else diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c index dee16f0e7570..72f400c3cbcb 100644 --- a/drivers/staging/iio/iio_simple_dummy_buffer.c +++ b/drivers/staging/iio/iio_simple_dummy_buffer.c @@ -155,7 +155,7 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev, * occurs, this function is run. Typically this grabs data * from the device. * - * NULL for the top half. This is normally implemented only if we + * NULL for the bottom half. This is normally implemented only if we * either want to ping a capture now pin (no sleeping) or grab * a timestamp as close as possible to a data ready trigger firing. * diff --git a/drivers/staging/iio/impedance-analyzer/Kconfig b/drivers/staging/iio/impedance-analyzer/Kconfig index ad0ff765e4b2..dd97b6bb3fd0 100644 --- a/drivers/staging/iio/impedance-analyzer/Kconfig +++ b/drivers/staging/iio/impedance-analyzer/Kconfig @@ -7,7 +7,7 @@ config AD5933 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. diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 779243d24dec..440e2261e8cb 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -22,7 +22,7 @@ #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" @@ -630,7 +630,7 @@ static const struct iio_buffer_setup_ops ad5933_ring_setup_ops = { 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; @@ -774,7 +774,7 @@ static int ad5933_probe(struct i2c_client *client, 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); @@ -794,7 +794,7 @@ static int ad5933_remove(struct i2c_client *client) 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); diff --git a/drivers/staging/iio/imu/Kconfig b/drivers/staging/iio/imu/Kconfig deleted file mode 100644 index 2c2f47de2630..000000000000 --- a/drivers/staging/iio/imu/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# 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 diff --git a/drivers/staging/iio/imu/Makefile b/drivers/staging/iio/imu/Makefile deleted file mode 100644 index 3400a13d1522..000000000000 --- a/drivers/staging/iio/imu/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# 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 diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h deleted file mode 100644 index 7a105e966464..000000000000 --- a/drivers/staging/iio/imu/adis16400.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * adis16400.h support Analog Devices ADIS16400 - * 3d 18g accelerometers, - * 3d gyroscopes, - * 3d 2.5gauss magnetometers via SPI - * - * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> - * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> - * - * Loosely based upon lis3l02dq.h - * - * 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. - */ - -#ifndef SPI_ADIS16400_H_ -#define SPI_ADIS16400_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 ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */ -#define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */ -#define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */ -#define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */ -#define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */ -#define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */ -#define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */ -#define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */ -#define ADIS16400_TEMP_OUT 0x16 /* Temperature output */ -#define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */ - -#define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */ -#define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */ -#define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */ - -#define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */ -#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */ -#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */ - -/* 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_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */ -#define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */ -#define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */ -#define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */ -#define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */ -#define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */ -#define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */ -#define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */ -#define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */ -#define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */ - -#define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */ -#define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */ -#define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */ -#define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */ -#define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */ -#define ADIS16400_DIAG_STAT 0x3C /* System status */ - -/* Alarm functions */ -#define ADIS16400_GLOB_CMD 0x3E /* System command */ -#define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */ -#define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */ -#define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */ -#define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */ -#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */ -#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */ - -#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */ - -#define ADIS16400_ERROR_ACTIVE (1<<14) -#define ADIS16400_NEW_DATA (1<<14) - -/* MSC_CTRL */ -#define ADIS16400_MSC_CTRL_MEM_TEST (1<<11) -#define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10) -#define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9) -#define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8) -#define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7) -#define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6) -#define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2) -#define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1) -#define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0) - -/* SMPL_PRD */ -#define ADIS16400_SMPL_PRD_TIME_BASE (1<<7) -#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) - -/* GLOB_CMD */ -#define ADIS16400_GLOB_CMD_SW_RESET (1<<7) -#define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4) -#define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3) -#define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2) -#define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1) -#define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0) - -/* SLP_CNT */ -#define ADIS16400_SLP_CNT_POWER_OFF (1<<8) - -#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) - -struct adis16400_chip_info { - const struct iio_chan_spec *channels; - const int num_channels; - const long flags; - unsigned int gyro_scale_micro; - 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); -}; - -/** - * 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 - **/ -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; -}; - -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 - -#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); - -#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) -{ -} - -#endif /* CONFIG_IIO_BUFFER */ -#endif /* SPI_ADIS16400_H_ */ diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c deleted file mode 100644 index 9c8f5ab7e13b..000000000000 --- a/drivers/staging/iio/imu/adis16400_core.c +++ /dev/null @@ -1,1320 +0,0 @@ -/* - * 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"); diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c deleted file mode 100644 index d46c1e38cf7b..000000000000 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ /dev/null @@ -1,204 +0,0 @@ -#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; -} diff --git a/drivers/staging/iio/imu/adis16400_trigger.c b/drivers/staging/iio/imu/adis16400_trigger.c deleted file mode 100644 index 42a678e92fc6..000000000000 --- a/drivers/staging/iio/imu/adis16400_trigger.c +++ /dev/null @@ -1,74 +0,0 @@ -#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); -} diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig index 4bed30eac3ed..ca8d6e66c899 100644 --- a/drivers/staging/iio/light/Kconfig +++ b/drivers/staging/iio/light/Kconfig @@ -25,16 +25,6 @@ config SENSORS_ISL29028 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 diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile index 141af1eb164c..9960fdf7c15b 100644 --- a/drivers/staging/iio/light/Makefile +++ b/drivers/staging/iio/light/Makefile @@ -2,7 +2,6 @@ # 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 diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c deleted file mode 100644 index 1a9adc020f64..000000000000 --- a/drivers/staging/iio/light/tsl2563.c +++ /dev/null @@ -1,899 +0,0 @@ -/* - * drivers/i2c/chips/tsl2563.c - * - * Copyright (C) 2008 Nokia Corporation - * - * Written by Timo O. Karjalainen <timo.o.karjalainen@nokia.com> - * Contact: Amit Kucheria <amit.kucheria@verdurent.com> - * - * Converted to IIO driver - * Amit Kucheria <amit.kucheria@verdurent.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/sched.h> -#include <linux/mutex.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/err.h> -#include <linux/slab.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> -#include <linux/iio/events.h> -#include "tsl2563.h" - -/* Use this many bits for fraction part. */ -#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) -/* 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 TSL2563_INT_PERSIST(n) ((n) & 0x0F) - -struct tsl2563_gainlevel_coeff { - u8 gaintime; - u16 min; - u16 max; -}; - -static const struct tsl2563_gainlevel_coeff tsl2563_gainlevel_table[] = { - { - .gaintime = TSL2563_TIMING_400MS | TSL2563_TIMING_GAIN16, - .min = 0, - .max = 65534, - }, { - .gaintime = TSL2563_TIMING_400MS | TSL2563_TIMING_GAIN1, - .min = 2048, - .max = 65534, - }, { - .gaintime = TSL2563_TIMING_100MS | TSL2563_TIMING_GAIN1, - .min = 4095, - .max = 37177, - }, { - .gaintime = TSL2563_TIMING_13MS | TSL2563_TIMING_GAIN1, - .min = 3000, - .max = 65535, - }, -}; - -struct tsl2563_chip { - struct mutex lock; - struct i2c_client *client; - struct delayed_work poweroff_work; - - /* Remember state for suspend and resume functions */ - bool suspended; - - struct tsl2563_gainlevel_coeff const *gainlevel; - - u16 low_thres; - u16 high_thres; - u8 intr; - bool int_enabled; - - /* Calibration coefficients */ - u32 calib0; - u32 calib1; - int cover_comp_gain; - - /* Cache current values, to be returned while suspended */ - u32 data0; - u32 data1; -}; - -static int tsl2563_set_power(struct tsl2563_chip *chip, int on) -{ - struct i2c_client *client = chip->client; - u8 cmd; - - cmd = on ? TSL2563_CMD_POWER_ON : TSL2563_CMD_POWER_OFF; - return i2c_smbus_write_byte_data(client, - TSL2563_CMD | TSL2563_REG_CTRL, cmd); -} - -/* - * Return value is 0 for off, 1 for on, or a negative error - * code if reading failed. - */ -static int tsl2563_get_power(struct tsl2563_chip *chip) -{ - struct i2c_client *client = chip->client; - int ret; - - ret = i2c_smbus_read_byte_data(client, TSL2563_CMD | TSL2563_REG_CTRL); - if (ret < 0) - return ret; - - return (ret & TSL2563_CTRL_POWER_MASK) == TSL2563_CMD_POWER_ON; -} - -static int tsl2563_configure(struct tsl2563_chip *chip) -{ - int ret; - - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_TIMING, - chip->gainlevel->gaintime); - if (ret) - goto error_ret; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_HIGHLOW, - chip->high_thres & 0xFF); - if (ret) - goto error_ret; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_HIGHHIGH, - (chip->high_thres >> 8) & 0xFF); - if (ret) - goto error_ret; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_LOWLOW, - chip->low_thres & 0xFF); - if (ret) - goto error_ret; - 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 */ -error_ret: - return ret; -} - -static void tsl2563_poweroff_work(struct work_struct *work) -{ - struct tsl2563_chip *chip = - container_of(work, struct tsl2563_chip, poweroff_work.work); - tsl2563_set_power(chip, 0); -} - -static int tsl2563_detect(struct tsl2563_chip *chip) -{ - int ret; - - ret = tsl2563_set_power(chip, 1); - if (ret) - return ret; - - ret = tsl2563_get_power(chip); - if (ret < 0) - return ret; - - return ret ? 0 : -ENODEV; -} - -static int tsl2563_read_id(struct tsl2563_chip *chip, u8 *id) -{ - struct i2c_client *client = chip->client; - int ret; - - ret = i2c_smbus_read_byte_data(client, TSL2563_CMD | TSL2563_REG_ID); - if (ret < 0) - return ret; - - *id = ret; - - return 0; -} - -/* - * "Normalized" ADC value is one obtained with 400ms of integration time and - * 16x gain. This function returns the number of bits of shift needed to - * convert between normalized values and HW values obtained using given - * timing and gain settings. - */ -static int adc_shiftbits(u8 timing) -{ - int shift = 0; - - switch (timing & TSL2563_TIMING_MASK) { - case TSL2563_TIMING_13MS: - shift += 5; - break; - case TSL2563_TIMING_100MS: - shift += 2; - break; - case TSL2563_TIMING_400MS: - /* no-op */ - break; - } - - if (!(timing & TSL2563_TIMING_GAIN16)) - shift += 4; - - return shift; -} - -/* Convert a HW ADC value to normalized scale. */ -static u32 normalize_adc(u16 adc, u8 timing) -{ - return adc << adc_shiftbits(timing); -} - -static void tsl2563_wait_adc(struct tsl2563_chip *chip) -{ - unsigned int delay; - - switch (chip->gainlevel->gaintime & TSL2563_TIMING_MASK) { - case TSL2563_TIMING_13MS: - delay = 14; - break; - case TSL2563_TIMING_100MS: - delay = 101; - break; - default: - delay = 402; - } - /* - * TODO: Make sure that we wait at least required delay but why we - * have to extend it one tick more? - */ - schedule_timeout_interruptible(msecs_to_jiffies(delay) + 2); -} - -static int tsl2563_adjust_gainlevel(struct tsl2563_chip *chip, u16 adc) -{ - struct i2c_client *client = chip->client; - - if (adc > chip->gainlevel->max || adc < chip->gainlevel->min) { - - (adc > chip->gainlevel->max) ? - chip->gainlevel++ : chip->gainlevel--; - - i2c_smbus_write_byte_data(client, - TSL2563_CMD | TSL2563_REG_TIMING, - chip->gainlevel->gaintime); - - tsl2563_wait_adc(chip); - tsl2563_wait_adc(chip); - - return 1; - } else - return 0; -} - -static int tsl2563_get_adc(struct tsl2563_chip *chip) -{ - struct i2c_client *client = chip->client; - u16 adc0, adc1; - int retry = 1; - int ret = 0; - - if (chip->suspended) - goto out; - - if (!chip->int_enabled) { - cancel_delayed_work(&chip->poweroff_work); - - if (!tsl2563_get_power(chip)) { - ret = tsl2563_set_power(chip, 1); - if (ret) - goto out; - ret = tsl2563_configure(chip); - if (ret) - goto out; - tsl2563_wait_adc(chip); - } - } - - while (retry) { - ret = i2c_smbus_read_word_data(client, - TSL2563_CMD | TSL2563_REG_DATA0LOW); - if (ret < 0) - goto out; - adc0 = ret; - - ret = i2c_smbus_read_word_data(client, - TSL2563_CMD | TSL2563_REG_DATA1LOW); - if (ret < 0) - goto out; - adc1 = ret; - - retry = tsl2563_adjust_gainlevel(chip, adc0); - } - - chip->data0 = normalize_adc(adc0, chip->gainlevel->gaintime); - chip->data1 = normalize_adc(adc1, chip->gainlevel->gaintime); - - if (!chip->int_enabled) - schedule_delayed_work(&chip->poweroff_work, 5 * HZ); - - ret = 0; -out: - return ret; -} - -static inline int calib_to_sysfs(u32 calib) -{ - return (int) (((calib * CALIB_BASE_SYSFS) + - CALIB_FRAC_HALF) >> CALIB_FRAC_BITS); -} - -static inline u32 calib_from_sysfs(int value) -{ - return (((u32) value) << CALIB_FRAC_BITS) / CALIB_BASE_SYSFS; -} - -/* - * Conversions between lux and ADC values. - * - * The basic formula is lux = c0 * adc0 - c1 * adc1, where c0 and c1 are - * appropriate constants. Different constants are needed for different - * kinds of light, determined by the ratio adc1/adc0 (basically the ratio - * of the intensities in infrared and visible wavelengths). lux_table below - * lists the upper threshold of the adc1/adc0 ratio and the corresponding - * constants. - */ - -struct tsl2563_lux_coeff { - unsigned long ch_ratio; - unsigned long ch0_coeff; - unsigned long ch1_coeff; -}; - -static const struct tsl2563_lux_coeff lux_table[] = { - { - .ch_ratio = FRAC10K(1300), - .ch0_coeff = FRAC10K(315), - .ch1_coeff = FRAC10K(262), - }, { - .ch_ratio = FRAC10K(2600), - .ch0_coeff = FRAC10K(337), - .ch1_coeff = FRAC10K(430), - }, { - .ch_ratio = FRAC10K(3900), - .ch0_coeff = FRAC10K(363), - .ch1_coeff = FRAC10K(529), - }, { - .ch_ratio = FRAC10K(5200), - .ch0_coeff = FRAC10K(392), - .ch1_coeff = FRAC10K(605), - }, { - .ch_ratio = FRAC10K(6500), - .ch0_coeff = FRAC10K(229), - .ch1_coeff = FRAC10K(291), - }, { - .ch_ratio = FRAC10K(8000), - .ch0_coeff = FRAC10K(157), - .ch1_coeff = FRAC10K(180), - }, { - .ch_ratio = FRAC10K(13000), - .ch0_coeff = FRAC10K(34), - .ch1_coeff = FRAC10K(26), - }, { - .ch_ratio = ULONG_MAX, - .ch0_coeff = 0, - .ch1_coeff = 0, - }, -}; - -/* - * 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; - unsigned long ratio, lux, ch0 = adc0, ch1 = adc1; - - ratio = ch0 ? ((ch1 << ADC_FRAC_BITS) / ch0) : ULONG_MAX; - - while (lp->ch_ratio < ratio) - lp++; - - lux = ch0 * lp->ch0_coeff - ch1 * lp->ch1_coeff; - - return (unsigned int) (lux >> ADC_FRAC_BITS); -} - -/*--------------------------------------------------------------*/ -/* Sysfs interface */ -/*--------------------------------------------------------------*/ - - -/* Apply calibration coefficient to ADC count. */ -static u32 calib_adc(u32 adc, u32 calib) -{ - unsigned long scaled = adc; - - scaled *= calib; - scaled >>= CALIB_FRAC_BITS; - - return (u32) scaled; -} - -static int tsl2563_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct tsl2563_chip *chip = iio_priv(indio_dev); - - if (chan->channel == IIO_MOD_LIGHT_BOTH) - chip->calib0 = calib_from_sysfs(val); - else - chip->calib1 = calib_from_sysfs(val); - - return 0; -} - -static int tsl2563_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long m) -{ - int ret = -EINVAL; - u32 calib0, calib1; - struct tsl2563_chip *chip = iio_priv(indio_dev); - - mutex_lock(&chip->lock); - switch (m) { - case IIO_CHAN_INFO_RAW: - case IIO_CHAN_INFO_PROCESSED: - switch (chan->type) { - case IIO_LIGHT: - ret = tsl2563_get_adc(chip); - if (ret) - goto error_ret; - calib0 = calib_adc(chip->data0, chip->calib0) * - chip->cover_comp_gain; - calib1 = calib_adc(chip->data1, chip->calib1) * - chip->cover_comp_gain; - *val = adc_to_lux(calib0, calib1); - ret = IIO_VAL_INT; - break; - case IIO_INTENSITY: - ret = tsl2563_get_adc(chip); - if (ret) - goto error_ret; - if (chan->channel == 0) - *val = chip->data0; - else - *val = chip->data1; - ret = IIO_VAL_INT; - break; - default: - break; - } - break; - - case IIO_CHAN_INFO_CALIBSCALE: - if (chan->channel == 0) - *val = calib_to_sysfs(chip->calib0); - else - *val = calib_to_sysfs(chip->calib1); - ret = IIO_VAL_INT; - break; - default: - ret = -EINVAL; - goto error_ret; - } - -error_ret: - mutex_unlock(&chip->lock); - return ret; -} - -static const struct iio_chan_spec tsl2563_channels[] = { - { - .type = IIO_LIGHT, - .indexed = 1, - .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT, - .channel = 0, - }, { - .type = IIO_INTENSITY, - .modified = 1, - .channel2 = IIO_MOD_LIGHT_BOTH, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, - .event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING) | - IIO_EV_BIT(IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING)), - }, { - .type = IIO_INTENSITY, - .modified = 1, - .channel2 = IIO_MOD_LIGHT_IR, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, - } -}; - -static int tsl2563_read_thresh(struct iio_dev *indio_dev, - u64 event_code, - int *val) -{ - struct tsl2563_chip *chip = iio_priv(indio_dev); - - switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { - case IIO_EV_DIR_RISING: - *val = chip->high_thres; - break; - case IIO_EV_DIR_FALLING: - *val = chip->low_thres; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int tsl2563_write_thresh(struct iio_dev *indio_dev, - u64 event_code, - int val) -{ - struct tsl2563_chip *chip = iio_priv(indio_dev); - int ret; - u8 address; - - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_RISING) - address = TSL2563_REG_HIGHLOW; - else - address = TSL2563_REG_LOWLOW; - mutex_lock(&chip->lock); - ret = i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | address, - val & 0xFF); - if (ret) - goto error_ret; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | (address + 1), - (val >> 8) & 0xFF); - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_RISING) - chip->high_thres = val; - else - chip->low_thres = val; - -error_ret: - mutex_unlock(&chip->lock); - - return ret; -} - -static irqreturn_t tsl2563_event_handler(int irq, void *private) -{ - struct iio_dev *dev_info = private; - struct tsl2563_chip *chip = iio_priv(dev_info); - - iio_push_event(dev_info, - IIO_UNMOD_EVENT_CODE(IIO_LIGHT, - 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_EITHER), - iio_get_time_ns()); - - /* clear the interrupt and push the event */ - i2c_smbus_write_byte(chip->client, TSL2563_CMD | TSL2563_CLEARINT); - return IRQ_HANDLED; -} - -static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev, - u64 event_code, - int state) -{ - struct tsl2563_chip *chip = iio_priv(indio_dev); - int ret = 0; - - mutex_lock(&chip->lock); - if (state && !(chip->intr & 0x30)) { - chip->intr &= ~0x30; - chip->intr |= 0x10; - /* ensure the chip is actually on */ - cancel_delayed_work(&chip->poweroff_work); - if (!tsl2563_get_power(chip)) { - ret = tsl2563_set_power(chip, 1); - if (ret) - goto out; - ret = tsl2563_configure(chip); - if (ret) - goto out; - } - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_INT, - chip->intr); - chip->int_enabled = true; - } - - if (!state && (chip->intr & 0x30)) { - chip->intr &= ~0x30; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_INT, - chip->intr); - chip->int_enabled = false; - /* now the interrupt is not enabled, we can go to sleep */ - schedule_delayed_work(&chip->poweroff_work, 5 * HZ); - } -out: - mutex_unlock(&chip->lock); - - return ret; -} - -static int tsl2563_read_interrupt_config(struct iio_dev *indio_dev, - u64 event_code) -{ - struct tsl2563_chip *chip = iio_priv(indio_dev); - int ret; - - mutex_lock(&chip->lock); - ret = i2c_smbus_read_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_INT); - mutex_unlock(&chip->lock); - if (ret < 0) - goto error_ret; - ret = !!(ret & 0x30); -error_ret: - - return ret; -} - -/*--------------------------------------------------------------*/ -/* 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, - .write_raw = &tsl2563_write_raw, -}; - -static const struct iio_info tsl2563_info = { - .driver_module = THIS_MODULE, - .read_raw = &tsl2563_read_raw, - .write_raw = &tsl2563_write_raw, - .read_event_value = &tsl2563_read_thresh, - .write_event_value = &tsl2563_write_thresh, - .read_event_config = &tsl2563_read_interrupt_config, - .write_event_config = &tsl2563_write_interrupt_config, -}; - -static int tsl2563_probe(struct i2c_client *client, - const struct i2c_device_id *device_id) -{ - struct iio_dev *indio_dev; - struct tsl2563_chip *chip; - struct tsl2563_platform_data *pdata = client->dev.platform_data; - int err = 0; - u8 id = 0; - - indio_dev = iio_device_alloc(sizeof(*chip)); - if (!indio_dev) - return -ENOMEM; - - chip = iio_priv(indio_dev); - - i2c_set_clientdata(client, chip); - chip->client = client; - - err = tsl2563_detect(chip); - if (err) { - dev_err(&client->dev, "detect error %d\n", -err); - goto fail1; - } - - err = tsl2563_read_id(chip, &id); - if (err) { - dev_err(&client->dev, "read id error %d\n", -err); - goto fail1; - } - - mutex_init(&chip->lock); - - /* Default values used until userspace says otherwise */ - chip->low_thres = 0x0; - chip->high_thres = 0xffff; - chip->gainlevel = tsl2563_gainlevel_table; - chip->intr = TSL2563_INT_PERSIST(4); - chip->calib0 = calib_from_sysfs(CALIB_BASE_SYSFS); - chip->calib1 = calib_from_sysfs(CALIB_BASE_SYSFS); - - if (pdata) - chip->cover_comp_gain = pdata->cover_comp_gain; - else - chip->cover_comp_gain = 1; - - dev_info(&client->dev, "model %d, rev. %d\n", id >> 4, id & 0x0f); - indio_dev->name = client->name; - indio_dev->channels = tsl2563_channels; - indio_dev->num_channels = ARRAY_SIZE(tsl2563_channels); - indio_dev->dev.parent = &client->dev; - indio_dev->modes = INDIO_DIRECT_MODE; - - if (client->irq) - indio_dev->info = &tsl2563_info; - else - indio_dev->info = &tsl2563_info_no_irq; - - if (client->irq) { - err = request_threaded_irq(client->irq, - NULL, - &tsl2563_event_handler, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "tsl2563_event", - indio_dev); - if (err) { - dev_err(&client->dev, "irq request error %d\n", -err); - goto fail1; - } - } - - err = tsl2563_configure(chip); - if (err) { - dev_err(&client->dev, "configure error %d\n", -err); - goto fail2; - } - - INIT_DELAYED_WORK(&chip->poweroff_work, tsl2563_poweroff_work); - - /* The interrupt cannot yet be enabled so this is fine without lock */ - schedule_delayed_work(&chip->poweroff_work, 5 * HZ); - - err = iio_device_register(indio_dev); - if (err) { - dev_err(&client->dev, "iio registration error %d\n", -err); - goto fail3; - } - - return 0; - -fail3: - cancel_delayed_work(&chip->poweroff_work); - flush_scheduled_work(); -fail2: - if (client->irq) - free_irq(client->irq, indio_dev); -fail1: - iio_device_free(indio_dev); - return err; -} - -static int tsl2563_remove(struct i2c_client *client) -{ - struct tsl2563_chip *chip = i2c_get_clientdata(client); - struct iio_dev *indio_dev = iio_priv_to_dev(chip); - - iio_device_unregister(indio_dev); - if (!chip->int_enabled) - cancel_delayed_work(&chip->poweroff_work); - /* Ensure that interrupts are disabled - then flush any bottom halves */ - chip->intr &= ~0x30; - i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | TSL2563_REG_INT, - chip->intr); - flush_scheduled_work(); - tsl2563_set_power(chip, 0); - if (client->irq) - free_irq(client->irq, indio_dev); - - iio_device_free(indio_dev); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int tsl2563_suspend(struct device *dev) -{ - struct tsl2563_chip *chip = i2c_get_clientdata(to_i2c_client(dev)); - int ret; - - mutex_lock(&chip->lock); - - ret = tsl2563_set_power(chip, 0); - if (ret) - goto out; - - chip->suspended = true; - -out: - mutex_unlock(&chip->lock); - return ret; -} - -static int tsl2563_resume(struct device *dev) -{ - struct tsl2563_chip *chip = i2c_get_clientdata(to_i2c_client(dev)); - int ret; - - mutex_lock(&chip->lock); - - ret = tsl2563_set_power(chip, 1); - if (ret) - goto out; - - ret = tsl2563_configure(chip); - if (ret) - goto out; - - chip->suspended = false; - -out: - mutex_unlock(&chip->lock); - return ret; -} - -static SIMPLE_DEV_PM_OPS(tsl2563_pm_ops, tsl2563_suspend, tsl2563_resume); -#define TSL2563_PM_OPS (&tsl2563_pm_ops) -#else -#define TSL2563_PM_OPS NULL -#endif - -static const struct i2c_device_id tsl2563_id[] = { - { "tsl2560", 0 }, - { "tsl2561", 1 }, - { "tsl2562", 2 }, - { "tsl2563", 3 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, tsl2563_id); - -static struct i2c_driver tsl2563_i2c_driver = { - .driver = { - .name = "tsl2563", - .pm = TSL2563_PM_OPS, - }, - .probe = tsl2563_probe, - .remove = tsl2563_remove, - .id_table = tsl2563_id, -}; -module_i2c_driver(tsl2563_i2c_driver); - -MODULE_AUTHOR("Nokia Corporation"); -MODULE_DESCRIPTION("tsl2563 light sensor driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/light/tsl2563.h b/drivers/staging/iio/light/tsl2563.h deleted file mode 100644 index b97368bd7fff..000000000000 --- a/drivers/staging/iio/light/tsl2563.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __LINUX_TSL2563_H -#define __LINUX_TSL2563_H - -struct tsl2563_platform_data { - int cover_comp_gain; -}; - -#endif /* __LINUX_TSL2563_H */ - diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index 9e50fbbadf9d..a58731e70bb9 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -292,59 +292,6 @@ static const u8 device_channel_config[] = { }; /** - * 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 @@ -1036,13 +983,12 @@ static ssize_t tsl2x7x_als_time_store(struct device *dev, 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); @@ -1109,12 +1055,12 @@ static ssize_t tsl2x7x_als_persistence_store(struct device *dev, 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; @@ -1155,12 +1101,12 @@ static ssize_t tsl2x7x_prox_persistence_store(struct device *dev, 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; diff --git a/drivers/staging/iio/meter/Kconfig b/drivers/staging/iio/meter/Kconfig index d290d2738419..e53274b64ae1 100644 --- a/drivers/staging/iio/meter/Kconfig +++ b/drivers/staging/iio/meter/Kconfig @@ -21,7 +21,7 @@ config ADE7758 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. diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index 51c3bdece785..e5943e2287cf 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -103,7 +103,6 @@ static int ade7753_spi_read_reg_24(struct device *dev, u8 reg_address, u32 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); int ret; @@ -122,10 +121,7 @@ static int ade7753_spi_read_reg_24(struct device *dev, mutex_lock(&st->buf_lock); st->tx[0] = ADE7753_READ_REG(reg_address); - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X", reg_address); diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index b50c89e93993..7b6503bf9a74 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c @@ -103,7 +103,6 @@ static int ade7754_spi_read_reg_24(struct device *dev, u8 reg_address, u32 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7754_state *st = iio_priv(indio_dev); int ret; @@ -122,9 +121,7 @@ static int ade7754_spi_read_reg_24(struct device *dev, st->tx[2] = 0; st->tx[3] = 0; - spi_message_init(&msg); - spi_message_add_tail(xfers, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X", reg_address); diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index 3454e5154ed2..53c68dcc4544 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -47,7 +47,6 @@ static int ade7758_spi_write_reg_16(struct device *dev, u16 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); struct spi_transfer xfers[] = { @@ -63,9 +62,7 @@ static int ade7758_spi_write_reg_16(struct device *dev, st->tx[1] = (value >> 8) & 0xFF; st->tx[2] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(xfers, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); mutex_unlock(&st->buf_lock); return ret; @@ -76,7 +73,6 @@ static int ade7758_spi_write_reg_24(struct device *dev, u32 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); struct spi_transfer xfers[] = { @@ -93,9 +89,7 @@ static int ade7758_spi_write_reg_24(struct device *dev, st->tx[2] = (value >> 8) & 0xFF; st->tx[3] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(xfers, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); mutex_unlock(&st->buf_lock); return ret; @@ -105,7 +99,6 @@ int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); int ret; @@ -128,10 +121,7 @@ int ade7758_spi_read_reg_8(struct device *dev, st->tx[0] = ADE7758_READ_REG(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); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X", reg_address); @@ -148,7 +138,6 @@ static int ade7758_spi_read_reg_16(struct device *dev, u8 reg_address, u16 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); int ret; @@ -173,10 +162,7 @@ static int ade7758_spi_read_reg_16(struct device *dev, st->tx[1] = 0; st->tx[2] = 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); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", reg_address); @@ -194,7 +180,6 @@ static int ade7758_spi_read_reg_24(struct device *dev, u8 reg_address, u32 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); int ret; @@ -219,10 +204,7 @@ static int ade7758_spi_read_reg_24(struct device *dev, st->tx[2] = 0; st->tx[3] = 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); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X", reg_address); diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c index 4552a4c7fe33..b29e2d5d9937 100644 --- a/drivers/staging/iio/meter/ade7758_ring.c +++ b/drivers/staging/iio/meter/ade7758_ring.c @@ -13,7 +13,7 @@ #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" @@ -119,7 +119,7 @@ static const struct iio_buffer_setup_ops ade7758_ring_setup_ops = { 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) @@ -127,7 +127,7 @@ 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; @@ -143,7 +143,7 @@ int ade7758_configure_ring(struct iio_dev *indio_dev) 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; @@ -183,8 +183,8 @@ int ade7758_configure_ring(struct iio_dev *indio_dev) 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; } diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c index 10b911bd3853..17dc373e1082 100644 --- a/drivers/staging/iio/meter/ade7759.c +++ b/drivers/staging/iio/meter/ade7759.c @@ -103,7 +103,6 @@ static int ade7759_spi_read_reg_40(struct device *dev, u8 reg_address, u64 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); int ret; @@ -120,9 +119,7 @@ static int ade7759_spi_read_reg_40(struct device *dev, st->tx[0] = ADE7759_READ_REG(reg_address); memset(&st->tx[1], 0 , 5); - spi_message_init(&msg); - spi_message_add_tail(xfers, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 40 bit register 0x%02X", reg_address); diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c index f0984fa1cbb9..a802cf2491d6 100644 --- a/drivers/staging/iio/meter/ade7854-spi.c +++ b/drivers/staging/iio/meter/ade7854-spi.c @@ -20,7 +20,6 @@ static int ade7854_spi_write_reg_8(struct device *dev, u8 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { @@ -35,9 +34,7 @@ static int ade7854_spi_write_reg_8(struct device *dev, st->tx[2] = reg_address & 0xFF; st->tx[3] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); return ret; @@ -48,7 +45,6 @@ static int ade7854_spi_write_reg_16(struct device *dev, u16 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { @@ -64,9 +60,7 @@ static int ade7854_spi_write_reg_16(struct device *dev, st->tx[3] = (value >> 8) & 0xFF; st->tx[4] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); return ret; @@ -77,7 +71,6 @@ static int ade7854_spi_write_reg_24(struct device *dev, u32 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { @@ -94,9 +87,7 @@ static int ade7854_spi_write_reg_24(struct device *dev, st->tx[4] = (value >> 8) & 0xFF; st->tx[5] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); return ret; @@ -107,7 +98,6 @@ static int ade7854_spi_write_reg_32(struct device *dev, u32 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { @@ -125,9 +115,7 @@ static int ade7854_spi_write_reg_32(struct device *dev, st->tx[5] = (value >> 8) & 0xFF; st->tx[6] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); return ret; @@ -137,7 +125,6 @@ static int ade7854_spi_read_reg_8(struct device *dev, u16 reg_address, u8 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -159,10 +146,7 @@ static int ade7854_spi_read_reg_8(struct device *dev, st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 8 bit register 0x%02X", reg_address); @@ -179,7 +163,6 @@ static int ade7854_spi_read_reg_16(struct device *dev, u16 reg_address, u16 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -200,10 +183,7 @@ static int ade7854_spi_read_reg_16(struct device *dev, st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 16 bit register 0x%02X", reg_address); @@ -220,7 +200,6 @@ static int ade7854_spi_read_reg_24(struct device *dev, u16 reg_address, u32 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -242,10 +221,7 @@ static int ade7854_spi_read_reg_24(struct device *dev, st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 24 bit register 0x%02X", reg_address); @@ -262,7 +238,6 @@ static int ade7854_spi_read_reg_32(struct device *dev, u16 reg_address, u32 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -284,10 +259,7 @@ static int ade7854_spi_read_reg_32(struct device *dev, st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 32 bit register 0x%02X", reg_address); diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index ed07a348eb55..53110b6a3c74 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -130,15 +130,12 @@ static int ad2s1210_config_read(struct ad2s1210_state *st, .rx_buf = st->rx, .tx_buf = st->tx, }; - struct spi_message msg; int ret = 0; ad2s1210_set_mode(MOD_CONFIG, st); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); st->tx[0] = address | AD2S1210_MSB_IS_HIGH; st->tx[1] = AD2S1210_REG_FAULT; - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret < 0) return ret; st->old_data = true; diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c deleted file mode 100644 index 3a45f9a52de8..000000000000 --- a/drivers/staging/iio/ring_sw.c +++ /dev/null @@ -1,366 +0,0 @@ -/* 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"); diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h deleted file mode 100644 index a5857aa7aefa..000000000000 --- a/drivers/staging/iio/ring_sw.h +++ /dev/null @@ -1,30 +0,0 @@ -/* 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_ */ |