diff options
author | Ingo Molnar <mingo@elte.hu> | 2010-08-19 12:48:09 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-08-19 12:48:09 +0200 |
commit | c8710ad38900153af7a3e6762e99c062cfa46443 (patch) | |
tree | a0c0632274c4eb72f51e99a5861f71cffe65ea60 /drivers/staging/iio | |
parent | 6016ee13db518ab1cd0cbf43fc2ad5712021e338 (diff) | |
parent | 86397dc3ccfc0e17b7550d05eaf15fe91f6498dd (diff) |
Merge branch 'tip/perf/urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace into perf/core
Diffstat (limited to 'drivers/staging/iio')
65 files changed, 2551 insertions, 1548 deletions
diff --git a/drivers/staging/iio/Documentation/overview.txt b/drivers/staging/iio/Documentation/overview.txt index e39dfc1705a..cc6ecad4035 100644 --- a/drivers/staging/iio/Documentation/overview.txt +++ b/drivers/staging/iio/Documentation/overview.txt @@ -44,7 +44,7 @@ which the raw data it self may be read back. applications it it useful to be able to capture data based on some external signal (trigger). These triggers might be a data ready signal, a gpio line connected to some external system or an on -processor periodic interrupt. A single trigger many initialize data +processor periodic interrupt. A single trigger may initialize data capture or reading from a number of sensors. These triggers are used in iio to fill software ring buffers acting in a very similar fashion to the hardware buffers described above. diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index b0e62449c62..ed48815a916 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -21,6 +21,7 @@ config IIO_RING_BUFFER if IIO_RING_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 @@ -44,6 +45,7 @@ source "drivers/staging/iio/adc/Kconfig" source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/imu/Kconfig" source "drivers/staging/iio/light/Kconfig" +source "drivers/staging/iio/magnetometer/Kconfig" source "drivers/staging/iio/trigger/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index 3502b39f084..e909674920f 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -14,5 +14,5 @@ obj-y += adc/ obj-y += gyro/ obj-y += imu/ obj-y += light/ - -obj-y += trigger/
\ No newline at end of file +obj-y += trigger/ +obj-y += magnetometer/ diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO index 15da0c2bb78..898cba1c939 100644 --- a/drivers/staging/iio/TODO +++ b/drivers/staging/iio/TODO @@ -66,4 +66,4 @@ Documentation 2) Some device require indvidual docs. Contact: Jonathan Cameron <jic23@cam.ac.uk>. -Mailing list: LKML. +Mailing list: linux-iio@vger.kernel.org diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index b4e57d1bc87..5926c03be1a 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -4,29 +4,29 @@ comment "Accelerometers" config ADIS16209 - tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" - depends on SPI - select IIO_TRIGGER if IIO_RING_BUFFER - select IIO_SW_RING if IIO_RING_BUFFER - help - Say yes here to build support for Analog Devices adis16209 dual-axis digital inclinometer - and accelerometer. + tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" + depends on SPI + select IIO_TRIGGER if IIO_RING_BUFFER + select IIO_SW_RING if IIO_RING_BUFFER + help + Say yes here to build support for Analog Devices adis16209 dual-axis digital inclinometer + and accelerometer. config ADIS16220 - tristate "Analog Devices ADIS16220 Programmable Digital Vibration Sensor driver" - depends on SPI - help - Say yes here to build support for Analog Devices adis16220 programmable - digital vibration sensor. + tristate "Analog Devices ADIS16220 Programmable Digital Vibration Sensor" + depends on SPI + help + Say yes here to build support for Analog Devices adis16220 programmable + digital vibration sensor. config ADIS16240 - tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder" - depends on SPI - select IIO_TRIGGER if IIO_RING_BUFFER - select IIO_SW_RING if IIO_RING_BUFFER - help - Say yes here to build support for Analog Devices adis16240 programmable - impact Sensor and recorder. + tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder" + depends on SPI + select IIO_TRIGGER if IIO_RING_BUFFER + select IIO_SW_RING if IIO_RING_BUFFER + help + Say yes here to build support for Analog Devices adis16240 programmable + impact Sensor and recorder. config KXSD9 tristate "Kionix KXSD9 Accelerometer Driver" @@ -46,9 +46,9 @@ config LIS3L02DQ and an event interface via a character device. config SCA3000 - depends on IIO_RING_BUFFER - depends on SPI - tristate "VTI SCA3000 series accelerometers" - help - Say yes here to build support for the VTI SCA3000 series of SPI - accelerometers. These devices use a hardware ring buffer.
\ No newline at end of file + depends on IIO_RING_BUFFER + depends on SPI + tristate "VTI SCA3000 series accelerometers" + help + Say yes here to build support for the VTI SCA3000 series of SPI + accelerometers. These devices use a hardware ring buffer. diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index c34b13634c2..ff84703a16f 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -1,6 +1,7 @@ # # Makefile for industrial I/O accelerometer drivers # + adis16209-y := adis16209_core.o adis16209-$(CONFIG_IIO_RING_BUFFER) += adis16209_ring.o adis16209_trigger.o obj-$(CONFIG_ADIS16209) += adis16209.o @@ -19,4 +20,4 @@ lis3l02dq-$(CONFIG_IIO_RING_BUFFER) += lis3l02dq_ring.o obj-$(CONFIG_LIS3L02DQ) += lis3l02dq.o sca3000-y := sca3000_core.o sca3000_ring.o -obj-$(CONFIG_SCA3000) += sca3000.o
\ No newline at end of file +obj-$(CONFIG_SCA3000) += sca3000.o diff --git a/drivers/staging/iio/accel/adis16209.h b/drivers/staging/iio/accel/adis16209.h index 877fd2a4838..4e97596620e 100644 --- a/drivers/staging/iio/accel/adis16209.h +++ b/drivers/staging/iio/accel/adis16209.h @@ -105,8 +105,6 @@ * struct adis16209_state - device instance specific data * @us: actual spi_device * @work_trigger_to_ring: bh for triggered event handling - * @work_cont_thresh: CLEAN - * @inter: used to check if new interrupt has been triggered * @last_timestamp: passing timestamp from th to bh of interrupt handler * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio @@ -117,7 +115,6 @@ struct adis16209_state { struct spi_device *us; struct work_struct work_trigger_to_ring; - struct iio_work_cont work_cont_thresh; s64 last_timestamp; struct iio_dev *indio_dev; struct iio_trigger *trig; @@ -129,16 +126,15 @@ struct adis16209_state { int adis16209_set_irq(struct device *dev, bool enable); #ifdef CONFIG_IIO_RING_BUFFER -enum adis16209_scan { - ADIS16209_SCAN_SUPPLY, - ADIS16209_SCAN_ACC_X, - ADIS16209_SCAN_ACC_Y, - ADIS16209_SCAN_AUX_ADC, - ADIS16209_SCAN_TEMP, - ADIS16209_SCAN_INCLI_X, - ADIS16209_SCAN_INCLI_Y, - ADIS16209_SCAN_ROT, -}; + +#define ADIS16209_SCAN_SUPPLY 0 +#define ADIS16209_SCAN_ACC_X 1 +#define ADIS16209_SCAN_ACC_Y 2 +#define ADIS16209_SCAN_AUX_ADC 3 +#define ADIS16209_SCAN_TEMP 4 +#define ADIS16209_SCAN_INCLI_X 5 +#define ADIS16209_SCAN_INCLI_Y 6 +#define ADIS16209_SCAN_ROT 7 void adis16209_remove_trigger(struct iio_dev *indio_dev); int adis16209_probe_trigger(struct iio_dev *indio_dev); @@ -150,8 +146,6 @@ ssize_t adis16209_read_data_from_ring(struct device *dev, int adis16209_configure_ring(struct iio_dev *indio_dev); void adis16209_unconfigure_ring(struct iio_dev *indio_dev); -int adis16209_initialize_ring(struct iio_ring_buffer *ring); -void adis16209_uninitialize_ring(struct iio_ring_buffer *ring); #else /* CONFIG_IIO_RING_BUFFER */ static inline void adis16209_remove_trigger(struct iio_dev *indio_dev) @@ -180,14 +174,5 @@ static inline void adis16209_unconfigure_ring(struct iio_dev *indio_dev) { } -static inline int adis16209_initialize_ring(struct iio_ring_buffer *ring) -{ - return 0; -} - -static inline void adis16209_uninitialize_ring(struct iio_ring_buffer *ring) -{ -} - #endif /* CONFIG_IIO_RING_BUFFER */ #endif /* SPI_ADIS16209_H_ */ diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c index ac375c50f56..6c6923f2eaa 100644 --- a/drivers/staging/iio/accel/adis16209_core.c +++ b/drivers/staging/iio/accel/adis16209_core.c @@ -14,12 +14,13 @@ #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 "../iio.h" #include "../sysfs.h" +#include "../ring_generic.h" #include "accel.h" #include "inclinometer.h" #include "../gyro/gyro.h" @@ -76,11 +77,13 @@ static int adis16209_spi_write_reg_16(struct device *dev, .bits_per_word = 8, .len = 2, .cs_change = 1, + .delay_usecs = 30, }, { .tx_buf = st->tx + 2, .bits_per_word = 8, .len = 2, .cs_change = 1, + .delay_usecs = 30, }, }; @@ -120,13 +123,13 @@ static int adis16209_spi_read_reg_16(struct device *dev, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 20, + .delay_usecs = 30, }, { .rx_buf = st->rx, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 20, + .delay_usecs = 30, }, }; @@ -518,7 +521,7 @@ static int __devinit adis16209_probe(struct spi_device *spi) goto error_unreg_ring_funcs; regdone = 1; - ret = adis16209_initialize_ring(st->indio_dev->ring); + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); if (ret) { printk(KERN_ERR "failed to initialize the ring\n"); goto error_unreg_ring_funcs; @@ -550,7 +553,7 @@ error_unregister_line: if (spi->irq) iio_unregister_interrupt_line(st->indio_dev, 0); error_uninitialize_ring: - adis16209_uninitialize_ring(st->indio_dev->ring); + iio_ring_buffer_unregister(st->indio_dev->ring); error_unreg_ring_funcs: adis16209_unconfigure_ring(st->indio_dev); error_free_dev: @@ -579,7 +582,7 @@ static int adis16209_remove(struct spi_device *spi) if (spi->irq) iio_unregister_interrupt_line(indio_dev, 0); - adis16209_uninitialize_ring(indio_dev->ring); + iio_ring_buffer_unregister(indio_dev->ring); iio_device_unregister(indio_dev); adis16209_unconfigure_ring(indio_dev); kfree(st->tx); diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c index 533e2857491..25fde659d09 100644 --- a/drivers/staging/iio/accel/adis16209_ring.c +++ b/drivers/staging/iio/accel/adis16209_ring.c @@ -6,6 +6,7 @@ #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> @@ -16,16 +17,6 @@ #include "../trigger.h" #include "adis16209.h" -/** - * combine_8_to_16() utility function to munge to u8s into u16 - **/ -static inline u16 combine_8_to_16(u8 lower, u8 upper) -{ - u16 _lower = lower; - u16 _upper = upper; - return _lower | (_upper << 8); -} - static IIO_SCAN_EL_C(supply, ADIS16209_SCAN_SUPPLY, IIO_UNSIGNED(14), ADIS16209_SUPPLY_OUT, NULL); static IIO_SCAN_EL_C(accel_x, ADIS16209_SCAN_ACC_X, IIO_SIGNED(14), @@ -67,10 +58,10 @@ static struct attribute_group adis16209_scan_el_group = { * adis16209_poll_func_th() top half interrupt handler called by trigger * @private_data: iio_dev **/ -static void adis16209_poll_func_th(struct iio_dev *indio_dev) +static void adis16209_poll_func_th(struct iio_dev *indio_dev, s64 time) { struct adis16209_state *st = iio_dev_get_devdata(indio_dev); - st->last_timestamp = indio_dev->trig->timestamp; + st->last_timestamp = time; schedule_work(&st->work_trigger_to_ring); } @@ -138,10 +129,9 @@ static void adis16209_trigger_bh_to_ring(struct work_struct *work_s) if (st->indio_dev->scan_count) if (adis16209_read_ring_data(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) { - data[i] = combine_8_to_16(st->rx[i*2+1], - st->rx[i*2]); - } + for (; i < st->indio_dev->scan_count; i++) + data[i] = be16_to_cpup( + (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ if (st->indio_dev->scan_timestamp) @@ -157,50 +147,6 @@ static void adis16209_trigger_bh_to_ring(struct work_struct *work_s) return; } -/* in these circumstances is it better to go with unaligned packing and - * deal with the cost?*/ -static int adis16209_data_rdy_ring_preenable(struct iio_dev *indio_dev) -{ - size_t size; - dev_dbg(&indio_dev->dev, "%s\n", __func__); - /* Check if there are any scan elements enabled, if not fail*/ - if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) - return -EINVAL; - - if (indio_dev->ring->access.set_bpd) { - if (indio_dev->scan_timestamp) - if (indio_dev->scan_count) - /* Timestamp (aligned to s64) and data */ - size = (((indio_dev->scan_count * sizeof(s16)) - + sizeof(s64) - 1) - & ~(sizeof(s64) - 1)) - + sizeof(s64); - else /* Timestamp only */ - size = sizeof(s64); - else /* Data only */ - size = indio_dev->scan_count*sizeof(s16); - indio_dev->ring->access.set_bpd(indio_dev->ring, size); - } - - return 0; -} - -static int adis16209_data_rdy_ring_postenable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_attach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - -static int adis16209_data_rdy_ring_predisable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_dettach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - void adis16209_unconfigure_ring(struct iio_dev *indio_dev) { kfree(indio_dev->pollfunc); @@ -235,18 +181,16 @@ int adis16209_configure_ring(struct iio_dev *indio_dev) indio_dev->ring = ring; /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); - ring->preenable = &adis16209_data_rdy_ring_preenable; - ring->postenable = &adis16209_data_rdy_ring_postenable; - ring->predisable = &adis16209_data_rdy_ring_predisable; + ring->bpe = 2; + ring->preenable = &iio_sw_ring_preenable; + ring->postenable = &iio_triggered_ring_postenable; + ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; - indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); - if (indio_dev->pollfunc == NULL) { - ret = -ENOMEM; - goto error_iio_sw_rb_free;; - } - indio_dev->pollfunc->poll_func_main = &adis16209_poll_func_th; - indio_dev->pollfunc->private_data = indio_dev; + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16209_poll_func_th); + if (ret) + goto error_iio_sw_rb_free; + indio_dev->modes |= INDIO_RING_TRIGGERED; return 0; @@ -254,13 +198,3 @@ error_iio_sw_rb_free: iio_sw_rb_free(indio_dev->ring); return ret; } - -int adis16209_initialize_ring(struct iio_ring_buffer *ring) -{ - return iio_ring_buffer_register(ring, 0); -} - -void adis16209_uninitialize_ring(struct iio_ring_buffer *ring) -{ - iio_ring_buffer_unregister(ring); -} diff --git a/drivers/staging/iio/accel/adis16209_trigger.c b/drivers/staging/iio/accel/adis16209_trigger.c index 4a0507c9a13..1487effa2e3 100644 --- a/drivers/staging/iio/accel/adis16209_trigger.c +++ b/drivers/staging/iio/accel/adis16209_trigger.c @@ -23,8 +23,7 @@ static int adis16209_data_rdy_trig_poll(struct iio_dev *dev_info, struct adis16209_state *st = iio_dev_get_devdata(dev_info); struct iio_trigger *trig = st->trig; - trig->timestamp = timestamp; - iio_trigger_poll(trig); + iio_trigger_poll(trig, timestamp); return IRQ_HANDLED; } @@ -83,14 +82,13 @@ int adis16209_probe_trigger(struct iio_dev *indio_dev) struct adis16209_state *st = indio_dev->dev_data; st->trig = iio_allocate_trigger(); - st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); + st->trig->name = kasprintf(GFP_KERNEL, + "adis16209-dev%d", + indio_dev->id); if (!st->trig->name) { ret = -ENOMEM; goto error_free_trig; } - snprintf((char *)st->trig->name, - IIO_TRIGGER_NAME_LENGTH, - "adis16209-dev%d", indio_dev->id); st->trig->dev.parent = &st->us->dev; st->trig->owner = THIS_MODULE; st->trig->private_data = st; diff --git a/drivers/staging/iio/accel/adis16220.h b/drivers/staging/iio/accel/adis16220.h index 2abf4850b37..7013314a9d7 100644 --- a/drivers/staging/iio/accel/adis16220.h +++ b/drivers/staging/iio/accel/adis16220.h @@ -127,7 +127,6 @@ * struct adis16220_state - device instance specific data * @us: actual spi_device * @work_trigger_to_ring: bh for triggered event handling - * @work_cont_thresh: CLEAN * @inter: used to check if new interrupt has been triggered * @last_timestamp: passing timestamp from th to bh of interrupt handler * @indio_dev: industrial I/O device structure diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c index 6de439fd167..bb7d76539cd 100644 --- a/drivers/staging/iio/accel/adis16220_core.c +++ b/drivers/staging/iio/accel/adis16220_core.c @@ -14,7 +14,7 @@ #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> @@ -72,13 +72,13 @@ static int adis16220_spi_write_reg_16(struct device *dev, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, { .tx_buf = st->tx + 2, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, }; @@ -118,13 +118,13 @@ static int adis16220_spi_read_reg_16(struct device *dev, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, { .rx_buf = st->rx, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, }; @@ -291,9 +291,9 @@ static int adis16220_check_status(struct device *dev) if (status & ADIS16220_DIAG_STAT_FLASH_UPT) dev_err(dev, "Flash update failed\n"); if (status & ADIS16220_DIAG_STAT_POWER_HIGH) - dev_err(dev, "Power supply above 5.25V\n"); + dev_err(dev, "Power supply above 3.625V\n"); if (status & ADIS16220_DIAG_STAT_POWER_LOW) - dev_err(dev, "Power supply below 4.75V\n"); + dev_err(dev, "Power supply below 3.15V\n"); error_ret: return ret; @@ -414,7 +414,7 @@ static ssize_t adis16220_capture_buffer_read(struct adis16220_state *st, return count; } -static ssize_t adis16220_accel_bin_read(struct kobject *kobj, +static ssize_t adis16220_accel_bin_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, @@ -438,7 +438,7 @@ static struct bin_attribute accel_bin = { .size = ADIS16220_CAPTURE_SIZE, }; -static ssize_t adis16220_adc1_bin_read(struct kobject *kobj, +static ssize_t adis16220_adc1_bin_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) @@ -461,7 +461,7 @@ static struct bin_attribute adc1_bin = { .size = ADIS16220_CAPTURE_SIZE, }; -static ssize_t adis16220_adc2_bin_read(struct kobject *kobj, +static ssize_t adis16220_adc2_bin_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) diff --git a/drivers/staging/iio/accel/adis16240.h b/drivers/staging/iio/accel/adis16240.h index dcff43c7523..51a807dde27 100644 --- a/drivers/staging/iio/accel/adis16240.h +++ b/drivers/staging/iio/accel/adis16240.h @@ -127,7 +127,6 @@ * struct adis16240_state - device instance specific data * @us: actual spi_device * @work_trigger_to_ring: bh for triggered event handling - * @work_cont_thresh: CLEAN * @inter: used to check if new interrupt has been triggered * @last_timestamp: passing timestamp from th to bh of interrupt handler * @indio_dev: industrial I/O device structure @@ -139,7 +138,6 @@ struct adis16240_state { struct spi_device *us; struct work_struct work_trigger_to_ring; - struct iio_work_cont work_cont_thresh; s64 last_timestamp; struct iio_dev *indio_dev; struct iio_trigger *trig; @@ -155,14 +153,12 @@ int adis16240_set_irq(struct device *dev, bool enable); * filling. This may change! */ -enum adis16240_scan { - ADIS16240_SCAN_SUPPLY, - ADIS16240_SCAN_ACC_X, - ADIS16240_SCAN_ACC_Y, - ADIS16240_SCAN_ACC_Z, - ADIS16240_SCAN_AUX_ADC, - ADIS16240_SCAN_TEMP, -}; +#define ADIS16240_SCAN_SUPPLY 0 +#define ADIS16240_SCAN_ACC_X 1 +#define ADIS16240_SCAN_ACC_Y 2 +#define ADIS16240_SCAN_ACC_Z 3 +#define ADIS16240_SCAN_AUX_ADC 4 +#define ADIS16240_SCAN_TEMP 5 void adis16240_remove_trigger(struct iio_dev *indio_dev); int adis16240_probe_trigger(struct iio_dev *indio_dev); @@ -175,8 +171,6 @@ ssize_t adis16240_read_data_from_ring(struct device *dev, int adis16240_configure_ring(struct iio_dev *indio_dev); void adis16240_unconfigure_ring(struct iio_dev *indio_dev); -int adis16240_initialize_ring(struct iio_ring_buffer *ring); -void adis16240_uninitialize_ring(struct iio_ring_buffer *ring); #else /* CONFIG_IIO_RING_BUFFER */ static inline void adis16240_remove_trigger(struct iio_dev *indio_dev) @@ -205,14 +199,5 @@ static inline void adis16240_unconfigure_ring(struct iio_dev *indio_dev) { } -static inline int adis16240_initialize_ring(struct iio_ring_buffer *ring) -{ - return 0; -} - -static inline void adis16240_uninitialize_ring(struct iio_ring_buffer *ring) -{ -} - #endif /* CONFIG_IIO_RING_BUFFER */ #endif /* SPI_ADIS16240_H_ */ diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c index 54fd6d77412..3e9531dd000 100644 --- a/drivers/staging/iio/accel/adis16240_core.c +++ b/drivers/staging/iio/accel/adis16240_core.c @@ -14,12 +14,13 @@ #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 "../iio.h" #include "../sysfs.h" +#include "../ring_generic.h" #include "accel.h" #include "../adc/adc.h" @@ -74,13 +75,13 @@ static int adis16240_spi_write_reg_16(struct device *dev, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, { .tx_buf = st->tx + 2, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, }; @@ -120,13 +121,13 @@ static int adis16240_spi_read_reg_16(struct device *dev, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, { .rx_buf = st->rx, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, }; @@ -502,7 +503,7 @@ static int __devinit adis16240_probe(struct spi_device *spi) goto error_unreg_ring_funcs; regdone = 1; - ret = adis16240_initialize_ring(st->indio_dev->ring); + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); if (ret) { printk(KERN_ERR "failed to initialize the ring\n"); goto error_unreg_ring_funcs; @@ -534,7 +535,7 @@ error_unregister_line: if (spi->irq) iio_unregister_interrupt_line(st->indio_dev, 0); error_uninitialize_ring: - adis16240_uninitialize_ring(st->indio_dev->ring); + iio_ring_buffer_unregister(st->indio_dev->ring); error_unreg_ring_funcs: adis16240_unconfigure_ring(st->indio_dev); error_free_dev: @@ -563,7 +564,7 @@ static int adis16240_remove(struct spi_device *spi) if (spi->irq) iio_unregister_interrupt_line(indio_dev, 0); - adis16240_uninitialize_ring(indio_dev->ring); + iio_ring_buffer_unregister(indio_dev->ring); iio_device_unregister(indio_dev); adis16240_unconfigure_ring(indio_dev); kfree(st->tx); diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c index 26b677bd84c..cd69a2e2bb9 100644 --- a/drivers/staging/iio/accel/adis16240_ring.c +++ b/drivers/staging/iio/accel/adis16240_ring.c @@ -6,6 +6,7 @@ #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> @@ -16,16 +17,6 @@ #include "../trigger.h" #include "adis16240.h" -/** - * combine_8_to_16() utility function to munge to u8s into u16 - **/ -static inline u16 combine_8_to_16(u8 lower, u8 upper) -{ - u16 _lower = lower; - u16 _upper = upper; - return _lower | (_upper << 8); -} - static IIO_SCAN_EL_C(supply, ADIS16240_SCAN_SUPPLY, IIO_UNSIGNED(10), ADIS16240_SUPPLY_OUT, NULL); static IIO_SCAN_EL_C(accel_x, ADIS16240_SCAN_ACC_X, IIO_SIGNED(10), @@ -61,10 +52,10 @@ static struct attribute_group adis16240_scan_el_group = { * adis16240_poll_func_th() top half interrupt handler called by trigger * @private_data: iio_dev **/ -static void adis16240_poll_func_th(struct iio_dev *indio_dev) +static void adis16240_poll_func_th(struct iio_dev *indio_dev, s64 time) { struct adis16240_state *st = iio_dev_get_devdata(indio_dev); - st->last_timestamp = indio_dev->trig->timestamp; + st->last_timestamp = time; schedule_work(&st->work_trigger_to_ring); } @@ -130,10 +121,9 @@ static void adis16240_trigger_bh_to_ring(struct work_struct *work_s) if (st->indio_dev->scan_count) if (adis16240_read_ring_data(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) { - data[i] = combine_8_to_16(st->rx[i*2+1], - st->rx[i*2]); - } + for (; i < st->indio_dev->scan_count; i++) + data[i] = be16_to_cpup( + (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ if (st->indio_dev->scan_timestamp) @@ -149,48 +139,6 @@ static void adis16240_trigger_bh_to_ring(struct work_struct *work_s) return; } -static int adis16240_data_rdy_ring_preenable(struct iio_dev *indio_dev) -{ - size_t size; - dev_dbg(&indio_dev->dev, "%s\n", __func__); - /* Check if there are any scan elements enabled, if not fail*/ - if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) - return -EINVAL; - - if (indio_dev->ring->access.set_bpd) { - if (indio_dev->scan_timestamp) - if (indio_dev->scan_count) - /* Timestamp (aligned sizeof(s64) and data */ - size = (((indio_dev->scan_count * sizeof(s16)) - + sizeof(s64) - 1) - & ~(sizeof(s64) - 1)) - + sizeof(s64); - else /* Timestamp only */ - size = sizeof(s64); - else /* Data only */ - size = indio_dev->scan_count*sizeof(s16); - indio_dev->ring->access.set_bpd(indio_dev->ring, size); - } - - return 0; -} - -static int adis16240_data_rdy_ring_postenable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_attach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - -static int adis16240_data_rdy_ring_predisable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_dettach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - void adis16240_unconfigure_ring(struct iio_dev *indio_dev) { kfree(indio_dev->pollfunc); @@ -223,18 +171,16 @@ int adis16240_configure_ring(struct iio_dev *indio_dev) indio_dev->ring = ring; /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); - ring->preenable = &adis16240_data_rdy_ring_preenable; - ring->postenable = &adis16240_data_rdy_ring_postenable; - ring->predisable = &adis16240_data_rdy_ring_predisable; + ring->bpe = 2; + ring->preenable = &iio_sw_ring_preenable; + ring->postenable = &iio_triggered_ring_postenable; + ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; - indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); - if (indio_dev->pollfunc == NULL) { - ret = -ENOMEM; - goto error_iio_sw_rb_free;; - } - indio_dev->pollfunc->poll_func_main = &adis16240_poll_func_th; - indio_dev->pollfunc->private_data = indio_dev; + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16240_poll_func_th); + if (ret) + goto error_iio_sw_rb_free; + indio_dev->modes |= INDIO_RING_TRIGGERED; return 0; @@ -243,12 +189,3 @@ error_iio_sw_rb_free: return ret; } -int adis16240_initialize_ring(struct iio_ring_buffer *ring) -{ - return iio_ring_buffer_register(ring, 0); -} - -void adis16240_uninitialize_ring(struct iio_ring_buffer *ring) -{ - iio_ring_buffer_unregister(ring); -} diff --git a/drivers/staging/iio/accel/adis16240_trigger.c b/drivers/staging/iio/accel/adis16240_trigger.c index df1312e17f4..2ba71fd73a4 100644 --- a/drivers/staging/iio/accel/adis16240_trigger.c +++ b/drivers/staging/iio/accel/adis16240_trigger.c @@ -23,8 +23,7 @@ static int adis16240_data_rdy_trig_poll(struct iio_dev *dev_info, struct adis16240_state *st = iio_dev_get_devdata(dev_info); struct iio_trigger *trig = st->trig; - trig->timestamp = timestamp; - iio_trigger_poll(trig); + iio_trigger_poll(trig, timestamp); return IRQ_HANDLED; } @@ -83,14 +82,13 @@ int adis16240_probe_trigger(struct iio_dev *indio_dev) struct adis16240_state *st = indio_dev->dev_data; st->trig = iio_allocate_trigger(); - st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); + st->trig->name = kasprintf(GFP_KERNEL, + "adis16240-dev%d", + indio_dev->id); if (!st->trig->name) { ret = -ENOMEM; goto error_free_trig; } - snprintf((char *)st->trig->name, - IIO_TRIGGER_NAME_LENGTH, - "adis16240-dev%d", indio_dev->id); st->trig->dev.parent = &st->us->dev; st->trig->owner = THIS_MODULE; st->trig->private_data = st; diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/staging/iio/accel/kxsd9.c index ae7ffe114fc..79f57950ebe 100644 --- a/drivers/staging/iio/accel/kxsd9.c +++ b/drivers/staging/iio/accel/kxsd9.c @@ -16,17 +16,11 @@ * heavily optimized ring buffer access function. */ -#include <linux/interrupt.h> -#include <linux/gpio.h> -#include <linux/fs.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/spi/spi.h> #include <linux/sysfs.h> -#include <linux/rtc.h> -#include <linux/delay.h> #include <linux/slab.h> -#include <linux/string.h> #include "../iio.h" #include "../sysfs.h" diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h index e76a97937a3..6e730553fca 100644 --- a/drivers/staging/iio/accel/lis3l02dq.h +++ b/drivers/staging/iio/accel/lis3l02dq.h @@ -148,30 +148,31 @@ Form of high byte dependant on justification set in ctrl reg */ #define LIS3L02DQ_MAX_RX 12 /** * struct lis3l02dq_state - device instance specific data + * @helper: data and func pointer allowing generic functions * @us: actual spi_device - * @work_trigger_to_ring: bh for triggered event handling - * @work_cont_thresh: CLEAN + * @work_thresh: bh for threshold events + * @thresh_timestamp: timestamp for threshold interrupts. * @inter: used to check if new interrupt has been triggered - * @last_timestamp: passing timestamp from th to bh of interrupt handler - * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer * @rx: recieve buffer * @buf_lock: mutex to protect tx and rx **/ struct lis3l02dq_state { + struct iio_sw_ring_helper_state help; struct spi_device *us; - struct work_struct work_trigger_to_ring; - struct iio_work_cont work_cont_thresh; + struct work_struct work_thresh; + s64 thresh_timestamp; bool inter; - s64 last_timestamp; - struct iio_dev *indio_dev; struct iio_trigger *trig; u8 *tx; u8 *rx; struct mutex buf_lock; }; +#define lis3l02dq_h_to_s(_h) \ + container_of(_h, struct lis3l02dq_state, help) + int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val); @@ -195,15 +196,15 @@ ssize_t lis3l02dq_read_accel_from_ring(struct device *dev, int lis3l02dq_configure_ring(struct iio_dev *indio_dev); void lis3l02dq_unconfigure_ring(struct iio_dev *indio_dev); -int lis3l02dq_initialize_ring(struct iio_ring_buffer *ring); -void lis3l02dq_uninitialize_ring(struct iio_ring_buffer *ring); #else /* CONFIG_IIO_RING_BUFFER */ -static inline void lis3l02dq_remove_trigger(struct iio_dev *indio_dev) {}; +static inline void lis3l02dq_remove_trigger(struct iio_dev *indio_dev) +{ +} static inline int lis3l02dq_probe_trigger(struct iio_dev *indio_dev) { return 0; -}; +} static inline ssize_t lis3l02dq_read_accel_from_ring(struct device *dev, @@ -211,18 +212,14 @@ lis3l02dq_read_accel_from_ring(struct device *dev, char *buf) { return 0; -}; +} static int lis3l02dq_configure_ring(struct iio_dev *indio_dev) { return 0; -}; +} static inline void lis3l02dq_unconfigure_ring(struct iio_dev *indio_dev) -{}; -static inline int lis3l02dq_initialize_ring(struct iio_ring_buffer *ring) { - return 0; -}; -static inline void lis3l02dq_uninitialize_ring(struct iio_ring_buffer *ring) {}; +} #endif /* CONFIG_IIO_RING_BUFFER */ #endif /* SPI_LIS3L02DQ_H_ */ diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index 6b5577d7d8d..0ee93373754 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -27,6 +27,9 @@ #include "../iio.h" #include "../sysfs.h" +#include "../ring_generic.h" +#include "../ring_sw.h" + #include "accel.h" #include "lis3l02dq.h" @@ -47,7 +50,9 @@ int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) int ret; struct spi_message msg; struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct lis3l02dq_state *st = iio_dev_get_devdata(indio_dev); + struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev); + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h); + struct spi_transfer xfer = { .tx_buf = st->tx, .rx_buf = st->rx, @@ -82,7 +87,9 @@ int lis3l02dq_spi_write_reg_8(struct device *dev, int ret; struct spi_message msg; struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct lis3l02dq_state *st = iio_dev_get_devdata(indio_dev); + struct iio_sw_ring_helper_state *h + = iio_dev_get_devdata(indio_dev); + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h); struct spi_transfer xfer = { .tx_buf = st->tx, .bits_per_word = 8, @@ -96,7 +103,7 @@ int lis3l02dq_spi_write_reg_8(struct device *dev, spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync(st->us, &msg); mutex_unlock(&st->buf_lock); return ret; @@ -116,7 +123,9 @@ static int lis3l02dq_spi_write_reg_s16(struct device *dev, int ret; struct spi_message msg; struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct lis3l02dq_state *st = iio_dev_get_devdata(indio_dev); + struct iio_sw_ring_helper_state *h + = iio_dev_get_devdata(indio_dev); + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h); struct spi_transfer xfers[] = { { .tx_buf = st->tx, .bits_per_word = 8, @@ -158,7 +167,9 @@ static int lis3l02dq_spi_read_reg_s16(struct device *dev, { struct spi_message msg; struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct lis3l02dq_state *st = iio_dev_get_devdata(indio_dev); + struct iio_sw_ring_helper_state *h + = iio_dev_get_devdata(indio_dev); + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h); int ret; struct spi_transfer xfers[] = { { .tx_buf = st->tx, @@ -411,7 +422,7 @@ static int lis3l02dq_initial_setup(struct lis3l02dq_state *st) val = LIS3L02DQ_DEFAULT_CTRL1; /* Write suitable defaults to ctrl1 */ - ret = lis3l02dq_spi_write_reg_8(&st->indio_dev->dev, + ret = lis3l02dq_spi_write_reg_8(&st->help.indio_dev->dev, LIS3L02DQ_REG_CTRL_1_ADDR, &val); if (ret) { @@ -419,7 +430,7 @@ static int lis3l02dq_initial_setup(struct lis3l02dq_state *st) goto err_ret; } /* Repeat as sometimes doesn't work first time?*/ - ret = lis3l02dq_spi_write_reg_8(&st->indio_dev->dev, + ret = lis3l02dq_spi_write_reg_8(&st->help.indio_dev->dev, LIS3L02DQ_REG_CTRL_1_ADDR, &val); if (ret) { @@ -429,17 +440,17 @@ static int lis3l02dq_initial_setup(struct lis3l02dq_state *st) /* Read back to check this has worked acts as loose test of correct * chip */ - ret = lis3l02dq_spi_read_reg_8(&st->indio_dev->dev, + ret = lis3l02dq_spi_read_reg_8(&st->help.indio_dev->dev, LIS3L02DQ_REG_CTRL_1_ADDR, &valtest); if (ret || (valtest != val)) { - dev_err(&st->indio_dev->dev, "device not playing ball"); + dev_err(&st->help.indio_dev->dev, "device not playing ball"); ret = -EINVAL; goto err_ret; } val = LIS3L02DQ_DEFAULT_CTRL2; - ret = lis3l02dq_spi_write_reg_8(&st->indio_dev->dev, + ret = lis3l02dq_spi_write_reg_8(&st->help.indio_dev->dev, LIS3L02DQ_REG_CTRL_2_ADDR, &val); if (ret) { @@ -448,7 +459,7 @@ static int lis3l02dq_initial_setup(struct lis3l02dq_state *st) } val = LIS3L02DQ_REG_WAKE_UP_CFG_LATCH_SRC; - ret = lis3l02dq_spi_write_reg_8(&st->indio_dev->dev, + ret = lis3l02dq_spi_write_reg_8(&st->help.indio_dev->dev, LIS3L02DQ_REG_WAKE_UP_CFG_ADDR, &val); if (ret) @@ -524,8 +535,7 @@ static ssize_t lis3l02dq_read_interrupt_config(struct device *dev, LIS3L02DQ_REG_WAKE_UP_CFG_ADDR, (u8 *)&val); - return ret ? ret : sprintf(buf, "%d\n", - (val & this_attr->mask) ? 1 : 0);; + return ret ? ret : sprintf(buf, "%d\n", !!(val & this_attr->mask)); } static ssize_t lis3l02dq_write_interrupt_config(struct device *dev, @@ -595,16 +605,18 @@ error_mutex_unlock: } -static int lis3l02dq_thresh_handler_th(struct iio_dev *dev_info, +static int lis3l02dq_thresh_handler_th(struct iio_dev *indio_dev, int index, s64 timestamp, int no_test) { - struct lis3l02dq_state *st = dev_info->dev_data; + struct iio_sw_ring_helper_state *h + = iio_dev_get_devdata(indio_dev); + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h); /* Stash the timestamp somewhere convenient for the bh */ - st->last_timestamp = timestamp; - schedule_work(&st->work_cont_thresh.ws); + st->thresh_timestamp = timestamp; + schedule_work(&st->work_thresh); return 0; } @@ -615,48 +627,49 @@ static int lis3l02dq_thresh_handler_th(struct iio_dev *dev_info, */ static void lis3l02dq_thresh_handler_bh_no_check(struct work_struct *work_s) { - struct iio_work_cont *wc - = container_of(work_s, struct iio_work_cont, ws); - struct lis3l02dq_state *st = wc->st; + struct lis3l02dq_state *st + = container_of(work_s, + struct lis3l02dq_state, work_thresh); + u8 t; - lis3l02dq_spi_read_reg_8(&st->indio_dev->dev, + lis3l02dq_spi_read_reg_8(&st->help.indio_dev->dev, LIS3L02DQ_REG_WAKE_UP_SRC_ADDR, &t); if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_HIGH) - iio_push_event(st->indio_dev, 0, + iio_push_event(st->help.indio_dev, 0, IIO_EVENT_CODE_ACCEL_Z_HIGH, - st->last_timestamp); + st->thresh_timestamp); if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_LOW) - iio_push_event(st->indio_dev, 0, + iio_push_event(st->help.indio_dev, 0, IIO_EVENT_CODE_ACCEL_Z_LOW, - st->last_timestamp); + st->thresh_timestamp); if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_HIGH) - iio_push_event(st->indio_dev, 0, + iio_push_event(st->help.indio_dev, 0, IIO_EVENT_CODE_ACCEL_Y_HIGH, - st->last_timestamp); + st->thresh_timestamp); if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_LOW) - iio_push_event(st->indio_dev, 0, + iio_push_event(st->help.indio_dev, 0, IIO_EVENT_CODE_ACCEL_Y_LOW, - st->last_timestamp); + st->thresh_timestamp); if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_HIGH) - iio_push_event(st->indio_dev, 0, + iio_push_event(st->help.indio_dev, 0, IIO_EVENT_CODE_ACCEL_X_HIGH, - st->last_timestamp); + st->thresh_timestamp); if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_LOW) - iio_push_event(st->indio_dev, 0, + iio_push_event(st->help.indio_dev, 0, IIO_EVENT_CODE_ACCEL_X_LOW, - st->last_timestamp); + st->thresh_timestamp); /* reenable the irq */ enable_irq(st->us->irq); /* Ack and allow for new interrupts */ - lis3l02dq_spi_read_reg_8(&st->indio_dev->dev, + lis3l02dq_spi_read_reg_8(&st->help.indio_dev->dev, LIS3L02DQ_REG_WAKE_UP_ACK_ADDR, &t); @@ -750,6 +763,7 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi) ret = -ENOMEM; goto error_ret; } + INIT_WORK(&st->work_thresh, lis3l02dq_thresh_handler_bh_no_check); /* this is only used tor removal purposes */ spi_set_drvdata(spi, st); @@ -767,56 +781,46 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi) st->us = spi; mutex_init(&st->buf_lock); /* setup the industrialio driver allocated elements */ - st->indio_dev = iio_allocate_device(); - if (st->indio_dev == NULL) { + st->help.indio_dev = iio_allocate_device(); + if (st->help.indio_dev == NULL) { ret = -ENOMEM; goto error_free_tx; } - st->indio_dev->dev.parent = &spi->dev; - st->indio_dev->num_interrupt_lines = 1; - st->indio_dev->event_attrs = &lis3l02dq_event_attribute_group; - st->indio_dev->attrs = &lis3l02dq_attribute_group; - st->indio_dev->dev_data = (void *)(st); - st->indio_dev->driver_module = THIS_MODULE; - st->indio_dev->modes = INDIO_DIRECT_MODE; + st->help.indio_dev->dev.parent = &spi->dev; + st->help.indio_dev->num_interrupt_lines = 1; + st->help.indio_dev->event_attrs = &lis3l02dq_event_attribute_group; + st->help.indio_dev->attrs = &lis3l02dq_attribute_group; + st->help.indio_dev->dev_data = (void *)(&st->help); + st->help.indio_dev->driver_module = THIS_MODULE; + st->help.indio_dev->modes = INDIO_DIRECT_MODE; - ret = lis3l02dq_configure_ring(st->indio_dev); + ret = lis3l02dq_configure_ring(st->help.indio_dev); if (ret) goto error_free_dev; - ret = iio_device_register(st->indio_dev); + ret = iio_device_register(st->help.indio_dev); if (ret) goto error_unreg_ring_funcs; regdone = 1; - ret = lis3l02dq_initialize_ring(st->indio_dev->ring); + ret = iio_ring_buffer_register(st->help.indio_dev->ring, 0); if (ret) { printk(KERN_ERR "failed to initialize the ring\n"); goto error_unreg_ring_funcs; } if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) { - /* This is a little unusual, in that the device seems - to need a full read of the interrupt source reg before - the interrupt will reset. - Hence the two handlers are the same */ - iio_init_work_cont(&st->work_cont_thresh, - lis3l02dq_thresh_handler_bh_no_check, - lis3l02dq_thresh_handler_bh_no_check, - LIS3L02DQ_REG_WAKE_UP_SRC_ADDR, - 0, - st); st->inter = 0; ret = iio_register_interrupt_line(spi->irq, - st->indio_dev, + st->help.indio_dev, 0, IRQF_TRIGGER_RISING, "lis3l02dq"); if (ret) goto error_uninitialize_ring; - ret = lis3l02dq_probe_trigger(st->indio_dev); + ret = lis3l02dq_probe_trigger(st->help.indio_dev); if (ret) goto error_unregister_line; } @@ -828,20 +832,20 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi) return 0; error_remove_trigger: - if (st->indio_dev->modes & INDIO_RING_TRIGGERED) - lis3l02dq_remove_trigger(st->indio_dev); + if (st->help.indio_dev->modes & INDIO_RING_TRIGGERED) + lis3l02dq_remove_trigger(st->help.indio_dev); error_unregister_line: - if (st->indio_dev->modes & INDIO_RING_TRIGGERED) - iio_unregister_interrupt_line(st->indio_dev, 0); + if (st->help.indio_dev->modes & INDIO_RING_TRIGGERED) + iio_unregister_interrupt_line(st->help.indio_dev, 0); error_uninitialize_ring: - lis3l02dq_uninitialize_ring(st->indio_dev->ring); + iio_ring_buffer_unregister(st->help.indio_dev->ring); error_unreg_ring_funcs: - lis3l02dq_unconfigure_ring(st->indio_dev); + lis3l02dq_unconfigure_ring(st->help.indio_dev); error_free_dev: if (regdone) - iio_device_unregister(st->indio_dev); + iio_device_unregister(st->help.indio_dev); else - iio_free_device(st->indio_dev); + iio_free_device(st->help.indio_dev); error_free_tx: kfree(st->tx); error_free_rx: @@ -856,7 +860,9 @@ error_ret: static int lis3l02dq_stop_device(struct iio_dev *indio_dev) { int ret; - struct lis3l02dq_state *st = indio_dev->dev_data; + struct iio_sw_ring_helper_state *h + = iio_dev_get_devdata(indio_dev); + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h); u8 val = 0; mutex_lock(&indio_dev->mlock); @@ -883,7 +889,7 @@ static int lis3l02dq_remove(struct spi_device *spi) { int ret; struct lis3l02dq_state *st = spi_get_drvdata(spi); - struct iio_dev *indio_dev = st->indio_dev; + struct iio_dev *indio_dev = st->help.indio_dev; ret = lis3l02dq_stop_device(indio_dev); if (ret) @@ -895,7 +901,7 @@ static int lis3l02dq_remove(struct spi_device *spi) if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) iio_unregister_interrupt_line(indio_dev, 0); - lis3l02dq_uninitialize_ring(indio_dev->ring); + iio_ring_buffer_unregister(indio_dev->ring); lis3l02dq_unconfigure_ring(indio_dev); iio_device_unregister(indio_dev); kfree(st->tx); diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index e4e202e6cb3..a960a8ff3c4 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -103,13 +103,15 @@ static struct attribute_group lis3l02dq_scan_el_group = { * lis3l02dq_poll_func_th() top half interrupt handler called by trigger * @private_data: iio_dev **/ -static void lis3l02dq_poll_func_th(struct iio_dev *indio_dev) +static void lis3l02dq_poll_func_th(struct iio_dev *indio_dev, s64 time) { - struct lis3l02dq_state *st = iio_dev_get_devdata(indio_dev); - st->last_timestamp = indio_dev->trig->timestamp; - schedule_work(&st->work_trigger_to_ring); - /* Indicate that this interrupt is being handled */ + struct iio_sw_ring_helper_state *h + = iio_dev_get_devdata(indio_dev); + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h); + /* in this case we need to slightly extend the helper function */ + iio_sw_poll_func_th(indio_dev, time); + /* Indicate that this interrupt is being handled */ /* Technically this is trigger related, but without this * handler running there is currently now way for the interrupt * to clear. @@ -120,16 +122,16 @@ static void lis3l02dq_poll_func_th(struct iio_dev *indio_dev) /** * lis3l02dq_data_rdy_trig_poll() the event handler for the data rdy trig **/ -static int lis3l02dq_data_rdy_trig_poll(struct iio_dev *dev_info, +static int lis3l02dq_data_rdy_trig_poll(struct iio_dev *indio_dev, int index, s64 timestamp, int no_test) { - struct lis3l02dq_state *st = iio_dev_get_devdata(dev_info); - struct iio_trigger *trig = st->trig; + struct iio_sw_ring_helper_state *h + = iio_dev_get_devdata(indio_dev); + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h); - trig->timestamp = timestamp; - iio_trigger_poll(trig); + iio_trigger_poll(st->trig, timestamp); return IRQ_HANDLED; } @@ -213,7 +215,7 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array) struct spi_message msg; int ret, i, j = 0; - xfers = kzalloc((st->indio_dev->scan_count) * 2 + xfers = kzalloc((st->help.indio_dev->scan_count) * 2 * sizeof(*xfers), GFP_KERNEL); if (!xfers) return -ENOMEM; @@ -221,7 +223,7 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array) mutex_lock(&st->buf_lock); for (i = 0; i < ARRAY_SIZE(read_all_tx_array)/4; i++) { - if (st->indio_dev->scan_mask & (1 << i)) { + if (st->help.indio_dev->scan_mask & (1 << i)) { /* lower byte */ xfers[j].tx_buf = st->tx + 2*j; st->tx[2*j] = read_all_tx_array[i*4]; @@ -249,7 +251,7 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array) * values in alternate bytes */ spi_message_init(&msg); - for (j = 0; j < st->indio_dev->scan_count * 2; j++) + for (j = 0; j < st->help.indio_dev->scan_count * 2; j++) spi_message_add_tail(&xfers[j], &msg); ret = spi_sync(st->us, &msg); @@ -259,102 +261,37 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array) 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 void lis3l02dq_trigger_bh_to_ring(struct work_struct *work_s) { - struct lis3l02dq_state *st - = container_of(work_s, struct lis3l02dq_state, - work_trigger_to_ring); - - u8 *rx_array; - int i = 0; - u16 *data; - size_t datasize = st->indio_dev - ->ring->access.get_bpd(st->indio_dev->ring); - - data = kmalloc(datasize , GFP_KERNEL); - if (data == NULL) { - dev_err(&st->us->dev, "memory alloc failed in ring bh"); - return; - } - /* Due to interleaved nature of transmission this buffer must be - * twice the number of bytes, or 4 times the number of channels - */ - rx_array = kmalloc(4 * (st->indio_dev->scan_count), GFP_KERNEL); - if (rx_array == NULL) { - dev_err(&st->us->dev, "memory alloc failed in ring bh"); - kfree(data); - return; - } + struct iio_sw_ring_helper_state *h + = container_of(work_s, struct iio_sw_ring_helper_state, + work_trigger_to_ring); + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h); - /* whilst trigger specific, if this read does nto occur the data - ready interrupt will not be cleared. Need to add a mechanism - to provide a dummy read function if this is not triggering on - the data ready function but something else is. - */ st->inter = 0; - - if (st->indio_dev->scan_count) - if (lis3l02dq_read_all(st, rx_array) >= 0) - for (; i < st->indio_dev->scan_count; i++) - data[i] = combine_8_to_16(rx_array[i*4+1], - rx_array[i*4+3]); - /* Guaranteed to be aligned with 8 byte boundary */ - if (st->indio_dev->scan_timestamp) - *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; - - st->indio_dev->ring->access.store_to(st->indio_dev->ring, - (u8 *)data, - st->last_timestamp); - - iio_trigger_notify_done(st->indio_dev->trig); - kfree(rx_array); - kfree(data); - - return; -} -/* in these circumstances is it better to go with unaligned packing and - * deal with the cost?*/ -static int lis3l02dq_data_rdy_ring_preenable(struct iio_dev *indio_dev) -{ - size_t size; - /* Check if there are any scan elements enabled, if not fail*/ - if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) - return -EINVAL; - - if (indio_dev->ring->access.set_bpd) { - if (indio_dev->scan_timestamp) - if (indio_dev->scan_count) /* Timestamp and data */ - size = 2*sizeof(s64); - else /* Timestamp only */ - size = sizeof(s64); - else /* Data only */ - size = indio_dev->scan_count*sizeof(s16); - indio_dev->ring->access.set_bpd(indio_dev->ring, size); - } - - return 0; + iio_sw_trigger_bh_to_ring(work_s); } -static int lis3l02dq_data_rdy_ring_postenable(struct iio_dev *indio_dev) +static int lis3l02dq_get_ring_element(struct iio_sw_ring_helper_state *h, + u8 *buf) { - return indio_dev->trig - ? iio_trigger_attach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} + int ret, i; + u8 *rx_array ; + s16 *data = (s16 *)buf; -static int lis3l02dq_data_rdy_ring_predisable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_dettach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} + rx_array = kzalloc(4 * (h->indio_dev->scan_count), GFP_KERNEL); + if (rx_array == NULL) + return -ENOMEM; + ret = lis3l02dq_read_all(lis3l02dq_h_to_s(h), rx_array); + if (ret < 0) + return ret; + for (i = 0; i < h->indio_dev->scan_count; i++) + data[i] = combine_8_to_16(rx_array[i*4+1], + rx_array[i*4+3]); + kfree(rx_array); + return i*sizeof(data[0]); +} /* Caller responsible for locking as necessary. */ static int @@ -427,7 +364,7 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig, struct lis3l02dq_state *st = trig->private_data; int ret = 0; u8 t; - __lis3l02dq_write_data_ready_config(&st->indio_dev->dev, + __lis3l02dq_write_data_ready_config(&st->help.indio_dev->dev, &iio_event_data_rdy_trig, state); if (state == false) { @@ -437,7 +374,7 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig, /* Clear any outstanding ready events */ ret = lis3l02dq_read_all(st, NULL); } - lis3l02dq_spi_read_reg_8(&st->indio_dev->dev, + lis3l02dq_spi_read_reg_8(&st->help.indio_dev->dev, LIS3L02DQ_REG_WAKE_UP_SRC_ADDR, &t); return ret; @@ -495,14 +432,14 @@ int lis3l02dq_probe_trigger(struct iio_dev *indio_dev) if (!state->trig) return -ENOMEM; - state->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); + state->trig->name = kasprintf(GFP_KERNEL, + "lis3l02dq-dev%d", + indio_dev->id); if (!state->trig->name) { ret = -ENOMEM; goto error_free_trig; } - snprintf((char *)state->trig->name, - IIO_TRIGGER_NAME_LENGTH, - "lis3l02dq-dev%d", indio_dev->id); + state->trig->dev.parent = &state->us->dev; state->trig->owner = THIS_MODULE; state->trig->private_data = state; @@ -540,12 +477,12 @@ void lis3l02dq_unconfigure_ring(struct iio_dev *indio_dev) int lis3l02dq_configure_ring(struct iio_dev *indio_dev) { - int ret = 0; - struct lis3l02dq_state *st = indio_dev->dev_data; - struct iio_ring_buffer *ring; - INIT_WORK(&st->work_trigger_to_ring, lis3l02dq_trigger_bh_to_ring); - /* Set default scan mode */ + int ret; + struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev); + INIT_WORK(&h->work_trigger_to_ring, lis3l02dq_trigger_bh_to_ring); + /* Set default scan mode */ + h->get_ring_element = &lis3l02dq_get_ring_element; iio_scan_mask_set(indio_dev, iio_scan_el_accel_x.number); iio_scan_mask_set(indio_dev, iio_scan_el_accel_y.number); iio_scan_mask_set(indio_dev, iio_scan_el_accel_z.number); @@ -553,26 +490,21 @@ int lis3l02dq_configure_ring(struct iio_dev *indio_dev) indio_dev->scan_el_attrs = &lis3l02dq_scan_el_group; - ring = iio_sw_rb_allocate(indio_dev); - if (!ring) { - ret = -ENOMEM; - return ret; - } - indio_dev->ring = ring; + indio_dev->ring = iio_sw_rb_allocate(indio_dev); + if (!indio_dev->ring) + return -ENOMEM; + /* Effectively select the ring buffer implementation */ - iio_ring_sw_register_funcs(&ring->access); - ring->preenable = &lis3l02dq_data_rdy_ring_preenable; - ring->postenable = &lis3l02dq_data_rdy_ring_postenable; - ring->predisable = &lis3l02dq_data_rdy_ring_predisable; - ring->owner = THIS_MODULE; - - indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); - if (indio_dev->pollfunc == NULL) { - ret = -ENOMEM; + iio_ring_sw_register_funcs(&indio_dev->ring->access); + indio_dev->ring->bpe = 2; + indio_dev->ring->preenable = &iio_sw_ring_preenable; + indio_dev->ring->postenable = &iio_triggered_ring_postenable; + indio_dev->ring->predisable = &iio_triggered_ring_predisable; + indio_dev->ring->owner = THIS_MODULE; + + ret = iio_alloc_pollfunc(indio_dev, NULL, &lis3l02dq_poll_func_th); + if (ret) goto error_iio_sw_rb_free;; - } - indio_dev->pollfunc->poll_func_main = &lis3l02dq_poll_func_th; - indio_dev->pollfunc->private_data = indio_dev; indio_dev->modes |= INDIO_RING_TRIGGERED; return 0; @@ -580,23 +512,3 @@ error_iio_sw_rb_free: iio_sw_rb_free(indio_dev->ring); return ret; } - -int lis3l02dq_initialize_ring(struct iio_ring_buffer *ring) -{ - return iio_ring_buffer_register(ring, 0); -} - -void lis3l02dq_uninitialize_ring(struct iio_ring_buffer *ring) -{ - iio_ring_buffer_unregister(ring); -} - -int lis3l02dq_set_ring_length(struct iio_dev *indio_dev, int length) -{ - /* Set sensible defaults for the ring buffer */ - if (indio_dev->ring->access.set_length) - return indio_dev->ring->access.set_length(indio_dev->ring, 500); - return 0; -} - - diff --git a/drivers/staging/iio/accel/sca3000.h b/drivers/staging/iio/accel/sca3000.h index e5321999b26..09d9470bb9a 100644 --- a/drivers/staging/iio/accel/sca3000.h +++ b/drivers/staging/iio/accel/sca3000.h @@ -242,7 +242,7 @@ static inline int sca3000_11bit_convert(uint8_t msb, uint8_t lsb) val |= (val & (1 << 12)) ? 0xE000 : 0; return val; -}; +} static inline int sca3000_13bit_convert(uint8_t msb, uint8_t lsb) { @@ -253,7 +253,7 @@ static inline int sca3000_13bit_convert(uint8_t msb, uint8_t lsb) val |= (val & (1 << 12)) ? 0xE000 : 0; return val; -}; +} #ifdef CONFIG_IIO_RING_BUFFER @@ -286,15 +286,19 @@ void sca3000_unconfigure_ring(struct iio_dev *indio_dev); void sca3000_ring_int_process(u8 val, struct iio_ring_buffer *ring); #else -static inline void sca3000_register_ring_funcs(struct iio_dev *indio_dev) {}; +static inline void sca3000_register_ring_funcs(struct iio_dev *indio_dev) +{ +} static inline int sca3000_register_ring_access_and_init(struct iio_dev *indio_dev) { return 0; -}; +} -static inline void sca3000_ring_int_process(u8 val, void *ring) {}; +static inline void sca3000_ring_int_process(u8 val, void *ring) +{ +} #endif diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index d4f82c39f33..b78b6b66ffe 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -387,7 +387,7 @@ sca3000_show_available_measurement_modes(struct device *dev, case SCA3000_OP_MODE_BYPASS: len += sprintf(buf + len, ", 1 - bypass mode"); break; - }; + } switch (st->info->option_mode_2) { case SCA3000_OP_MODE_WIDE: len += sprintf(buf + len, ", 2 - wide mode"); @@ -433,7 +433,7 @@ sca3000_show_measurement_mode(struct device *dev, case SCA3000_OP_MODE_BYPASS: len += sprintf(buf + len, "1 - bypass mode\n"); break; - }; + } break; case SCA3000_MEAS_MODE_OP_2: switch (st->info->option_mode_2) { @@ -442,7 +442,7 @@ sca3000_show_measurement_mode(struct device *dev, break; } break; - }; + } error_ret: mutex_unlock(&st->lock); @@ -559,7 +559,7 @@ static ssize_t sca3000_read_av_freq(struct device *dev, st->info->option_mode_2_freq/2, st->info->option_mode_2_freq/4); break; - }; + } kfree(rx); return len; error_ret: @@ -590,7 +590,7 @@ static inline int __sca3000_get_base_freq(struct sca3000_state *st, case SCA3000_MEAS_MODE_OP_2: *base_freq = info->option_mode_2_freq; break; - }; + } kfree(rx); error_ret: return ret; @@ -627,8 +627,8 @@ static ssize_t sca3000_read_frequency(struct device *dev, case 0x02: len = sprintf(buf, "%d\n", base_freq/4); break; - }; - kfree(rx); + } + kfree(rx); return len; error_ret_mut: mutex_unlock(&st->lock); diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 18c9376ecbb..688510fd8bb 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -1,4 +1,4 @@ - +# # Makefile for industrial I/O ADC drivers # diff --git a/drivers/staging/iio/adc/adc.h b/drivers/staging/iio/adc/adc.h index 04eb16fd0a9..7841e6ad434 100644 --- a/drivers/staging/iio/adc/adc.h +++ b/drivers/staging/iio/adc/adc.h @@ -26,3 +26,6 @@ _show, \ NULL, \ _addr) + +#define IIO_EVENT_CODE_IN_HIGH_THRESH(a) (IIO_EVENT_CODE_ADC_BASE + a) +#define IIO_EVENT_CODE_IN_LOW_THRESH(a) (IIO_EVENT_CODE_ADC_BASE + a + 32) diff --git a/drivers/staging/iio/adc/max1363.h b/drivers/staging/iio/adc/max1363.h index 72cf3670936..8f0fe1ced2c 100644 --- a/drivers/staging/iio/adc/max1363.h +++ b/drivers/staging/iio/adc/max1363.h @@ -32,14 +32,6 @@ /* Specific to the max1363 */ #define MAX1363_MON_RESET_CHAN(a) (1 << ((a) + 4)) -#define MAX1363_MON_CONV_RATE_133ksps 0 -#define MAX1363_MON_CONV_RATE_66_5ksps 0x02 -#define MAX1363_MON_CONV_RATE_33_3ksps 0x04 -#define MAX1363_MON_CONV_RATE_16_6ksps 0x06 -#define MAX1363_MON_CONV_RATE_8_3ksps 0x08 -#define MAX1363_MON_CONV_RATE_4_2ksps 0x0A -#define MAX1363_MON_CONV_RATE_2_0ksps 0x0C -#define MAX1363_MON_CONV_RATE_1_0ksps 0x0E #define MAX1363_MON_INT_ENABLE 0x01 /* defined for readability reasons */ @@ -67,9 +59,8 @@ /** * struct max1363_mode - scan mode information - * @name: Name used to identify the scan mode. * @conf: The corresponding value of the configuration register - * @numvals: The number of values returned by a single scan + * @modemask: Bit mask corresponding to channels enabled in this mode */ struct max1363_mode { int8_t conf; @@ -122,15 +113,6 @@ struct max1363_mode { .modemask = _mask \ } -/* Not currently handled */ -#define MAX1363_MODE_MONITOR { \ - .name = "monitor", \ - .conf = MAX1363_CHANNEL_SEL(3) \ - | MAX1363_CONFIG_SCAN_MONITOR_MODE \ - | MAX1363_CONFIG_SE, \ - .numvals = 10, \ - } - /* This may seem an overly long winded way to do this, but at least it makes * clear what all the various options actually do. Alternative suggestions * that don't require user to have intimate knowledge of the chip welcomed. @@ -147,7 +129,7 @@ enum max1363_channels { max1363_in1min0, max1363_in3min2, max1363_in5min4, max1363_in7min6, max1363_in9min8, max1363_in11min10, - }; +}; /* This must be maintained along side the max1363_mode_table in max1363_core */ enum max1363_modes { @@ -179,7 +161,6 @@ enum max1363_modes { * @default_mode: the scan mode in which the chip starts up */ struct max1363_chip_info { - const char *name; u8 num_inputs; u8 bits; u16 int_vref_mv; @@ -191,7 +172,6 @@ struct max1363_chip_info { struct attribute_group *scan_attrs; }; - /** * struct max1363_state - driver instance specific data * @indio_dev: the industrial I/O device @@ -204,12 +184,20 @@ struct max1363_chip_info { * @poll_work: bottom half of polling interrupt handler * @protect_ring: used to ensure only one polling bh running at a time * @reg: supply regulator + * @monitor_on: whether monitor mode is enabled + * @monitor_speed: parameter corresponding to device monitor speed setting + * @mask_high: bitmask for enabled high thresholds + * @mask_low: bitmask for enabled low thresholds + * @thresh_high: high threshold values + * @thresh_low: low threshold values + * @last_timestamp: timestamp of last event interrupt + * @thresh_work: bh work structure for event handling */ struct max1363_state { struct iio_dev *indio_dev; struct i2c_client *client; - char setupbyte; - char configbyte; + u8 setupbyte; + u8 configbyte; const struct max1363_chip_info *chip_info; const struct max1363_mode *current_mode; u32 requestedmask; @@ -217,6 +205,18 @@ struct max1363_state { atomic_t protect_ring; struct iio_trigger *trig; struct regulator *reg; + + /* Using monitor modes and buffer at the same time is + currently not supported */ + bool monitor_on; + unsigned int monitor_speed:3; + u8 mask_high; + u8 mask_low; + /* 4x unipolar first then the fours bipolar ones */ + s16 thresh_high[8]; + s16 thresh_low[8]; + s64 last_timestamp; + struct work_struct thresh_work; }; const struct max1363_mode @@ -230,32 +230,21 @@ int max1363_single_channel_from_ring(long mask, struct max1363_state *st); int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev); void max1363_ring_cleanup(struct iio_dev *indio_dev); -int max1363_initialize_ring(struct iio_ring_buffer *ring); -void max1363_uninitialize_ring(struct iio_ring_buffer *ring); - #else /* CONFIG_MAX1363_RING_BUFFER */ -static inline void max1363_uninitialize_ring(struct iio_ring_buffer *ring) -{ -}; - -static inline int max1363_initialize_ring(struct iio_ring_buffer *ring) -{ - return 0; -}; - int max1363_single_channel_from_ring(long mask, struct max1363_state *st) { return -EINVAL; -}; - +} static inline int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev) { return 0; -}; +} -static inline void max1363_ring_cleanup(struct iio_dev *indio_dev) {}; +static inline void max1363_ring_cleanup(struct iio_dev *indio_dev) +{ +} #endif /* CONFIG_MAX1363_RING_BUFFER */ #endif /* _MAX1363_H_ */ diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c index 905f8560d31..6435e509dd5 100644 --- a/drivers/staging/iio/adc/max1363_core.c +++ b/drivers/staging/iio/adc/max1363_core.c @@ -18,21 +18,19 @@ * * Not currently implemented. * - * - Monitor interrrupt generation. * - Control of internal reference. */ #include <linux/interrupt.h> -#include <linux/gpio.h> #include <linux/workqueue.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/sysfs.h> #include <linux/list.h> #include <linux/i2c.h> -#include <linux/rtc.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/err.h> #include "../iio.h" #include "../sysfs.h" @@ -48,7 +46,7 @@ IIO_SCAN_EL_C(in##number, number, IIO_UNSIGNED(16), 0, NULL); #define MAX1363_SCAN_EL_D(p, n, number) \ IIO_SCAN_NAMED_EL_C(in##p##m##in##n, in##p-in##n, \ - number, IIO_SIGNED(16), 0 , NULL); + number, IIO_SIGNED(16), 0, NULL); static MAX1363_SCAN_EL(0); static MAX1363_SCAN_EL(1); @@ -148,7 +146,7 @@ const struct max1363_mode mask)) return &max1363_mode_table[ci->mode_list[i]]; return NULL; -}; +} static ssize_t max1363_show_precision(struct device *dev, struct device_attribute *attr, @@ -167,7 +165,7 @@ static int max1363_write_basic_config(struct i2c_client *client, unsigned char d2) { int ret; - u8 *tx_buf = kmalloc(2 , GFP_KERNEL); + u8 *tx_buf = kmalloc(2, GFP_KERNEL); if (!tx_buf) return -ENOMEM; @@ -206,6 +204,16 @@ static ssize_t max1363_read_single_channel(struct device *dev, long mask; mutex_lock(&dev_info->mlock); + /* + * If monitor mode is enabled, the method for reading a single + * channel will have to be rather different and has not yet + * been implemented. + */ + if (st->monitor_on) { + ret = -EBUSY; + goto error_ret; + } + /* If ring buffer capture is occuring, query the buffer */ if (iio_ring_enabled(dev_info)) { mask = max1363_mode_table[this_attr->address].modemask; @@ -305,7 +313,7 @@ static ssize_t max1363_show_name(struct device *dev, { struct iio_dev *dev_info = dev_get_drvdata(dev); struct max1363_state *st = iio_dev_get_devdata(dev_info); - return sprintf(buf, "%s\n", st->chip_info->name); + return sprintf(buf, "%s\n", st->client->name); } static IIO_DEVICE_ATTR(name, S_IRUGO, max1363_show_name, NULL, 0); @@ -552,8 +560,7 @@ enum { max1361, /* max1363 and max1368 tested - rest from data sheet */ static const struct max1363_chip_info max1363_chip_info_tbl[] = { - { - .name = "max1361", + [max1361] = { .num_inputs = 4, .bits = 10, .int_vref_mv = 2048, @@ -563,8 +570,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max1362", + }, + [max1362] = { .num_inputs = 4, .bits = 10, .int_vref_mv = 4096, @@ -574,8 +581,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max1363", + }, + [max1363] = { .num_inputs = 4, .bits = 12, .int_vref_mv = 2048, @@ -585,8 +592,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max1364", + }, + [max1364] = { .num_inputs = 4, .bits = 12, .int_vref_mv = 4096, @@ -596,8 +603,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max1036", + }, + [max1036] = { .num_inputs = 4, .bits = 8, .int_vref_mv = 4096, @@ -606,8 +613,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max1037", + }, + [max1037] = { .num_inputs = 4, .bits = 8, .int_vref_mv = 2048, @@ -616,8 +623,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max1038", + }, + [max1038] = { .num_inputs = 12, .bits = 8, .int_vref_mv = 4096, @@ -626,8 +633,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to11, .dev_attrs = &max1238_dev_attr_group, .scan_attrs = &max1238_scan_el_group, - }, { - .name = "max1039", + }, + [max1039] = { .num_inputs = 12, .bits = 8, .int_vref_mv = 2048, @@ -636,8 +643,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to11, .dev_attrs = &max1238_dev_attr_group, .scan_attrs = &max1238_scan_el_group, - }, { - .name = "max1136", + }, + [max1136] = { .num_inputs = 4, .bits = 10, .int_vref_mv = 4096, @@ -646,8 +653,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max1137", + }, + [max1137] = { .num_inputs = 4, .bits = 10, .int_vref_mv = 2048, @@ -656,8 +663,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max1138", + }, + [max1138] = { .num_inputs = 12, .bits = 10, .int_vref_mv = 4096, @@ -666,8 +673,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to11, .dev_attrs = &max1238_dev_attr_group, .scan_attrs = &max1238_scan_el_group, - }, { - .name = "max1139", + }, + [max1139] = { .num_inputs = 12, .bits = 10, .int_vref_mv = 2048, @@ -676,8 +683,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to11, .dev_attrs = &max1238_dev_attr_group, .scan_attrs = &max1238_scan_el_group, - }, { - .name = "max1236", + }, + [max1236] = { .num_inputs = 4, .bits = 12, .int_vref_mv = 4096, @@ -686,8 +693,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max1237", + }, + [max1237] = { .num_inputs = 4, .bits = 12, .int_vref_mv = 2048, @@ -696,8 +703,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max1238", + }, + [max1238] = { .num_inputs = 12, .bits = 12, .int_vref_mv = 4096, @@ -706,8 +713,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to11, .dev_attrs = &max1238_dev_attr_group, .scan_attrs = &max1238_scan_el_group, - }, { - .name = "max1239", + }, + [max1239] = { .num_inputs = 12, .bits = 12, .int_vref_mv = 2048, @@ -716,8 +723,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to11, .dev_attrs = &max1238_dev_attr_group, .scan_attrs = &max1238_scan_el_group, - }, { - .name = "max11600", + }, + [max11600] = { .num_inputs = 4, .bits = 8, .int_vref_mv = 4096, @@ -726,8 +733,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max11601", + }, + [max11601] = { .num_inputs = 4, .bits = 8, .int_vref_mv = 2048, @@ -736,8 +743,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max11602", + }, + [max11602] = { .num_inputs = 8, .bits = 8, .int_vref_mv = 4096, @@ -746,8 +753,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to7, .dev_attrs = &max11608_dev_attr_group, .scan_attrs = &max11608_scan_el_group, - }, { - .name = "max11603", + }, + [max11603] = { .num_inputs = 8, .bits = 8, .int_vref_mv = 2048, @@ -756,8 +763,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to7, .dev_attrs = &max11608_dev_attr_group, .scan_attrs = &max11608_scan_el_group, - }, { - .name = "max11604", + }, + [max11604] = { .num_inputs = 12, .bits = 8, .int_vref_mv = 4098, @@ -766,8 +773,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to11, .dev_attrs = &max1238_dev_attr_group, .scan_attrs = &max1238_scan_el_group, - }, { - .name = "max11605", + }, + [max11605] = { .num_inputs = 12, .bits = 8, .int_vref_mv = 2048, @@ -776,8 +783,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to11, .dev_attrs = &max1238_dev_attr_group, .scan_attrs = &max1238_scan_el_group, - }, { - .name = "max11606", + }, + [max11606] = { .num_inputs = 4, .bits = 10, .int_vref_mv = 4096, @@ -786,8 +793,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max11607", + }, + [max11607] = { .num_inputs = 4, .bits = 10, .int_vref_mv = 2048, @@ -796,8 +803,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max11608", + }, + [max11608] = { .num_inputs = 8, .bits = 10, .int_vref_mv = 4096, @@ -806,8 +813,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to7, .dev_attrs = &max11608_dev_attr_group, .scan_attrs = &max11608_scan_el_group, - }, { - .name = "max11609", + }, + [max11609] = { .num_inputs = 8, .bits = 10, .int_vref_mv = 2048, @@ -816,8 +823,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to7, .dev_attrs = &max11608_dev_attr_group, .scan_attrs = &max11608_scan_el_group, - }, { - .name = "max11610", + }, + [max11610] = { .num_inputs = 12, .bits = 10, .int_vref_mv = 4098, @@ -826,8 +833,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to11, .dev_attrs = &max1238_dev_attr_group, .scan_attrs = &max1238_scan_el_group, - }, { - .name = "max11611", + }, + [max11611] = { .num_inputs = 12, .bits = 10, .int_vref_mv = 2048, @@ -836,8 +843,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to11, .dev_attrs = &max1238_dev_attr_group, .scan_attrs = &max1238_scan_el_group, - }, { - .name = "max11612", + }, + [max11612] = { .num_inputs = 4, .bits = 12, .int_vref_mv = 4096, @@ -846,8 +853,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max11613", + }, + [max11613] = { .num_inputs = 4, .bits = 12, .int_vref_mv = 2048, @@ -856,8 +863,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to3, .dev_attrs = &max1363_dev_attr_group, .scan_attrs = &max1363_scan_el_group, - }, { - .name = "max11614", + }, + [max11614] = { .num_inputs = 8, .bits = 12, .int_vref_mv = 4096, @@ -866,8 +873,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to7, .dev_attrs = &max11608_dev_attr_group, .scan_attrs = &max11608_scan_el_group, - }, { - .name = "max11615", + }, + [max11615] = { .num_inputs = 8, .bits = 12, .int_vref_mv = 2048, @@ -876,8 +883,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to7, .dev_attrs = &max11608_dev_attr_group, .scan_attrs = &max11608_scan_el_group, - }, { - .name = "max11616", + }, + [max11616] = { .num_inputs = 12, .bits = 12, .int_vref_mv = 4098, @@ -886,8 +893,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .default_mode = s0to11, .dev_attrs = &max1238_dev_attr_group, .scan_attrs = &max1238_scan_el_group, - }, { - .name = "max11617", + }, + [max11617] = { .num_inputs = 12, .bits = 12, .int_vref_mv = 2048, @@ -899,6 +906,668 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { } }; +static const int max1363_monitor_speeds[] = { 133000, 665000, 33300, 16600, + 8300, 4200, 2000, 1000 }; + +static ssize_t max1363_monitor_show_freq(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct max1363_state *st = iio_dev_get_devdata(dev_info); + return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]); +} + +static ssize_t max1363_monitor_store_freq(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct max1363_state *st = iio_dev_get_devdata(dev_info); + int i, ret; + unsigned long val; + bool found = false; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(max1363_monitor_speeds); i++) + if (val == max1363_monitor_speeds[i]) { + found = true; + break; + } + if (!found) + return -EINVAL; + + mutex_lock(&dev_info->mlock); + st->monitor_speed = i; + mutex_unlock(&dev_info->mlock); + + return 0; +} + +static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, + max1363_monitor_show_freq, + max1363_monitor_store_freq); + +static IIO_CONST_ATTR(sampling_frequency_available, + "133000 665000 33300 16600 8300 4200 2000 1000"); + +static ssize_t max1363_show_thresh(struct device *dev, + struct device_attribute *attr, + char *buf, + bool high) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct max1363_state *st = iio_dev_get_devdata(dev_info); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + if (high) + return sprintf(buf, "%d\n", + st->thresh_high[this_attr->address]); + else + return sprintf(buf, "%d\n", + st->thresh_low[this_attr->address & 0x7]); +} + +static ssize_t max1363_show_thresh_low(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return max1363_show_thresh(dev, attr, buf, false); +} + +static ssize_t max1363_show_thresh_high(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return max1363_show_thresh(dev, attr, buf, true); +} + +static ssize_t max1363_store_thresh_unsigned(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len, + bool high) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct max1363_state *st = iio_dev_get_devdata(dev_info); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + return -EINVAL; + switch (st->chip_info->bits) { + case 10: + if (val > 0x3FF) + return -EINVAL; + break; + case 12: + if (val > 0xFFF) + return -EINVAL; + break; + } + + switch (high) { + case 1: + st->thresh_high[this_attr->address] = val; + break; + case 0: + st->thresh_low[this_attr->address & 0x7] = val; + break; + } + + return len; +} + +static ssize_t max1363_store_thresh_high_unsigned(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return max1363_store_thresh_unsigned(dev, attr, buf, len, true); +} + +static ssize_t max1363_store_thresh_low_unsigned(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return max1363_store_thresh_unsigned(dev, attr, buf, len, false); +} + +static ssize_t max1363_store_thresh_signed(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len, + bool high) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct max1363_state *st = iio_dev_get_devdata(dev_info); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + long val; + int ret; + + ret = strict_strtol(buf, 10, &val); + if (ret) + return -EINVAL; + switch (st->chip_info->bits) { + case 10: + if (val < -512 || val > 511) + return -EINVAL; + break; + case 12: + if (val < -2048 || val > 2047) + return -EINVAL; + break; + } + + switch (high) { + case 1: + st->thresh_high[this_attr->address] = val; + break; + case 0: + st->thresh_low[this_attr->address & 0x7] = val; + break; + } + + return len; +} + +static ssize_t max1363_store_thresh_high_signed(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return max1363_store_thresh_signed(dev, attr, buf, len, true); +} + +static ssize_t max1363_store_thresh_low_signed(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return max1363_store_thresh_signed(dev, attr, buf, len, false); +} + +static IIO_DEVICE_ATTR(in0_thresh_high_value, S_IRUGO | S_IWUSR, + max1363_show_thresh_high, + max1363_store_thresh_high_unsigned, 0); +static IIO_DEVICE_ATTR(in0_thresh_low_value, S_IRUGO | S_IWUSR, + max1363_show_thresh_low, + max1363_store_thresh_low_unsigned, 0); +static IIO_DEVICE_ATTR(in1_thresh_high_value, S_IRUGO | S_IWUSR, + max1363_show_thresh_high, + max1363_store_thresh_high_unsigned, 1); +static IIO_DEVICE_ATTR(in1_thresh_low_value, S_IRUGO | S_IWUSR, + max1363_show_thresh_low, + max1363_store_thresh_low_unsigned, 1); +static IIO_DEVICE_ATTR(in2_thresh_high_value, S_IRUGO | S_IWUSR, + max1363_show_thresh_high, + max1363_store_thresh_high_unsigned, 2); +static IIO_DEVICE_ATTR(in2_thresh_low_value, S_IRUGO | S_IWUSR, + max1363_show_thresh_low, + max1363_store_thresh_low_unsigned, 2); +static IIO_DEVICE_ATTR(in3_thresh_high_value, S_IRUGO | S_IWUSR, + max1363_show_thresh_high, + max1363_store_thresh_high_unsigned, 3); +static IIO_DEVICE_ATTR(in3_thresh_low_value, S_IRUGO | S_IWUSR, + max1363_show_thresh_low, + max1363_store_thresh_low_unsigned, 3); + +static IIO_DEVICE_ATTR_NAMED(in0min1_thresh_high_value, + in0-in1_thresh_high_value, + S_IRUGO | S_IWUSR, max1363_show_thresh_high, + max1363_store_thresh_high_signed, 4); +static IIO_DEVICE_ATTR_NAMED(in0min1_thresh_low_value, + in0-in1_thresh_low_value, + S_IRUGO | S_IWUSR, max1363_show_thresh_low, + max1363_store_thresh_low_signed, 4); +static IIO_DEVICE_ATTR_NAMED(in2min3_thresh_high_value, + in2-in3_thresh_high_value, + S_IRUGO | S_IWUSR, max1363_show_thresh_high, + max1363_store_thresh_high_signed, 5); +static IIO_DEVICE_ATTR_NAMED(in2min3_thresh_low_value, + in2-in3_thresh_low_value, + S_IRUGO | S_IWUSR, max1363_show_thresh_low, + max1363_store_thresh_low_signed, 5); +static IIO_DEVICE_ATTR_NAMED(in1min0_thresh_high_value, + in1-in0_thresh_high_value, + S_IRUGO | S_IWUSR, max1363_show_thresh_high, + max1363_store_thresh_high_signed, 6); +static IIO_DEVICE_ATTR_NAMED(in1min0_thresh_low_value, + in1-in0_thresh_low_value, + S_IRUGO | S_IWUSR, max1363_show_thresh_low, + max1363_store_thresh_low_signed, 6); +static IIO_DEVICE_ATTR_NAMED(in3min2_thresh_high_value, + in3-in2_thresh_high_value, + S_IRUGO | S_IWUSR, max1363_show_thresh_high, + max1363_store_thresh_high_signed, 7); +static IIO_DEVICE_ATTR_NAMED(in3min2_thresh_low_value, + in3-in2_thresh_low_value, + S_IRUGO | S_IWUSR, max1363_show_thresh_low, + max1363_store_thresh_low_signed, 7); + +static int max1363_int_th(struct iio_dev *dev_info, + int index, + s64 timestamp, + int not_test) +{ + struct max1363_state *st = dev_info->dev_data; + + st->last_timestamp = timestamp; + schedule_work(&st->thresh_work); + return 0; +} + +static void max1363_thresh_handler_bh(struct work_struct *work_s) +{ + struct max1363_state *st = container_of(work_s, struct max1363_state, + thresh_work); + u8 rx; + u8 tx[2] = { st->setupbyte, + MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0 }; + + i2c_master_recv(st->client, &rx, 1); + if (rx & (1 << 0)) + iio_push_event(st->indio_dev, 0, + IIO_EVENT_CODE_IN_LOW_THRESH(3), + st->last_timestamp); + if (rx & (1 << 1)) + iio_push_event(st->indio_dev, 0, + IIO_EVENT_CODE_IN_HIGH_THRESH(3), + st->last_timestamp); + if (rx & (1 << 2)) + iio_push_event(st->indio_dev, 0, + IIO_EVENT_CODE_IN_LOW_THRESH(2), + st->last_timestamp); + if (rx & (1 << 3)) + iio_push_event(st->indio_dev, 0, + IIO_EVENT_CODE_IN_HIGH_THRESH(2), + st->last_timestamp); + if (rx & (1 << 4)) + iio_push_event(st->indio_dev, 0, + IIO_EVENT_CODE_IN_LOW_THRESH(1), + st->last_timestamp); + if (rx & (1 << 5)) + iio_push_event(st->indio_dev, 0, + IIO_EVENT_CODE_IN_HIGH_THRESH(1), + st->last_timestamp); + if (rx & (1 << 6)) + iio_push_event(st->indio_dev, 0, + IIO_EVENT_CODE_IN_LOW_THRESH(0), + st->last_timestamp); + if (rx & (1 << 7)) + iio_push_event(st->indio_dev, 0, + IIO_EVENT_CODE_IN_HIGH_THRESH(0), + st->last_timestamp); + enable_irq(st->client->irq); + i2c_master_send(st->client, tx, 2); +} + +static ssize_t max1363_read_interrupt_config(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct max1363_state *st = iio_dev_get_devdata(dev_info); + struct iio_event_attr *this_attr = to_iio_event_attr(attr); + int val; + + mutex_lock(&dev_info->mlock); + if (this_attr->mask & 0x8) + val = (1 << (this_attr->mask & 0x7)) & st->mask_low; + else + val = (1 << this_attr->mask) & st->mask_high; + mutex_unlock(&dev_info->mlock); + + return sprintf(buf, "%d\n", !!val); +} + +static int max1363_monitor_mode_update(struct max1363_state *st, int enabled) +{ + u8 *tx_buf; + int ret, i = 3, j; + unsigned long numelements; + int len; + long modemask; + + if (!enabled) { + /* transition to ring capture is not currently supported */ + st->setupbyte &= ~MAX1363_SETUP_MONITOR_SETUP; + st->configbyte &= ~MAX1363_SCAN_MASK; + st->monitor_on = false; + return max1363_write_basic_config(st->client, + st->setupbyte, + st->configbyte); + } + + /* Ensure we are in the relevant mode */ + st->setupbyte |= MAX1363_SETUP_MONITOR_SETUP; + st->configbyte &= ~(MAX1363_CHANNEL_SEL_MASK + | MAX1363_SCAN_MASK + | MAX1363_SE_DE_MASK); + st->configbyte |= MAX1363_CONFIG_SCAN_MONITOR_MODE; + if ((st->mask_low | st->mask_high) & 0x0F) { + st->configbyte |= max1363_mode_table[s0to3].conf; + modemask = max1363_mode_table[s0to3].modemask; + } else if ((st->mask_low | st->mask_high) & 0x30) { + st->configbyte |= max1363_mode_table[d0m1to2m3].conf; + modemask = max1363_mode_table[d0m1to2m3].modemask; + } else { + st->configbyte |= max1363_mode_table[d1m0to3m2].conf; + modemask = max1363_mode_table[d1m0to3m2].modemask; + } + numelements = hweight_long(modemask); + len = 3 * numelements + 3; + tx_buf = kmalloc(len, GFP_KERNEL); + if (!tx_buf) { + ret = -ENOMEM; + goto error_ret; + } + tx_buf[0] = st->configbyte; + tx_buf[1] = st->setupbyte; + tx_buf[2] = (st->monitor_speed << 1); + + /* + * So we need to do yet another bit of nefarious scan mode + * setup to match what we need. + */ + for (j = 0; j < 8; j++) + if (modemask & (1 << j)) { + /* Establish the mode is in the scan */ + if (st->mask_low & (1 << j)) { + tx_buf[i] = (st->thresh_low[j] >> 4) & 0xFF; + tx_buf[i + 1] = (st->thresh_low[j] << 4) & 0xF0; + } else if (j < 4) { + tx_buf[i] = 0; + tx_buf[i + 1] = 0; + } else { + tx_buf[i] = 0x80; + tx_buf[i + 1] = 0; + } + if (st->mask_high & (1 << j)) { + tx_buf[i + 1] |= + (st->thresh_high[j] >> 8) & 0x0F; + tx_buf[i + 2] = st->thresh_high[j] & 0xFF; + } else if (j < 4) { + tx_buf[i + 1] |= 0x0F; + tx_buf[i + 2] = 0xFF; + } else { + tx_buf[i + 1] |= 0x07; + tx_buf[i + 2] = 0xFF; + } + i += 3; + } + + + ret = i2c_master_send(st->client, tx_buf, len); + if (ret < 0) + goto error_ret; + if (ret != len) { + ret = -EIO; + goto error_ret; + } + + /* + * Now that we hopefully have sensible thresholds in place it is + * time to turn the interrupts on. + * It is unclear from the data sheet if this should be necessary + * (i.e. whether monitor mode setup is atomic) but it appears to + * be in practice. + */ + tx_buf[0] = st->setupbyte; + tx_buf[1] = MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0; + ret = i2c_master_send(st->client, tx_buf, 2); + if (ret < 0) + goto error_ret; + if (ret != 2) { + ret = -EIO; + goto error_ret; + } + ret = 0; + st->monitor_on = true; +error_ret: + + kfree(tx_buf); + + return ret; +} + +/* + * To keep this managable we always use one of 3 scan modes. + * Scan 0...3, 0-1,2-3 and 1-0,3-2 + */ +static inline int __max1363_check_event_mask(int thismask, int checkmask) +{ + int ret = 0; + /* Is it unipolar */ + if (thismask < 4) { + if (checkmask & ~0x0F) { + ret = -EBUSY; + goto error_ret; + } + } else if (thismask < 6) { + if (checkmask & ~0x30) { + ret = -EBUSY; + goto error_ret; + } + } else if (checkmask & ~0xC0) + ret = -EBUSY; +error_ret: + return ret; +} + +static ssize_t max1363_write_interrupt_config(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct max1363_state *st = iio_dev_get_devdata(dev_info); + struct iio_event_attr *this_attr = to_iio_event_attr(attr); + unsigned long val; + int ret; + u16 unifiedmask; + ret = strict_strtoul(buf, 10, &val); + if (ret) + return -EINVAL; + mutex_lock(&st->indio_dev->mlock); + unifiedmask = st->mask_low | st->mask_high; + if (this_attr->mask & 0x08) { + /* If we are disabling no need to test */ + if (val == 0) + st->mask_low &= ~(1 << (this_attr->mask & 0x7)); + else { + ret = __max1363_check_event_mask(this_attr->mask & 0x7, + unifiedmask); + if (ret) + goto error_ret; + st->mask_low |= (1 << (this_attr->mask & 0x7)); + } + } else { + if (val == 0) + st->mask_high &= ~(1 << (this_attr->mask)); + else { + ret = __max1363_check_event_mask(this_attr->mask, + unifiedmask); + if (ret) + goto error_ret; + st->mask_high |= (1 << this_attr->mask); + } + } + if (st->monitor_on && !st->mask_high && !st->mask_low) + iio_remove_event_from_list(this_attr->listel, + &dev_info->interrupts[0]->ev_list); + if (!st->monitor_on && val) + iio_add_event_to_list(this_attr->listel, + &dev_info->interrupts[0]->ev_list); + + max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low)); +error_ret: + mutex_unlock(&st->indio_dev->mlock); + + return len; +} + +IIO_EVENT_SH(max1363_thresh, max1363_int_th); + +#define MAX1363_HIGH_THRESH(a) a +#define MAX1363_LOW_THRESH(a) (a | 0x8) + +IIO_EVENT_ATTR_SH(in0_thresh_high_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_HIGH_THRESH(0)); + +IIO_EVENT_ATTR_SH(in0_thresh_low_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_LOW_THRESH(0)); + +IIO_EVENT_ATTR_SH(in1_thresh_high_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_HIGH_THRESH(1)); + +IIO_EVENT_ATTR_SH(in1_thresh_low_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_LOW_THRESH(1)); + +IIO_EVENT_ATTR_SH(in2_thresh_high_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_HIGH_THRESH(2)); + +IIO_EVENT_ATTR_SH(in2_thresh_low_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_LOW_THRESH(2)); + +IIO_EVENT_ATTR_SH(in3_thresh_high_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_HIGH_THRESH(3)); + +IIO_EVENT_ATTR_SH(in3_thresh_low_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_LOW_THRESH(3)); + +IIO_EVENT_ATTR_NAMED_SH(in0min1_thresh_high_en, + in0-in1_thresh_high_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_HIGH_THRESH(4)); + +IIO_EVENT_ATTR_NAMED_SH(in0min1_thresh_low_en, + in0-in1_thresh_low_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_LOW_THRESH(4)); + +IIO_EVENT_ATTR_NAMED_SH(in3min2_thresh_high_en, + in3-in2_thresh_high_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_HIGH_THRESH(5)); + +IIO_EVENT_ATTR_NAMED_SH(in3min2_thresh_low_en, + in3-in2_thresh_low_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_LOW_THRESH(5)); + +IIO_EVENT_ATTR_NAMED_SH(in1min0_thresh_high_en, + in1-in0_thresh_high_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_HIGH_THRESH(6)); + +IIO_EVENT_ATTR_NAMED_SH(in1min0_thresh_low_en, + in1-in0_thresh_low_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_LOW_THRESH(6)); + +IIO_EVENT_ATTR_NAMED_SH(in2min3_thresh_high_en, + in2-in3_thresh_high_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_HIGH_THRESH(7)); + +IIO_EVENT_ATTR_NAMED_SH(in2min3_thresh_low_en, + in2-in3_thresh_low_en, + iio_event_max1363_thresh, + max1363_read_interrupt_config, + max1363_write_interrupt_config, + MAX1363_LOW_THRESH(7)); + +/* + * As with scan_elements, only certain sets of these can + * be combined. + */ +static struct attribute *max1363_event_attributes[] = { + &iio_dev_attr_in0_thresh_high_value.dev_attr.attr, + &iio_dev_attr_in0_thresh_low_value.dev_attr.attr, + &iio_dev_attr_in1_thresh_high_value.dev_attr.attr, + &iio_dev_attr_in1_thresh_low_value.dev_attr.attr, + &iio_dev_attr_in2_thresh_high_value.dev_attr.attr, + &iio_dev_attr_in2_thresh_low_value.dev_attr.attr, + &iio_dev_attr_in3_thresh_high_value.dev_attr.attr, + &iio_dev_attr_in3_thresh_low_value.dev_attr.attr, + &iio_dev_attr_in0min1_thresh_high_value.dev_attr.attr, + &iio_dev_attr_in0min1_thresh_low_value.dev_attr.attr, + &iio_dev_attr_in2min3_thresh_high_value.dev_attr.attr, + &iio_dev_attr_in2min3_thresh_low_value.dev_attr.attr, + &iio_dev_attr_in1min0_thresh_high_value.dev_attr.attr, + &iio_dev_attr_in1min0_thresh_low_value.dev_attr.attr, + &iio_dev_attr_in3min2_thresh_high_value.dev_attr.attr, + &iio_dev_attr_in3min2_thresh_low_value.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_event_attr_in0_thresh_high_en.dev_attr.attr, + &iio_event_attr_in0_thresh_low_en.dev_attr.attr, + &iio_event_attr_in1_thresh_high_en.dev_attr.attr, + &iio_event_attr_in1_thresh_low_en.dev_attr.attr, + &iio_event_attr_in2_thresh_high_en.dev_attr.attr, + &iio_event_attr_in2_thresh_low_en.dev_attr.attr, + &iio_event_attr_in3_thresh_high_en.dev_attr.attr, + &iio_event_attr_in3_thresh_low_en.dev_attr.attr, + &iio_event_attr_in0min1_thresh_high_en.dev_attr.attr, + &iio_event_attr_in0min1_thresh_low_en.dev_attr.attr, + &iio_event_attr_in3min2_thresh_high_en.dev_attr.attr, + &iio_event_attr_in3min2_thresh_low_en.dev_attr.attr, + &iio_event_attr_in1min0_thresh_high_en.dev_attr.attr, + &iio_event_attr_in1min0_thresh_low_en.dev_attr.attr, + &iio_event_attr_in2min3_thresh_high_en.dev_attr.attr, + &iio_event_attr_in2min3_thresh_low_en.dev_attr.attr, + NULL, +}; + +static struct attribute_group max1363_event_attribute_group = { + .attrs = max1363_event_attributes, +}; + static int max1363_initial_setup(struct max1363_state *st) { st->setupbyte = MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD @@ -930,19 +1599,7 @@ static int __devinit max1363_probe(struct i2c_client *client, atomic_set(&st->protect_ring, 0); - /* Find the chip model specific data */ - for (i = 0; i < ARRAY_SIZE(max1363_chip_info_tbl); i++) - if (!strcmp(max1363_chip_info_tbl[i].name, id->name)) { - st->chip_info = &max1363_chip_info_tbl[i]; - break; - }; - /* Unsupported chip */ - if (!st->chip_info) { - dev_err(&client->dev, "%s is not supported\n", id->name); - ret = -ENODEV; - goto error_free_st; - } - + st->chip_info = &max1363_chip_info_tbl[id->driver_data]; st->reg = regulator_get(&client->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); @@ -978,6 +1635,11 @@ static int __devinit max1363_probe(struct i2c_client *client, st->indio_dev->dev_data = (void *)(st); st->indio_dev->driver_module = THIS_MODULE; st->indio_dev->modes = INDIO_DIRECT_MODE; + if (st->chip_info->monitor_mode && client->irq) { + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs + = &max1363_event_attribute_group; + } ret = max1363_initial_setup(st); if (ret) @@ -991,10 +1653,25 @@ static int __devinit max1363_probe(struct i2c_client *client, if (ret) goto error_cleanup_ring; regdone = 1; - ret = max1363_initialize_ring(st->indio_dev->ring); + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); if (ret) goto error_cleanup_ring; + + if (st->chip_info->monitor_mode && client->irq) { + ret = iio_register_interrupt_line(client->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_RISING, + client->name); + if (ret) + goto error_uninit_ring; + + INIT_WORK(&st->thresh_work, max1363_thresh_handler_bh); + } + return 0; +error_uninit_ring: + iio_ring_buffer_unregister(st->indio_dev->ring); error_cleanup_ring: max1363_ring_cleanup(st->indio_dev); error_free_available_scan_masks: @@ -1010,7 +1687,6 @@ error_disable_reg: error_put_reg: if (!IS_ERR(st->reg)) regulator_put(st->reg); -error_free_st: kfree(st); error_ret: @@ -1021,7 +1697,10 @@ static int max1363_remove(struct i2c_client *client) { struct max1363_state *st = i2c_get_clientdata(client); struct iio_dev *indio_dev = st->indio_dev; - max1363_uninitialize_ring(indio_dev->ring); + + if (st->chip_info->monitor_mode && client->irq) + iio_unregister_interrupt_line(st->indio_dev, 0); + iio_ring_buffer_unregister(indio_dev->ring); max1363_ring_cleanup(indio_dev); kfree(st->indio_dev->available_scan_masks); iio_device_unregister(indio_dev); diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c index 56688dc9c92..786b17a0d6b 100644 --- a/drivers/staging/iio/adc/max1363_ring.c +++ b/drivers/staging/iio/adc/max1363_ring.c @@ -68,7 +68,7 @@ error_ret: } /** - * max1363_ring_preenable() setup the parameters of the ring before enabling + * max1363_ring_preenable() - setup the parameters of the ring before enabling * * The complex nature of the setting of the nuber of bytes per datum is due * to this driver currently ensuring that the timestamp is stored at an 8 @@ -105,44 +105,15 @@ static int max1363_ring_preenable(struct iio_dev *indio_dev) return 0; } -/** - * max1363_ring_postenable() typical ring post enable - * - * Only not moved into the core for the hardware ring buffer cases - * that are more sophisticated. - **/ -static int max1363_ring_postenable(struct iio_dev *indio_dev) -{ - if (indio_dev->trig == NULL) - return 0; - return iio_trigger_attach_poll_func(indio_dev->trig, - indio_dev->pollfunc); -} /** - * max1363_ring_predisable() runs just prior to ring buffer being disabled - * - * Typical predisable function which ensures that no trigger events can - * occur before we disable the ring buffer (and hence would have no idea - * what to do with them) - **/ -static int max1363_ring_predisable(struct iio_dev *indio_dev) -{ - if (indio_dev->trig) - return iio_trigger_dettach_poll_func(indio_dev->trig, - indio_dev->pollfunc); - else - return 0; -} - -/** - * max1363_poll_func_th() th of trigger launched polling to ring buffer + * max1363_poll_func_th() - th of trigger launched polling to ring buffer * * As sampling only occurs on i2c comms occuring, leave timestamping until * then. Some triggers will generate their own time stamp. Currently * there is no way of notifying them when no one cares. **/ -static void max1363_poll_func_th(struct iio_dev *indio_dev) +static void max1363_poll_func_th(struct iio_dev *indio_dev, s64 time) { struct max1363_state *st = indio_dev->dev_data; @@ -151,7 +122,7 @@ static void max1363_poll_func_th(struct iio_dev *indio_dev) return; } /** - * max1363_poll_bh_to_ring() bh of trigger launched polling to ring buffer + * max1363_poll_bh_to_ring() - bh of trigger launched polling to ring buffer * @work_s: the work struct through which this was scheduled * * Currently there is no option in this driver to disable the saving of @@ -223,19 +194,14 @@ int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev) } /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&st->indio_dev->ring->access); - indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); - if (indio_dev->pollfunc == NULL) { - ret = -ENOMEM; + ret = iio_alloc_pollfunc(indio_dev, NULL, &max1363_poll_func_th); + if (ret) goto error_deallocate_sw_rb; - } - /* Configure the polling function called on trigger interrupts */ - indio_dev->pollfunc->poll_func_main = &max1363_poll_func_th; - indio_dev->pollfunc->private_data = indio_dev; /* Ring buffer functions - here trigger setup related */ - indio_dev->ring->postenable = &max1363_ring_postenable; + indio_dev->ring->postenable = &iio_triggered_ring_postenable; indio_dev->ring->preenable = &max1363_ring_preenable; - indio_dev->ring->predisable = &max1363_ring_predisable; + indio_dev->ring->predisable = &iio_triggered_ring_predisable; INIT_WORK(&st->poll_work, &max1363_poll_bh_to_ring); /* Flag that polled ring buffering is possible */ @@ -258,13 +224,3 @@ void max1363_ring_cleanup(struct iio_dev *indio_dev) kfree(indio_dev->pollfunc); iio_sw_rb_free(indio_dev->ring); } - -void max1363_uninitialize_ring(struct iio_ring_buffer *ring) -{ - iio_ring_buffer_unregister(ring); -}; - -int max1363_initialize_ring(struct iio_ring_buffer *ring) -{ - return iio_ring_buffer_register(ring, 0); -}; diff --git a/drivers/staging/iio/chrdev.h b/drivers/staging/iio/chrdev.h index 3f96f8696a4..fd23bd1ea7b 100644 --- a/drivers/staging/iio/chrdev.h +++ b/drivers/staging/iio/chrdev.h @@ -73,8 +73,6 @@ struct iio_shared_ev_pointer { * @det_events: list of detected events * @max_events: maximum number of events before new ones are dropped * @current_events: number of events in detected list - * @id: indentifier to allow the event interface to know which - * physical line it corresponds to * @attr: this chrdev's minor number sysfs attribute * @owner: ensure the driver module owns the file, not iio * @private: driver specific data @@ -90,7 +88,6 @@ struct iio_event_interface { struct iio_detected_event_list det_events; int max_events; int current_events; - int id; struct iio_chrdev_minor_attr attr; struct module *owner; void *private; diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile index 6d2c547686c..b5f0dc01122 100644 --- a/drivers/staging/iio/gyro/Makefile +++ b/drivers/staging/iio/gyro/Makefile @@ -1,4 +1,4 @@ - +# # Makefile for digital gyroscope sensor drivers # diff --git a/drivers/staging/iio/gyro/adis16260.h b/drivers/staging/iio/gyro/adis16260.h index f19efb4c91c..812440af57d 100644 --- a/drivers/staging/iio/gyro/adis16260.h +++ b/drivers/staging/iio/gyro/adis16260.h @@ -85,7 +85,6 @@ * struct adis16260_state - device instance specific data * @us: actual spi_device * @work_trigger_to_ring: bh for triggered event handling - * @work_cont_thresh: CLEAN * @inter: used to check if new interrupt has been triggered * @last_timestamp: passing timestamp from th to bh of interrupt handler * @indio_dev: industrial I/O device structure @@ -97,7 +96,6 @@ struct adis16260_state { struct spi_device *us; struct work_struct work_trigger_to_ring; - struct iio_work_cont work_cont_thresh; s64 last_timestamp; struct iio_dev *indio_dev; struct iio_trigger *trig; @@ -113,13 +111,11 @@ int adis16260_set_irq(struct device *dev, bool enable); * filling. This may change! */ -enum adis16260_scan { - ADIS16260_SCAN_SUPPLY, - ADIS16260_SCAN_GYRO, - ADIS16260_SCAN_AUX_ADC, - ADIS16260_SCAN_TEMP, - ADIS16260_SCAN_ANGL, -}; +#define ADIS16260_SCAN_SUPPLY 0 +#define ADIS16260_SCAN_GYRO 1 +#define ADIS16260_SCAN_AUX_ADC 2 +#define ADIS16260_SCAN_TEMP 3 +#define ADIS16260_SCAN_ANGL 4 void adis16260_remove_trigger(struct iio_dev *indio_dev); int adis16260_probe_trigger(struct iio_dev *indio_dev); @@ -132,8 +128,6 @@ ssize_t adis16260_read_data_from_ring(struct device *dev, int adis16260_configure_ring(struct iio_dev *indio_dev); void adis16260_unconfigure_ring(struct iio_dev *indio_dev); -int adis16260_initialize_ring(struct iio_ring_buffer *ring); -void adis16260_uninitialize_ring(struct iio_ring_buffer *ring); #else /* CONFIG_IIO_RING_BUFFER */ static inline void adis16260_remove_trigger(struct iio_dev *indio_dev) @@ -162,14 +156,5 @@ static inline void adis16260_unconfigure_ring(struct iio_dev *indio_dev) { } -static inline int adis16260_initialize_ring(struct iio_ring_buffer *ring) -{ - return 0; -} - -static inline void adis16260_uninitialize_ring(struct iio_ring_buffer *ring) -{ -} - #endif /* CONFIG_IIO_RING_BUFFER */ #endif /* SPI_ADIS16260_H_ */ diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c index c93f4d580fc..134dfaae2f0 100644 --- a/drivers/staging/iio/gyro/adis16260_core.c +++ b/drivers/staging/iio/gyro/adis16260_core.c @@ -14,12 +14,13 @@ #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 "../iio.h" #include "../sysfs.h" +#include "../ring_generic.h" #include "../adc/adc.h" #include "gyro.h" @@ -555,8 +556,7 @@ static int __devinit adis16260_probe(struct spi_device *spi) if (ret) goto error_unreg_ring_funcs; regdone = 1; - - ret = adis16260_initialize_ring(st->indio_dev->ring); + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); if (ret) { printk(KERN_ERR "failed to initialize the ring\n"); goto error_unreg_ring_funcs; @@ -588,7 +588,7 @@ error_unregister_line: if (spi->irq) iio_unregister_interrupt_line(st->indio_dev, 0); error_uninitialize_ring: - adis16260_uninitialize_ring(st->indio_dev->ring); + iio_ring_buffer_unregister(st->indio_dev->ring); error_unreg_ring_funcs: adis16260_unconfigure_ring(st->indio_dev); error_free_dev: @@ -622,15 +622,13 @@ static int adis16260_remove(struct spi_device *spi) if (spi->irq) iio_unregister_interrupt_line(indio_dev, 0); - adis16260_uninitialize_ring(indio_dev->ring); + iio_ring_buffer_unregister(st->indio_dev->ring); iio_device_unregister(indio_dev); adis16260_unconfigure_ring(indio_dev); kfree(st->tx); kfree(st->rx); kfree(st); - return 0; - err_ret: return ret; } diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c index 4c4390ca6d7..9ef7f9080dc 100644 --- a/drivers/staging/iio/gyro/adis16260_ring.c +++ b/drivers/staging/iio/gyro/adis16260_ring.c @@ -6,6 +6,7 @@ #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> @@ -16,16 +17,6 @@ #include "../trigger.h" #include "adis16260.h" -/** - * combine_8_to_16() utility function to munge to u8s into u16 - **/ -static inline u16 combine_8_to_16(u8 lower, u8 upper) -{ - u16 _lower = lower; - u16 _upper = upper; - return _lower | (_upper << 8); -} - static IIO_SCAN_EL_C(supply, ADIS16260_SCAN_SUPPLY, IIO_UNSIGNED(12), ADIS16260_SUPPLY_OUT, NULL); static IIO_SCAN_EL_C(gyro, ADIS16260_SCAN_GYRO, IIO_SIGNED(14), @@ -58,10 +49,10 @@ static struct attribute_group adis16260_scan_el_group = { * adis16260_poll_func_th() top half interrupt handler called by trigger * @private_data: iio_dev **/ -static void adis16260_poll_func_th(struct iio_dev *indio_dev) +static void adis16260_poll_func_th(struct iio_dev *indio_dev, s64 time) { struct adis16260_state *st = iio_dev_get_devdata(indio_dev); - st->last_timestamp = indio_dev->trig->timestamp; + st->last_timestamp = time; schedule_work(&st->work_trigger_to_ring); } @@ -133,10 +124,9 @@ static void adis16260_trigger_bh_to_ring(struct work_struct *work_s) if (st->indio_dev->scan_count) if (adis16260_read_ring_data(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) { - data[i] = combine_8_to_16(st->rx[i*2+1], - st->rx[i*2]); - } + for (; i < st->indio_dev->scan_count; i++) + data[i] = be16_to_cpup( + (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ if (st->indio_dev->scan_timestamp) @@ -152,48 +142,6 @@ static void adis16260_trigger_bh_to_ring(struct work_struct *work_s) return; } -static int adis16260_data_rdy_ring_preenable(struct iio_dev *indio_dev) -{ - size_t size; - dev_dbg(&indio_dev->dev, "%s\n", __func__); - /* Check if there are any scan elements enabled, if not fail*/ - if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) - return -EINVAL; - - if (indio_dev->ring->access.set_bpd) { - if (indio_dev->scan_timestamp) - if (indio_dev->scan_count) - /* Timestamp (aligned s64) and data */ - size = (((indio_dev->scan_count * sizeof(s16)) - + sizeof(s64) - 1) - & ~(sizeof(s64) - 1)) - + sizeof(s64); - else /* Timestamp only */ - size = sizeof(s64); - else /* Data only */ - size = indio_dev->scan_count*sizeof(s16); - indio_dev->ring->access.set_bpd(indio_dev->ring, size); - } - - return 0; -} - -static int adis16260_data_rdy_ring_postenable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_attach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - -static int adis16260_data_rdy_ring_predisable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_dettach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - void adis16260_unconfigure_ring(struct iio_dev *indio_dev) { kfree(indio_dev->pollfunc); @@ -225,18 +173,16 @@ int adis16260_configure_ring(struct iio_dev *indio_dev) indio_dev->ring = ring; /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); - ring->preenable = &adis16260_data_rdy_ring_preenable; - ring->postenable = &adis16260_data_rdy_ring_postenable; - ring->predisable = &adis16260_data_rdy_ring_predisable; + ring->bpe = 2; + ring->preenable = &iio_sw_ring_preenable; + ring->postenable = &iio_triggered_ring_postenable; + ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; - indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); - if (indio_dev->pollfunc == NULL) { - ret = -ENOMEM; - goto error_iio_sw_rb_free;; - } - indio_dev->pollfunc->poll_func_main = &adis16260_poll_func_th; - indio_dev->pollfunc->private_data = indio_dev; + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16260_poll_func_th); + if (ret) + goto error_iio_sw_rb_free; + indio_dev->modes |= INDIO_RING_TRIGGERED; return 0; @@ -244,13 +190,3 @@ error_iio_sw_rb_free: iio_sw_rb_free(indio_dev->ring); return ret; } - -int adis16260_initialize_ring(struct iio_ring_buffer *ring) -{ - return iio_ring_buffer_register(ring, 0); -} - -void adis16260_uninitialize_ring(struct iio_ring_buffer *ring) -{ - iio_ring_buffer_unregister(ring); -} diff --git a/drivers/staging/iio/gyro/adis16260_trigger.c b/drivers/staging/iio/gyro/adis16260_trigger.c index b3c565942b8..de01537d257 100644 --- a/drivers/staging/iio/gyro/adis16260_trigger.c +++ b/drivers/staging/iio/gyro/adis16260_trigger.c @@ -23,8 +23,7 @@ static int adis16260_data_rdy_trig_poll(struct iio_dev *dev_info, struct adis16260_state *st = iio_dev_get_devdata(dev_info); struct iio_trigger *trig = st->trig; - trig->timestamp = timestamp; - iio_trigger_poll(trig); + iio_trigger_poll(trig, timestamp); return IRQ_HANDLED; } @@ -83,14 +82,13 @@ int adis16260_probe_trigger(struct iio_dev *indio_dev) struct adis16260_state *st = indio_dev->dev_data; st->trig = iio_allocate_trigger(); - st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); + st->trig->name = kasprintf(GFP_KERNEL, + "adis16260-dev%d", + indio_dev->id); if (!st->trig->name) { ret = -ENOMEM; goto error_free_trig; } - snprintf((char *)st->trig->name, - IIO_TRIGGER_NAME_LENGTH, - "adis16260-dev%d", indio_dev->id); st->trig->dev.parent = &st->us->dev; st->trig->owner = THIS_MODULE; st->trig->private_data = st; diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h index fcee47cbe89..9d0ca128679 100644 --- a/drivers/staging/iio/iio.h +++ b/drivers/staging/iio/iio.h @@ -16,9 +16,7 @@ #include "chrdev.h" /* IIO TODO LIST */ -/* Static device specific elements (conversion factors etc) - * should be exported via sysfs - * +/* * Provide means of adjusting timer accuracy. * Currently assumes nano seconds. */ @@ -284,49 +282,6 @@ int iio_push_event(struct iio_dev *dev_info, s64 timestamp); /** - * struct iio_work_cont - container for when singleton handler case matters - * @ws: [DEVICE] work_struct when not only possible event - * @ws_nocheck: [DEVICE] work_struct when only possible event - * @address: [DEVICE] associated register address - * @mask: [DEVICE] associated mask for identifying event source - * @st: [DEVICE] device specific state information - **/ -struct iio_work_cont { - struct work_struct ws; - struct work_struct ws_nocheck; - int address; - int mask; - void *st; -}; - -#define to_iio_work_cont_check(_ws) \ - container_of(_ws, struct iio_work_cont, ws) - -#define to_iio_work_cont_no_check(_ws) \ - container_of(_ws, struct iio_work_cont, ws_nocheck) - -/** - * iio_init_work_cont() - intiialize the elements of a work container - * @cont: the work container - * @_checkfunc: function called when there are multiple possible int sources - * @_nocheckfunc: function for when there is only one int source - * @_add: driver dependent, typically a register address - * @_mask: driver dependent, typically a bit mask for a register - * @_st: driver dependent, typically pointer to a device state structure - **/ -static inline void -iio_init_work_cont(struct iio_work_cont *cont, - void (*_checkfunc)(struct work_struct *), - void (*_nocheckfunc)(struct work_struct *), - int _add, int _mask, void *_st) -{ - INIT_WORK(&(cont)->ws, _checkfunc); - INIT_WORK(&(cont)->ws_nocheck, _nocheckfunc); - cont->address = _add; - cont->mask = _mask; - cont->st = _st; -} -/** * __iio_push_event() - tries to add an event to the list associated with a chrdev * @ev_int: the event interface to which we are pushing the event * @ev_code: the outgoing event code @@ -428,7 +383,9 @@ void iio_put(void); **/ void iio_get(void); -/* Ring buffer related */ +/** + * iio_device_get_chrdev_minor() - get an unused minor number + **/ int iio_device_get_chrdev_minor(void); void iio_device_free_chrdev_minor(int val); diff --git a/drivers/staging/iio/imu/Kconfig b/drivers/staging/iio/imu/Kconfig index 6308d6faad5..31a6233a206 100644 --- a/drivers/staging/iio/imu/Kconfig +++ b/drivers/staging/iio/imu/Kconfig @@ -6,9 +6,8 @@ comment "Inertial measurement units" config ADIS16300 tristate "Analog Devices ADIS16300 IMU SPI driver" depends on SPI - select IIO_SW_RING - select IIO_RING_BUFFER - select IIO_TRIGGER + select IIO_SW_RING if IIO_RING_BUFFER + select IIO_TRIGGER if IIO_RING_BUFFER help Say yes here to build support for Analog Devices adis16300 four degrees of freedom inertial sensor. @@ -24,10 +23,9 @@ config ADIS16350 config ADIS16400 tristate "Analog Devices ADIS16400/5 IMU SPI driver" - depends on SPI - select IIO_SW_RING - select IIO_RING_BUFFER - select IIO_TRIGGER - help - Say yes here to build support for Analog Devices adis16400/5 triaxial - inertial sensor with Magnetometer.
\ No newline at end of file + depends on SPI + select IIO_SW_RING if IIO_RING_BUFFER + select IIO_TRIGGER if IIO_RING_BUFFER + help + Say yes here to build support for Analog Devices adis16400/5 triaxial + inertial sensor with Magnetometer. diff --git a/drivers/staging/iio/imu/Makefile b/drivers/staging/iio/imu/Makefile index 31df7359e20..f3b450b6611 100644 --- a/drivers/staging/iio/imu/Makefile +++ b/drivers/staging/iio/imu/Makefile @@ -1,6 +1,7 @@ # # Makefile for Inertial Measurement Units # + adis16300-y := adis16300_core.o adis16300-$(CONFIG_IIO_RING_BUFFER) += adis16300_ring.o adis16300_trigger.o obj-$(CONFIG_ADIS16300) += adis16300.o @@ -11,4 +12,4 @@ obj-$(CONFIG_ADIS16350) += adis16350.o adis16400-y := adis16400_core.o adis16400-$(CONFIG_IIO_RING_BUFFER) += adis16400_ring.o adis16400_trigger.o -obj-$(CONFIG_ADIS16400) += adis16400.o
\ No newline at end of file +obj-$(CONFIG_ADIS16400) += adis16400.o diff --git a/drivers/staging/iio/imu/adis16300.h b/drivers/staging/iio/imu/adis16300.h index 1c7ea5c840e..1f25d68064a 100644 --- a/drivers/staging/iio/imu/adis16300.h +++ b/drivers/staging/iio/imu/adis16300.h @@ -94,7 +94,6 @@ * struct adis16300_state - device instance specific data * @us: actual spi_device * @work_trigger_to_ring: bh for triggered event handling - * @work_cont_thresh: CLEAN * @inter: used to check if new interrupt has been triggered * @last_timestamp: passing timestamp from th to bh of interrupt handler * @indio_dev: industrial I/O device structure @@ -106,7 +105,6 @@ struct adis16300_state { struct spi_device *us; struct work_struct work_trigger_to_ring; - struct iio_work_cont work_cont_thresh; s64 last_timestamp; struct iio_dev *indio_dev; struct iio_trigger *trig; @@ -115,30 +113,22 @@ struct adis16300_state { struct mutex buf_lock; }; -int adis16300_spi_read_burst(struct device *dev, u8 *rx); - int adis16300_set_irq(struct device *dev, bool enable); -int adis16300_reset(struct device *dev); - -int adis16300_check_status(struct device *dev); - #ifdef CONFIG_IIO_RING_BUFFER /* At the moment triggers are only used for ring buffer * filling. This may change! */ -enum adis16300_scan { - ADIS16300_SCAN_SUPPLY, - ADIS16300_SCAN_GYRO_X, - ADIS16300_SCAN_ACC_X, - ADIS16300_SCAN_ACC_Y, - ADIS16300_SCAN_ACC_Z, - ADIS16300_SCAN_TEMP, - ADIS16300_SCAN_ADC_0, - ADIS16300_SCAN_INCLI_X, - ADIS16300_SCAN_INCLI_Y, -}; +#define ADIS16300_SCAN_SUPPLY 0 +#define ADIS16300_SCAN_GYRO_X 1 +#define ADIS16300_SCAN_ACC_X 2 +#define ADIS16300_SCAN_ACC_Y 3 +#define ADIS16300_SCAN_ACC_Z 4 +#define ADIS16300_SCAN_TEMP 5 +#define ADIS16300_SCAN_ADC_0 6 +#define ADIS16300_SCAN_INCLI_X 7 +#define ADIS16300_SCAN_INCLI_Y 8 void adis16300_remove_trigger(struct iio_dev *indio_dev); int adis16300_probe_trigger(struct iio_dev *indio_dev); diff --git a/drivers/staging/iio/imu/adis16300_core.c b/drivers/staging/iio/imu/adis16300_core.c index 5a7e5ef9bc5..f1950d56cb1 100644 --- a/drivers/staging/iio/imu/adis16300_core.c +++ b/drivers/staging/iio/imu/adis16300_core.c @@ -14,12 +14,13 @@ #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 "../iio.h" #include "../sysfs.h" +#include "../ring_generic.h" #include "../accel/accel.h" #include "../accel/inclinometer.h" #include "../gyro/gyro.h" @@ -29,10 +30,7 @@ #define DRIVER_NAME "adis16300" -/* At the moment the spi framework doesn't allow global setting of cs_change. - * It's in the likely to be added comment at the top of spi.h. - * This means that use cannot be made of spi_write etc. - */ +static int adis16300_check_status(struct device *dev); /** * adis16300_spi_write_reg_8() - write single byte to a register @@ -79,11 +77,13 @@ static int adis16300_spi_write_reg_16(struct device *dev, .bits_per_word = 8, .len = 2, .cs_change = 1, + .delay_usecs = 75, }, { .tx_buf = st->tx + 2, .bits_per_word = 8, .len = 2, .cs_change = 1, + .delay_usecs = 75, }, }; @@ -122,12 +122,14 @@ static int adis16300_spi_read_reg_16(struct device *dev, .tx_buf = st->tx, .bits_per_word = 8, .len = 2, - .cs_change = 0, + .cs_change = 1, + .delay_usecs = 75, }, { .rx_buf = st->rx, .bits_per_word = 8, .len = 2, - .cs_change = 0, + .cs_change = 1, + .delay_usecs = 75, }, }; @@ -154,54 +156,6 @@ error_ret: return ret; } -/** - * adis16300_spi_read_burst() - read all data registers - * @dev: device associated with child of actual device (iio_dev or iio_trig) - * @rx: somewhere to pass back the value read (min size is 24 bytes) - **/ -int adis16300_spi_read_burst(struct device *dev, u8 *rx) -{ - struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct adis16300_state *st = iio_dev_get_devdata(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, - .cs_change = 0, - }, { - .rx_buf = rx, - .bits_per_word = 8, - .len = 18, - .cs_change = 0, - }, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADIS16300_READ_REG(ADIS16300_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(ADIS16300_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 ssize_t adis16300_spi_read_signed(struct device *dev, struct device_attribute *attr, char *buf, @@ -240,6 +194,24 @@ static ssize_t adis16300_read_12bit_unsigned(struct device *dev, return sprintf(buf, "%u\n", val & 0x0FFF); } +static ssize_t adis16300_read_14bit_unsigned(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u16 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = adis16300_spi_read_reg_16(dev, this_attr->address, &val); + if (ret) + return ret; + + if (val & ADIS16300_ERROR_ACTIVE) + adis16300_check_status(dev); + + return sprintf(buf, "%u\n", val & 0x3FFF); +} + static ssize_t adis16300_read_14bit_signed(struct device *dev, struct device_attribute *attr, char *buf) @@ -356,6 +328,18 @@ static ssize_t adis16300_write_frequency(struct device *dev, return ret ? ret : len; } +static int adis16300_reset(struct device *dev) +{ + int ret; + ret = adis16300_spi_write_reg_8(dev, + ADIS16300_GLOB_CMD, + ADIS16300_GLOB_CMD_SW_RESET); + if (ret) + dev_err(dev, "problem resetting device"); + + return ret; +} + static ssize_t adis16300_write_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -371,8 +355,6 @@ static ssize_t adis16300_write_reset(struct device *dev, return -1; } - - int adis16300_set_irq(struct device *dev, bool enable) { int ret; @@ -396,32 +378,37 @@ error_ret: return ret; } -int adis16300_reset(struct device *dev) +/* Power down the device */ +static int adis16300_stop_device(struct device *dev) { int ret; - ret = adis16300_spi_write_reg_8(dev, - ADIS16300_GLOB_CMD, - ADIS16300_GLOB_CMD_SW_RESET); + u16 val = ADIS16300_SLP_CNT_POWER_OFF; + + ret = adis16300_spi_write_reg_16(dev, ADIS16300_SLP_CNT, val); if (ret) - dev_err(dev, "problem resetting device"); + dev_err(dev, "problem with turning device off: SLP_CNT"); return ret; } -/* Power down the device */ -static int adis16300_stop_device(struct device *dev) +static int adis16300_self_test(struct device *dev) { int ret; - u16 val = ADIS16300_SLP_CNT_POWER_OFF; + ret = adis16300_spi_write_reg_16(dev, + ADIS16300_MSC_CTRL, + ADIS16300_MSC_CTRL_MEM_TEST); + if (ret) { + dev_err(dev, "problem starting self test"); + goto err_ret; + } - ret = adis16300_spi_write_reg_16(dev, ADIS16300_SLP_CNT, val); - if (ret) - dev_err(dev, "problem with turning device off: SLP_CNT"); + adis16300_check_status(dev); +err_ret: return ret; } -int adis16300_check_status(struct device *dev) +static int adis16300_check_status(struct device *dev) { u16 status; int ret; @@ -483,6 +470,11 @@ static int adis16300_initial_setup(struct adis16300_state *st) } /* Do self test */ + ret = adis16300_self_test(dev); + if (ret) { + dev_err(dev, "self test failure"); + goto err_ret; + } /* Read status register to check the result */ ret = adis16300_check_status(dev); @@ -526,7 +518,7 @@ static IIO_DEV_ATTR_ACCEL_Z_OFFSET(S_IWUSR | S_IRUGO, adis16300_write_16bit, ADIS16300_ZACCL_OFF); -static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16300_read_14bit_signed, +static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16300_read_14bit_unsigned, ADIS16300_SUPPLY_OUT); static IIO_CONST_ATTR(in_supply_scale, "0.00242"); @@ -548,7 +540,7 @@ static IIO_DEV_ATTR_INCLI_Y(adis16300_read_13bit_signed, ADIS16300_YINCLI_OUT); static IIO_CONST_ATTR(incli_scale, "0.044 d"); -static IIO_DEV_ATTR_TEMP_RAW(adis16300_read_12bit_signed); +static IIO_DEV_ATTR_TEMP_RAW(adis16300_read_12bit_unsigned); static IIO_CONST_ATTR(temp_offset, "198.16 K"); static IIO_CONST_ATTR(temp_scale, "0.14 K"); @@ -653,21 +645,13 @@ static int __devinit adis16300_probe(struct spi_device *spi) goto error_unreg_ring_funcs; regdone = 1; - ret = adis16300_initialize_ring(st->indio_dev->ring); + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); if (ret) { printk(KERN_ERR "failed to initialize the ring\n"); goto error_unreg_ring_funcs; } - if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) { -#if 0 /* fixme: here we should support */ - iio_init_work_cont(&st->work_cont_thresh, - NULL, - adis16300_thresh_handler_bh_no_check, - 0, - 0, - st); -#endif + if (spi->irq) { ret = iio_register_interrupt_line(spi->irq, st->indio_dev, 0, @@ -688,13 +672,12 @@ static int __devinit adis16300_probe(struct spi_device *spi) return 0; error_remove_trigger: - if (st->indio_dev->modes & INDIO_RING_TRIGGERED) - adis16300_remove_trigger(st->indio_dev); + adis16300_remove_trigger(st->indio_dev); error_unregister_line: - if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + if (spi->irq) iio_unregister_interrupt_line(st->indio_dev, 0); error_uninitialize_ring: - adis16300_uninitialize_ring(st->indio_dev->ring); + iio_ring_buffer_unregister(st->indio_dev->ring); error_unreg_ring_funcs: adis16300_unconfigure_ring(st->indio_dev); error_free_dev: @@ -712,7 +695,6 @@ error_ret: return ret; } -/* fixme, confirm ordering in this function */ static int adis16300_remove(struct spi_device *spi) { int ret; @@ -726,12 +708,12 @@ static int adis16300_remove(struct spi_device *spi) flush_scheduled_work(); adis16300_remove_trigger(indio_dev); - if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) + if (spi->irq) iio_unregister_interrupt_line(indio_dev, 0); - adis16300_uninitialize_ring(indio_dev->ring); - adis16300_unconfigure_ring(indio_dev); + iio_ring_buffer_unregister(indio_dev->ring); iio_device_unregister(indio_dev); + adis16300_unconfigure_ring(indio_dev); kfree(st->tx); kfree(st->rx); kfree(st); diff --git a/drivers/staging/iio/imu/adis16300_ring.c b/drivers/staging/iio/imu/adis16300_ring.c index 76cf8a6f3c3..fc93160acb2 100644 --- a/drivers/staging/iio/imu/adis16300_ring.c +++ b/drivers/staging/iio/imu/adis16300_ring.c @@ -6,6 +6,7 @@ #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> @@ -16,17 +17,7 @@ #include "../trigger.h" #include "adis16300.h" -/** - * combine_8_to_16() utility function to munge to u8s into u16 - **/ -static inline u16 combine_8_to_16(u8 lower, u8 upper) -{ - u16 _lower = lower; - u16 _upper = upper; - return _lower | (_upper << 8); -} - -static IIO_SCAN_EL_C(supply, ADIS16300_SCAN_SUPPLY, IIO_SIGNED(14), +static IIO_SCAN_EL_C(supply, ADIS16300_SCAN_SUPPLY, IIO_UNSIGNED(14), ADIS16300_SUPPLY_OUT, NULL); static IIO_SCAN_EL_C(gyro_x, ADIS16300_SCAN_GYRO_X, IIO_SIGNED(14), @@ -39,9 +30,9 @@ static IIO_SCAN_EL_C(accel_y, ADIS16300_SCAN_ACC_Y, IIO_SIGNED(14), static IIO_SCAN_EL_C(accel_z, ADIS16300_SCAN_ACC_Z, IIO_SIGNED(14), ADIS16300_ZACCL_OUT, NULL); -static IIO_SCAN_EL_C(temp, ADIS16300_SCAN_TEMP, IIO_SIGNED(12), +static IIO_SCAN_EL_C(temp, ADIS16300_SCAN_TEMP, IIO_UNSIGNED(12), ADIS16300_TEMP_OUT, NULL); -static IIO_SCAN_EL_C(adc_0, ADIS16300_SCAN_ADC_0, IIO_SIGNED(12), +static IIO_SCAN_EL_C(adc_0, ADIS16300_SCAN_ADC_0, IIO_UNSIGNED(12), ADIS16300_AUX_ADC, NULL); static IIO_SCAN_EL_C(incli_x, ADIS16300_SCAN_INCLI_X, IIO_SIGNED(12), @@ -74,10 +65,10 @@ static struct attribute_group adis16300_scan_el_group = { * adis16300_poll_func_th() top half interrupt handler called by trigger * @private_data: iio_dev **/ -static void adis16300_poll_func_th(struct iio_dev *indio_dev) +static void adis16300_poll_func_th(struct iio_dev *indio_dev, s64 time) { struct adis16300_state *st = iio_dev_get_devdata(indio_dev); - st->last_timestamp = indio_dev->trig->timestamp; + st->last_timestamp = time; schedule_work(&st->work_trigger_to_ring); /* Indicate that this interrupt is being handled */ @@ -87,6 +78,54 @@ static void adis16300_poll_func_th(struct iio_dev *indio_dev) */ } +/** + * adis16300_spi_read_burst() - read all data registers + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @rx: somewhere to pass back the value read (min size is 24 bytes) + **/ +static int adis16300_spi_read_burst(struct device *dev, u8 *rx) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16300_state *st = iio_dev_get_devdata(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, + .cs_change = 0, + }, { + .rx_buf = rx, + .bits_per_word = 8, + .len = 18, + .cs_change = 0, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16300_READ_REG(ADIS16300_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 = ADIS16300_SPI_BURST; + 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; +} + /* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device * specific to be rolled into the core. */ @@ -109,10 +148,9 @@ static void adis16300_trigger_bh_to_ring(struct work_struct *work_s) if (st->indio_dev->scan_count) if (adis16300_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) { - data[i] = combine_8_to_16(st->rx[i*2+1], - st->rx[i*2]); - } + for (; i < st->indio_dev->scan_count; i++) + data[i] = be16_to_cpup( + (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ if (st->indio_dev->scan_timestamp) @@ -127,45 +165,6 @@ static void adis16300_trigger_bh_to_ring(struct work_struct *work_s) return; } -/* in these circumstances is it better to go with unaligned packing and - * deal with the cost?*/ -static int adis16300_data_rdy_ring_preenable(struct iio_dev *indio_dev) -{ - size_t size; - dev_dbg(&indio_dev->dev, "%s\n", __func__); - /* Check if there are any scan elements enabled, if not fail*/ - if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) - return -EINVAL; - - if (indio_dev->ring->access.set_bpd) { - if (indio_dev->scan_timestamp) - if (indio_dev->scan_count) /* Timestamp and data */ - size = 4*sizeof(s64); - else /* Timestamp only */ - size = sizeof(s64); - else /* Data only */ - size = indio_dev->scan_count*sizeof(s16); - indio_dev->ring->access.set_bpd(indio_dev->ring, size); - } - - return 0; -} - -static int adis16300_data_rdy_ring_postenable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_attach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - -static int adis16300_data_rdy_ring_predisable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_dettach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} void adis16300_unconfigure_ring(struct iio_dev *indio_dev) { @@ -202,18 +201,16 @@ int adis16300_configure_ring(struct iio_dev *indio_dev) indio_dev->ring = ring; /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); - ring->preenable = &adis16300_data_rdy_ring_preenable; - ring->postenable = &adis16300_data_rdy_ring_postenable; - ring->predisable = &adis16300_data_rdy_ring_predisable; + ring->bpe = 2; + ring->preenable = &iio_sw_ring_preenable; + ring->postenable = &iio_triggered_ring_postenable; + ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; - indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); - if (indio_dev->pollfunc == NULL) { - ret = -ENOMEM; - goto error_iio_sw_rb_free;; - } - indio_dev->pollfunc->poll_func_main = &adis16300_poll_func_th; - indio_dev->pollfunc->private_data = indio_dev; + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16300_poll_func_th); + if (ret) + goto error_iio_sw_rb_free; + indio_dev->modes |= INDIO_RING_TRIGGERED; return 0; @@ -222,12 +219,3 @@ error_iio_sw_rb_free: return ret; } -int adis16300_initialize_ring(struct iio_ring_buffer *ring) -{ - return iio_ring_buffer_register(ring, 0); -} - -void adis16300_uninitialize_ring(struct iio_ring_buffer *ring) -{ - iio_ring_buffer_unregister(ring); -} diff --git a/drivers/staging/iio/imu/adis16300_trigger.c b/drivers/staging/iio/imu/adis16300_trigger.c index 54edb20bf11..64036cd9910 100644 --- a/drivers/staging/iio/imu/adis16300_trigger.c +++ b/drivers/staging/iio/imu/adis16300_trigger.c @@ -23,8 +23,7 @@ static int adis16300_data_rdy_trig_poll(struct iio_dev *dev_info, struct adis16300_state *st = iio_dev_get_devdata(dev_info); struct iio_trigger *trig = st->trig; - trig->timestamp = timestamp; - iio_trigger_poll(trig); + iio_trigger_poll(trig, timestamp); return IRQ_HANDLED; } @@ -86,14 +85,13 @@ int adis16300_probe_trigger(struct iio_dev *indio_dev) struct adis16300_state *st = indio_dev->dev_data; st->trig = iio_allocate_trigger(); - st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); + st->trig->name = kasprintf(GFP_KERNEL, + "adis16300-dev%d", + indio_dev->id); if (!st->trig->name) { ret = -ENOMEM; goto error_free_trig; } - snprintf((char *)st->trig->name, - IIO_TRIGGER_NAME_LENGTH, - "adis16300-dev%d", indio_dev->id); st->trig->dev.parent = &st->us->dev; st->trig->owner = THIS_MODULE; st->trig->private_data = st; diff --git a/drivers/staging/iio/imu/adis16350.h b/drivers/staging/iio/imu/adis16350.h index 334b18ace38..b00001e3edd 100644 --- a/drivers/staging/iio/imu/adis16350.h +++ b/drivers/staging/iio/imu/adis16350.h @@ -100,7 +100,6 @@ * struct adis16350_state - device instance specific data * @us: actual spi_device * @work_trigger_to_ring: bh for triggered event handling - * @work_cont_thresh: CLEAN * @inter: used to check if new interrupt has been triggered * @last_timestamp: passing timestamp from th to bh of interrupt handler * @indio_dev: industrial I/O device structure @@ -112,7 +111,6 @@ struct adis16350_state { struct spi_device *us; struct work_struct work_trigger_to_ring; - struct iio_work_cont work_cont_data_rdy; s64 last_timestamp; struct iio_dev *indio_dev; struct iio_trigger *trig; @@ -125,19 +123,17 @@ int adis16350_set_irq(struct device *dev, bool enable); #ifdef CONFIG_IIO_RING_BUFFER -enum adis16350_scan { - ADIS16350_SCAN_SUPPLY, - ADIS16350_SCAN_GYRO_X, - ADIS16350_SCAN_GYRO_Y, - ADIS16350_SCAN_GYRO_Z, - ADIS16350_SCAN_ACC_X, - ADIS16350_SCAN_ACC_Y, - ADIS16350_SCAN_ACC_Z, - ADIS16350_SCAN_TEMP_X, - ADIS16350_SCAN_TEMP_Y, - ADIS16350_SCAN_TEMP_Z, - ADIS16350_SCAN_ADC_0 -}; +#define ADIS16350_SCAN_SUPPLY 0 +#define ADIS16350_SCAN_GYRO_X 1 +#define ADIS16350_SCAN_GYRO_Y 2 +#define ADIS16350_SCAN_GYRO_Z 3 +#define ADIS16350_SCAN_ACC_X 4 +#define ADIS16350_SCAN_ACC_Y 5 +#define ADIS16350_SCAN_ACC_Z 6 +#define ADIS16350_SCAN_TEMP_X 7 +#define ADIS16350_SCAN_TEMP_Y 8 +#define ADIS16350_SCAN_TEMP_Z 9 +#define ADIS16350_SCAN_ADC_0 10 void adis16350_remove_trigger(struct iio_dev *indio_dev); int adis16350_probe_trigger(struct iio_dev *indio_dev); @@ -150,8 +146,6 @@ ssize_t adis16350_read_data_from_ring(struct device *dev, int adis16350_configure_ring(struct iio_dev *indio_dev); void adis16350_unconfigure_ring(struct iio_dev *indio_dev); -int adis16350_initialize_ring(struct iio_ring_buffer *ring); -void adis16350_uninitialize_ring(struct iio_ring_buffer *ring); #else /* CONFIG_IIO_RING_BUFFER */ static inline void adis16350_remove_trigger(struct iio_dev *indio_dev) @@ -171,7 +165,7 @@ adis16350_read_data_from_ring(struct device *dev, return 0; } -static int adis16350_configure_ring(struct iio_dev *indio_dev) +static inline int adis16350_configure_ring(struct iio_dev *indio_dev) { return 0; } @@ -179,15 +173,5 @@ static int adis16350_configure_ring(struct iio_dev *indio_dev) static inline void adis16350_unconfigure_ring(struct iio_dev *indio_dev) { } - -static inline int adis16350_initialize_ring(struct iio_ring_buffer *ring) -{ - return 0; -} - -static inline void adis16350_uninitialize_ring(struct iio_ring_buffer *ring) -{ -} - #endif /* CONFIG_IIO_RING_BUFFER */ #endif /* SPI_ADIS16350_H_ */ diff --git a/drivers/staging/iio/imu/adis16350_core.c b/drivers/staging/iio/imu/adis16350_core.c index 0edde73ce5c..1575b7b5d44 100644 --- a/drivers/staging/iio/imu/adis16350_core.c +++ b/drivers/staging/iio/imu/adis16350_core.c @@ -14,12 +14,13 @@ #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 "../iio.h" #include "../sysfs.h" +#include "../ring_generic.h" #include "../accel/accel.h" #include "../adc/adc.h" #include "../gyro/gyro.h" @@ -75,13 +76,13 @@ static int adis16350_spi_write_reg_16(struct device *dev, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, { .tx_buf = st->tx + 2, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, }; @@ -121,13 +122,13 @@ static int adis16350_spi_read_reg_16(struct device *dev, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, { .rx_buf = st->rx, .bits_per_word = 8, .len = 2, .cs_change = 1, - .delay_usecs = 25, + .delay_usecs = 35, }, }; @@ -619,7 +620,7 @@ static int __devinit adis16350_probe(struct spi_device *spi) goto error_unreg_ring_funcs; regdone = 1; - ret = adis16350_initialize_ring(st->indio_dev->ring); + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); if (ret) { printk(KERN_ERR "failed to initialize the ring\n"); goto error_unreg_ring_funcs; @@ -651,7 +652,7 @@ error_unregister_line: if (spi->irq) iio_unregister_interrupt_line(st->indio_dev, 0); error_uninitialize_ring: - adis16350_uninitialize_ring(st->indio_dev->ring); + iio_ring_buffer_unregister(st->indio_dev->ring); error_unreg_ring_funcs: adis16350_unconfigure_ring(st->indio_dev); error_free_dev: @@ -685,7 +686,7 @@ static int adis16350_remove(struct spi_device *spi) if (spi->irq) iio_unregister_interrupt_line(indio_dev, 0); - adis16350_uninitialize_ring(indio_dev->ring); + iio_ring_buffer_unregister(indio_dev->ring); iio_device_unregister(indio_dev); adis16350_unconfigure_ring(indio_dev); kfree(st->tx); diff --git a/drivers/staging/iio/imu/adis16350_ring.c b/drivers/staging/iio/imu/adis16350_ring.c index 5e9716ea7c7..e053e9aaa2e 100644 --- a/drivers/staging/iio/imu/adis16350_ring.c +++ b/drivers/staging/iio/imu/adis16350_ring.c @@ -6,6 +6,7 @@ #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> @@ -16,16 +17,6 @@ #include "../trigger.h" #include "adis16350.h" -/** - * combine_8_to_16() utility function to munge to u8s into u16 - **/ -static inline u16 combine_8_to_16(u8 lower, u8 upper) -{ - u16 _lower = lower; - u16 _upper = upper; - return _lower | (_upper << 8); -} - static IIO_SCAN_EL_C(supply, ADIS16350_SCAN_SUPPLY, IIO_UNSIGNED(12), ADIS16350_SUPPLY_OUT, NULL); @@ -80,10 +71,10 @@ static struct attribute_group adis16350_scan_el_group = { * adis16350_poll_func_th() top half interrupt handler called by trigger * @private_data: iio_dev **/ -static void adis16350_poll_func_th(struct iio_dev *indio_dev) +static void adis16350_poll_func_th(struct iio_dev *indio_dev, s64 time) { struct adis16350_state *st = iio_dev_get_devdata(indio_dev); - st->last_timestamp = indio_dev->trig->timestamp; + st->last_timestamp = time; schedule_work(&st->work_trigger_to_ring); } @@ -157,10 +148,9 @@ static void adis16350_trigger_bh_to_ring(struct work_struct *work_s) if (st->indio_dev->scan_count) if (adis16350_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) { - data[i] = combine_8_to_16(st->rx[i*2+1], - st->rx[i*2]); - } + for (; i < st->indio_dev->scan_count; i++) + data[i] = be16_to_cpup( + (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ if (st->indio_dev->scan_timestamp) @@ -176,48 +166,6 @@ static void adis16350_trigger_bh_to_ring(struct work_struct *work_s) return; } -static int adis16350_data_rdy_ring_preenable(struct iio_dev *indio_dev) -{ - size_t size; - dev_dbg(&indio_dev->dev, "%s\n", __func__); - /* Check if there are any scan elements enabled, if not fail*/ - if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) - return -EINVAL; - - if (indio_dev->ring->access.set_bpd) { - if (indio_dev->scan_timestamp) - if (indio_dev->scan_count) - /* Timestamp (aligned sizeof(s64) and data */ - size = (((indio_dev->scan_count * sizeof(s16)) - + sizeof(s64) - 1) - & ~(sizeof(s64) - 1)) - + sizeof(s64); - else /* Timestamp only */ - size = sizeof(s64); - else /* Data only */ - size = indio_dev->scan_count*sizeof(s16); - indio_dev->ring->access.set_bpd(indio_dev->ring, size); - } - - return 0; -} - -static int adis16350_data_rdy_ring_postenable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_attach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - -static int adis16350_data_rdy_ring_predisable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_dettach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - void adis16350_unconfigure_ring(struct iio_dev *indio_dev) { kfree(indio_dev->pollfunc); @@ -255,18 +203,16 @@ int adis16350_configure_ring(struct iio_dev *indio_dev) indio_dev->ring = ring; /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); - ring->preenable = &adis16350_data_rdy_ring_preenable; - ring->postenable = &adis16350_data_rdy_ring_postenable; - ring->predisable = &adis16350_data_rdy_ring_predisable; + ring->bpe = 2; + ring->preenable = &iio_sw_ring_preenable; + ring->postenable = &iio_triggered_ring_postenable; + ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; - indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); - if (indio_dev->pollfunc == NULL) { - ret = -ENOMEM; - goto error_iio_sw_rb_free;; - } - indio_dev->pollfunc->poll_func_main = &adis16350_poll_func_th; - indio_dev->pollfunc->private_data = indio_dev; + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16350_poll_func_th); + if (ret) + goto error_iio_sw_rb_free; + indio_dev->modes |= INDIO_RING_TRIGGERED; return 0; @@ -275,12 +221,3 @@ error_iio_sw_rb_free: return ret; } -int adis16350_initialize_ring(struct iio_ring_buffer *ring) -{ - return iio_ring_buffer_register(ring, 0); -} - -void adis16350_uninitialize_ring(struct iio_ring_buffer *ring) -{ - iio_ring_buffer_unregister(ring); -} diff --git a/drivers/staging/iio/imu/adis16350_trigger.c b/drivers/staging/iio/imu/adis16350_trigger.c index 1ffa75d05fa..76edccc85b7 100644 --- a/drivers/staging/iio/imu/adis16350_trigger.c +++ b/drivers/staging/iio/imu/adis16350_trigger.c @@ -23,8 +23,7 @@ static int adis16350_data_rdy_trig_poll(struct iio_dev *dev_info, struct adis16350_state *st = iio_dev_get_devdata(dev_info); struct iio_trigger *trig = st->trig; - trig->timestamp = timestamp; - iio_trigger_poll(trig); + iio_trigger_poll(trig, timestamp); return IRQ_HANDLED; } @@ -86,14 +85,13 @@ int adis16350_probe_trigger(struct iio_dev *indio_dev) struct adis16350_state *st = indio_dev->dev_data; st->trig = iio_allocate_trigger(); - st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); + st->trig->name = kasprintf(GFP_KERNEL, + "adis16350-dev%d", + indio_dev->id); if (!st->trig->name) { ret = -ENOMEM; goto error_free_trig; } - snprintf((char *)st->trig->name, - IIO_TRIGGER_NAME_LENGTH, - "adis16350-dev%d", indio_dev->id); st->trig->dev.parent = &st->us->dev; st->trig->owner = THIS_MODULE; st->trig->private_data = st; diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h index 5a69a7ab91c..6ff33e1ad8c 100644 --- a/drivers/staging/iio/imu/adis16400.h +++ b/drivers/staging/iio/imu/adis16400.h @@ -126,7 +126,6 @@ * struct adis16400_state - device instance specific data * @us: actual spi_device * @work_trigger_to_ring: bh for triggered event handling - * @work_cont_thresh: CLEAN * @inter: used to check if new interrupt has been triggered * @last_timestamp: passing timestamp from th to bh of interrupt handler * @indio_dev: industrial I/O device structure @@ -138,7 +137,6 @@ struct adis16400_state { struct spi_device *us; struct work_struct work_trigger_to_ring; - struct iio_work_cont work_cont_thresh; s64 last_timestamp; struct iio_dev *indio_dev; struct iio_trigger *trig; @@ -147,33 +145,25 @@ struct adis16400_state { struct mutex buf_lock; }; -int adis16400_spi_read_burst(struct device *dev, u8 *rx); - int adis16400_set_irq(struct device *dev, bool enable); -int adis16400_reset(struct device *dev); - -int adis16400_check_status(struct device *dev); - #ifdef CONFIG_IIO_RING_BUFFER /* At the moment triggers are only used for ring buffer * filling. This may change! */ -enum adis16400_scan { - ADIS16400_SCAN_SUPPLY, - ADIS16400_SCAN_GYRO_X, - ADIS16400_SCAN_GYRO_Y, - ADIS16400_SCAN_GYRO_Z, - ADIS16400_SCAN_ACC_X, - ADIS16400_SCAN_ACC_Y, - ADIS16400_SCAN_ACC_Z, - ADIS16400_SCAN_MAGN_X, - ADIS16400_SCAN_MAGN_Y, - ADIS16400_SCAN_MAGN_Z, - ADIS16400_SCAN_TEMP, - ADIS16400_SCAN_ADC_0 -}; +#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 ADIS16400_SCAN_MAGN_Y 8 +#define ADIS16400_SCAN_MAGN_Z 9 +#define ADIS16400_SCAN_TEMP 10 +#define ADIS16400_SCAN_ADC_0 11 void adis16400_remove_trigger(struct iio_dev *indio_dev); int adis16400_probe_trigger(struct iio_dev *indio_dev); @@ -186,8 +176,6 @@ ssize_t adis16400_read_data_from_ring(struct device *dev, int adis16400_configure_ring(struct iio_dev *indio_dev); void adis16400_unconfigure_ring(struct iio_dev *indio_dev); -int adis16400_initialize_ring(struct iio_ring_buffer *ring); -void adis16400_uninitialize_ring(struct iio_ring_buffer *ring); #else /* CONFIG_IIO_RING_BUFFER */ static inline void adis16400_remove_trigger(struct iio_dev *indio_dev) @@ -216,14 +204,5 @@ static inline void adis16400_unconfigure_ring(struct iio_dev *indio_dev) { } -static inline int adis16400_initialize_ring(struct iio_ring_buffer *ring) -{ - return 0; -} - -static inline void adis16400_uninitialize_ring(struct iio_ring_buffer *ring) -{ -} - #endif /* CONFIG_IIO_RING_BUFFER */ #endif /* SPI_ADIS16400_H_ */ diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index e69e2ce47da..6013fee218e 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -21,12 +21,13 @@ #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 "../iio.h" #include "../sysfs.h" +#include "../ring_generic.h" #include "../accel/accel.h" #include "../adc/adc.h" #include "../gyro/gyro.h" @@ -36,6 +37,8 @@ #define DRIVER_NAME "adis16400" +static int adis16400_check_status(struct device *dev); + /* At the moment the spi framework doesn't allow global setting of cs_change. * It's in the likely to be added comment at the top of spi.h. * This means that use cannot be made of spi_write etc. @@ -161,54 +164,6 @@ error_ret: return ret; } -/** - * adis16400_spi_read_burst() - read all data registers - * @dev: device associated with child of actual device (iio_dev or iio_trig) - * @rx: somewhere to pass back the value read (min size is 24 bytes) - **/ -int adis16400_spi_read_burst(struct device *dev, u8 *rx) -{ - struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct adis16400_state *st = iio_dev_get_devdata(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, - .cs_change = 0, - }, { - .rx_buf = rx, - .bits_per_word = 8, - .len = 24, - .cs_change = 1, - }, - }; - - 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 ssize_t adis16400_spi_read_signed(struct device *dev, struct device_attribute *attr, char *buf, @@ -277,7 +232,6 @@ static ssize_t adis16400_read_12bit_signed(struct device *dev, return ret; } - static ssize_t adis16400_write_16bit(struct device *dev, struct device_attribute *attr, const char *buf, @@ -349,6 +303,18 @@ static ssize_t adis16400_write_frequency(struct device *dev, return ret ? ret : len; } +static int adis16400_reset(struct device *dev) +{ + int ret; + ret = adis16400_spi_write_reg_8(dev, + ADIS16400_GLOB_CMD, + ADIS16400_GLOB_CMD_SW_RESET); + if (ret) + dev_err(dev, "problem resetting device"); + + return ret; +} + static ssize_t adis16400_write_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -364,8 +330,6 @@ static ssize_t adis16400_write_reset(struct device *dev, return -1; } - - int adis16400_set_irq(struct device *dev, bool enable) { int ret; @@ -388,18 +352,6 @@ error_ret: return ret; } -int adis16400_reset(struct device *dev) -{ - int ret; - ret = adis16400_spi_write_reg_8(dev, - ADIS16400_GLOB_CMD, - ADIS16400_GLOB_CMD_SW_RESET); - if (ret) - dev_err(dev, "problem resetting device"); - - return ret; -} - /* Power down the device */ static int adis16400_stop_device(struct device *dev) { @@ -430,7 +382,7 @@ err_ret: return ret; } -int adis16400_check_status(struct device *dev) +static int adis16400_check_status(struct device *dev) { u16 status; int ret; @@ -496,6 +448,11 @@ static int adis16400_initial_setup(struct adis16400_state *st) } /* Do self test */ + ret = adis16400_self_test(dev); + if (ret) { + dev_err(dev, "self test failure"); + goto err_ret; + } /* Read status register to check the result */ ret = adis16400_check_status(dev); @@ -685,21 +642,13 @@ static int __devinit adis16400_probe(struct spi_device *spi) goto error_unreg_ring_funcs; regdone = 1; - ret = adis16400_initialize_ring(st->indio_dev->ring); + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); if (ret) { printk(KERN_ERR "failed to initialize the ring\n"); goto error_unreg_ring_funcs; } if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) { -#if 0 /* fixme: here we should support */ - iio_init_work_cont(&st->work_cont_thresh, - NULL, - adis16400_thresh_handler_bh_no_check, - 0, - 0, - st); -#endif ret = iio_register_interrupt_line(spi->irq, st->indio_dev, 0, @@ -726,7 +675,7 @@ error_unregister_line: if (st->indio_dev->modes & INDIO_RING_TRIGGERED) iio_unregister_interrupt_line(st->indio_dev, 0); error_uninitialize_ring: - adis16400_uninitialize_ring(st->indio_dev->ring); + iio_ring_buffer_unregister(st->indio_dev->ring); error_unreg_ring_funcs: adis16400_unconfigure_ring(st->indio_dev); error_free_dev: @@ -761,7 +710,7 @@ static int adis16400_remove(struct spi_device *spi) if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) iio_unregister_interrupt_line(indio_dev, 0); - adis16400_uninitialize_ring(indio_dev->ring); + iio_ring_buffer_unregister(st->indio_dev->ring); adis16400_unconfigure_ring(indio_dev); iio_device_unregister(indio_dev); kfree(st->tx); diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c index 5529b32bd2e..949db76283d 100644 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ b/drivers/staging/iio/imu/adis16400_ring.c @@ -6,6 +6,7 @@ #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> @@ -16,16 +17,6 @@ #include "../trigger.h" #include "adis16400.h" -/** - * combine_8_to_16() utility function to munge to u8s into u16 - **/ -static inline u16 combine_8_to_16(u8 lower, u8 upper) -{ - u16 _lower = lower; - u16 _upper = upper; - return _lower | (_upper << 8); -} - static IIO_SCAN_EL_C(supply, ADIS16400_SCAN_SUPPLY, IIO_SIGNED(14), ADIS16400_SUPPLY_OUT, NULL); @@ -83,10 +74,10 @@ static struct attribute_group adis16400_scan_el_group = { * adis16400_poll_func_th() top half interrupt handler called by trigger * @private_data: iio_dev **/ -static void adis16400_poll_func_th(struct iio_dev *indio_dev) +static void adis16400_poll_func_th(struct iio_dev *indio_dev, s64 time) { struct adis16400_state *st = iio_dev_get_devdata(indio_dev); - st->last_timestamp = indio_dev->trig->timestamp; + st->last_timestamp = time; schedule_work(&st->work_trigger_to_ring); /* Indicate that this interrupt is being handled */ @@ -96,6 +87,54 @@ static void adis16400_poll_func_th(struct iio_dev *indio_dev) */ } +/** + * adis16400_spi_read_burst() - read all data registers + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @rx: somewhere to pass back the value read (min size is 24 bytes) + **/ +static int adis16400_spi_read_burst(struct device *dev, u8 *rx) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16400_state *st = iio_dev_get_devdata(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, + .cs_change = 0, + }, { + .rx_buf = rx, + .bits_per_word = 8, + .len = 24, + .cs_change = 1, + }, + }; + + 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; +} + /* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device * specific to be rolled into the core. */ @@ -118,10 +157,9 @@ static void adis16400_trigger_bh_to_ring(struct work_struct *work_s) if (st->indio_dev->scan_count) if (adis16400_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) { - data[i] = combine_8_to_16(st->rx[i*2+1], - st->rx[i*2]); - } + for (; i < st->indio_dev->scan_count; i++) + data[i] = be16_to_cpup( + (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ if (st->indio_dev->scan_timestamp) @@ -136,45 +174,6 @@ static void adis16400_trigger_bh_to_ring(struct work_struct *work_s) return; } -/* in these circumstances is it better to go with unaligned packing and - * deal with the cost?*/ -static int adis16400_data_rdy_ring_preenable(struct iio_dev *indio_dev) -{ - size_t size; - dev_dbg(&indio_dev->dev, "%s\n", __func__); - /* Check if there are any scan elements enabled, if not fail*/ - if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) - return -EINVAL; - - if (indio_dev->ring->access.set_bpd) { - if (indio_dev->scan_timestamp) - if (indio_dev->scan_count) /* Timestamp and data */ - size = 6*sizeof(s64); - else /* Timestamp only */ - size = sizeof(s64); - else /* Data only */ - size = indio_dev->scan_count*sizeof(s16); - indio_dev->ring->access.set_bpd(indio_dev->ring, size); - } - - return 0; -} - -static int adis16400_data_rdy_ring_postenable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_attach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} - -static int adis16400_data_rdy_ring_predisable(struct iio_dev *indio_dev) -{ - return indio_dev->trig - ? iio_trigger_dettach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; -} void adis16400_unconfigure_ring(struct iio_dev *indio_dev) { @@ -214,18 +213,16 @@ int adis16400_configure_ring(struct iio_dev *indio_dev) indio_dev->ring = ring; /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); - ring->preenable = &adis16400_data_rdy_ring_preenable; - ring->postenable = &adis16400_data_rdy_ring_postenable; - ring->predisable = &adis16400_data_rdy_ring_predisable; + ring->bpe = 2; + ring->preenable = &iio_sw_ring_preenable; + ring->postenable = &iio_triggered_ring_postenable; + ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; - indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); - if (indio_dev->pollfunc == NULL) { - ret = -ENOMEM; - goto error_iio_sw_rb_free;; - } - indio_dev->pollfunc->poll_func_main = &adis16400_poll_func_th; - indio_dev->pollfunc->private_data = indio_dev; + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16400_poll_func_th); + if (ret) + goto error_iio_sw_rb_free; + indio_dev->modes |= INDIO_RING_TRIGGERED; return 0; @@ -233,13 +230,3 @@ error_iio_sw_rb_free: iio_sw_rb_free(indio_dev->ring); return ret; } - -int adis16400_initialize_ring(struct iio_ring_buffer *ring) -{ - return iio_ring_buffer_register(ring, 0); -} - -void adis16400_uninitialize_ring(struct iio_ring_buffer *ring) -{ - iio_ring_buffer_unregister(ring); -} diff --git a/drivers/staging/iio/imu/adis16400_trigger.c b/drivers/staging/iio/imu/adis16400_trigger.c index 3b3250ac768..aafe6010f1b 100644 --- a/drivers/staging/iio/imu/adis16400_trigger.c +++ b/drivers/staging/iio/imu/adis16400_trigger.c @@ -23,8 +23,7 @@ static int adis16400_data_rdy_trig_poll(struct iio_dev *dev_info, struct adis16400_state *st = iio_dev_get_devdata(dev_info); struct iio_trigger *trig = st->trig; - trig->timestamp = timestamp; - iio_trigger_poll(trig); + iio_trigger_poll(trig, timestamp); return IRQ_HANDLED; } @@ -86,14 +85,13 @@ int adis16400_probe_trigger(struct iio_dev *indio_dev) struct adis16400_state *st = indio_dev->dev_data; st->trig = iio_allocate_trigger(); - st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); + st->trig->name = kasprintf(GFP_KERNEL, + "adis16400-dev%d", + indio_dev->id); if (!st->trig->name) { ret = -ENOMEM; goto error_free_trig; } - snprintf((char *)st->trig->name, - IIO_TRIGGER_NAME_LENGTH, - "adis16400-dev%d", indio_dev->id); st->trig->dev.parent = &st->us->dev; st->trig->owner = THIS_MODULE; st->trig->private_data = st; diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c index 01030684ef2..dd4d87a8bca 100644 --- a/drivers/staging/iio/industrialio-core.c +++ b/drivers/staging/iio/industrialio-core.c @@ -30,9 +30,6 @@ /* IDR to assign each registered device a unique id*/ static DEFINE_IDR(iio_idr); - -/* IDR for general event identifiers */ -static DEFINE_IDR(iio_event_idr); /* IDR to allocate character device minor numbers */ static DEFINE_IDR(iio_chrdev_idr); /* Lock used to protect both of the above */ @@ -654,16 +651,11 @@ static int iio_device_register_eventset(struct iio_dev *dev_info) for (i = 0; i < dev_info->num_interrupt_lines; i++) { dev_info->event_interfaces[i].owner = dev_info->driver_module; - ret = iio_get_new_idr_val(&iio_event_idr); - if (ret < 0) - goto error_free_setup_ev_ints; - else - dev_info->event_interfaces[i].id = ret; snprintf(dev_info->event_interfaces[i]._name, 20, "%s:event%d", dev_name(&dev_info->dev), - dev_info->event_interfaces[i].id); + i); ret = iio_setup_ev_int(&dev_info->event_interfaces[i], (const char *)(dev_info @@ -674,8 +666,6 @@ static int iio_device_register_eventset(struct iio_dev *dev_info) if (ret) { dev_err(&dev_info->dev, "Could not get chrdev interface\n"); - iio_free_idr_val(&iio_event_idr, - dev_info->event_interfaces[i].id); goto error_free_setup_ev_ints; } @@ -711,11 +701,8 @@ error_remove_sysfs_interfaces: ->event_interfaces[j].dev.kobj, &dev_info->event_attrs[j]); error_free_setup_ev_ints: - for (j = 0; j < i; j++) { - iio_free_idr_val(&iio_event_idr, - dev_info->event_interfaces[j].id); + for (j = 0; j < i; j++) iio_free_ev_int(&dev_info->event_interfaces[j]); - } kfree(dev_info->interrupts); error_free_event_interfaces: kfree(dev_info->event_interfaces); @@ -735,11 +722,8 @@ static void iio_device_unregister_eventset(struct iio_dev *dev_info) ->event_interfaces[i].dev.kobj, &dev_info->event_attrs[i]); - for (i = 0; i < dev_info->num_interrupt_lines; i++) { - iio_free_idr_val(&iio_event_idr, - dev_info->event_interfaces[i].id); + for (i = 0; i < dev_info->num_interrupt_lines; i++) iio_free_ev_int(&dev_info->event_interfaces[i]); - } kfree(dev_info->interrupts); kfree(dev_info->event_interfaces); } diff --git a/drivers/staging/iio/industrialio-ring.c b/drivers/staging/iio/industrialio-ring.c index ada159bbb1f..6ab578e4f5f 100644 --- a/drivers/staging/iio/industrialio-ring.c +++ b/drivers/staging/iio/industrialio-ring.c @@ -149,12 +149,10 @@ __iio_request_ring_buffer_event_chrdev(struct iio_ring_buffer *buf, { int ret; - buf->ev_int.id = id; - snprintf(buf->ev_int._name, sizeof(buf->ev_int._name), "%s:event%d", dev_name(&buf->dev), - buf->ev_int.id); + id); ret = iio_setup_ev_int(&(buf->ev_int), buf->ev_int._name, owner, diff --git a/drivers/staging/iio/industrialio-trigger.c b/drivers/staging/iio/industrialio-trigger.c index 5682e61600f..57dd9232cf0 100644 --- a/drivers/staging/iio/industrialio-trigger.c +++ b/drivers/staging/iio/industrialio-trigger.c @@ -31,7 +31,6 @@ * Any other suggestions? */ - static DEFINE_IDR(iio_trigger_idr); static DEFINE_SPINLOCK(iio_trigger_idr_lock); @@ -173,7 +172,7 @@ struct iio_trigger *iio_trigger_find_by_name(const char *name, size_t len) } EXPORT_SYMBOL(iio_trigger_find_by_name); -void iio_trigger_poll(struct iio_trigger *trig) +void iio_trigger_poll(struct iio_trigger *trig, s64 time) { struct iio_poll_func *pf_cursor; @@ -185,7 +184,8 @@ void iio_trigger_poll(struct iio_trigger *trig) } list_for_each_entry(pf_cursor, &trig->pollfunc_list, list) { if (pf_cursor->poll_func_main) { - pf_cursor->poll_func_main(pf_cursor->private_data); + pf_cursor->poll_func_main(pf_cursor->private_data, + time); trig->use_count++; } } @@ -198,8 +198,7 @@ void iio_trigger_notify_done(struct iio_trigger *trig) if (trig->use_count == 0 && trig->try_reenable) if (trig->try_reenable(trig)) { /* Missed and interrupt so launch new poll now */ - trig->timestamp = 0; - iio_trigger_poll(trig); + iio_trigger_poll(trig, 0); } } EXPORT_SYMBOL(iio_trigger_notify_done); @@ -284,7 +283,7 @@ error_ret: EXPORT_SYMBOL(iio_trigger_dettach_poll_func); /** - * iio_trigger_read_currrent() trigger consumer sysfs query which trigger + * iio_trigger_read_currrent() - trigger consumer sysfs query which trigger * * For trigger consumers the current_trigger interface allows the trigger * used by the device to be queried. @@ -296,10 +295,9 @@ static ssize_t iio_trigger_read_current(struct device *dev, struct iio_dev *dev_info = dev_get_drvdata(dev); int len = 0; if (dev_info->trig) - len = snprintf(buf, - IIO_TRIGGER_NAME_LENGTH, - "%s\n", - dev_info->trig->name); + len = sprintf(buf, + "%s\n", + dev_info->trig->name); return len; } @@ -324,8 +322,6 @@ static ssize_t iio_trigger_write_current(struct device *dev, } mutex_unlock(&dev_info->mlock); - len = len < IIO_TRIGGER_NAME_LENGTH ? len : IIO_TRIGGER_NAME_LENGTH; - dev_info->trig = iio_trigger_find_by_name(buf, len); if (oldtrig && dev_info->trig != oldtrig) iio_put_trigger(oldtrig); @@ -402,3 +398,34 @@ int iio_device_unregister_trigger_consumer(struct iio_dev *dev_info) } EXPORT_SYMBOL(iio_device_unregister_trigger_consumer); +int iio_alloc_pollfunc(struct iio_dev *indio_dev, + void (*immediate)(struct iio_dev *indio_dev), + void (*main)(struct iio_dev *private_data, s64 time)) +{ + indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL); + if (indio_dev->pollfunc == NULL) + return -ENOMEM; + indio_dev->pollfunc->poll_func_immediate = immediate; + indio_dev->pollfunc->poll_func_main = main; + indio_dev->pollfunc->private_data = indio_dev; + return 0; +} +EXPORT_SYMBOL(iio_alloc_pollfunc); + +int iio_triggered_ring_postenable(struct iio_dev *indio_dev) +{ + return indio_dev->trig + ? iio_trigger_attach_poll_func(indio_dev->trig, + indio_dev->pollfunc) + : 0; +} +EXPORT_SYMBOL(iio_triggered_ring_postenable); + +int iio_triggered_ring_predisable(struct iio_dev *indio_dev) +{ + return indio_dev->trig + ? iio_trigger_dettach_poll_func(indio_dev->trig, + indio_dev->pollfunc) + : 0; +} +EXPORT_SYMBOL(iio_triggered_ring_predisable); diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig index 80cb6e590fb..3ddc478e618 100644 --- a/drivers/staging/iio/light/Kconfig +++ b/drivers/staging/iio/light/Kconfig @@ -12,4 +12,3 @@ config SENSORS_TSL2563 This driver can also be built as a module. If so, the module will be called tsl2563. - diff --git a/drivers/staging/iio/light/light.h b/drivers/staging/iio/light/light.h index f00f827689c..e4e1e2c4139 100644 --- a/drivers/staging/iio/light/light.h +++ b/drivers/staging/iio/light/light.h @@ -2,11 +2,6 @@ /* Light to digital sensor attributes */ -#define IIO_DEV_ATTR_LIGHT_INFRARED(_num, _show, _addr) \ - IIO_DEVICE_ATTR(light_infrared##_num, S_IRUGO, _show, NULL, _addr) +#define IIO_EVENT_CODE_LIGHT_THRESH IIO_EVENT_CODE_LIGHT_BASE -#define IIO_DEV_ATTR_LIGHT_BROAD(_num, _show, _addr) \ - IIO_DEVICE_ATTR(light_broadspectrum##_num, S_IRUGO, _show, NULL, _addr) -#define IIO_DEV_ATTR_LIGHT_VISIBLE(_num, _show, _addr) \ - IIO_DEVICE_ATTR(light_visible##_num, S_IRUGO, _show, NULL, _addr) diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c index e4b0a5ef1c1..98f8b78f5d8 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/staging/iio/light/tsl2563.c @@ -27,6 +27,7 @@ #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> @@ -117,15 +118,17 @@ struct tsl2563_chip { struct iio_dev *indio_dev; struct delayed_work poweroff_work; + struct work_struct work_thresh; + s64 event_timestamp; /* Remember state for suspend and resume functions */ pm_message_t state; struct tsl2563_gainlevel_coeff *gainlevel; - /* Thresholds are in lux */ u16 low_thres; u16 high_thres; u8 intr; + bool int_enabled; /* Calibration coefficients */ u32 calib0; @@ -189,17 +192,29 @@ static int tsl2563_get_power(struct tsl2563_chip *chip) static int tsl2563_configure(struct tsl2563_chip *chip) { - struct i2c_client *client = chip->client; int ret; - ret = tsl2563_write(client, TSL2563_REG_TIMING, + ret = tsl2563_write(chip->client, TSL2563_REG_TIMING, chip->gainlevel->gaintime); if (ret) - goto out; - - ret = tsl2563_write(client, TSL2563_REG_INT, chip->intr); - -out: + goto error_ret; + ret = tsl2563_write(chip->client, TSL2563_REG_HIGHLOW, + chip->high_thres & 0xFF); + if (ret) + goto error_ret; + ret = tsl2563_write(chip->client, TSL2563_REG_HIGHHIGH, + (chip->high_thres >> 8) & 0xFF); + if (ret) + goto error_ret; + ret = tsl2563_write(chip->client, TSL2563_REG_LOWLOW, + chip->low_thres & 0xFF); + if (ret) + goto error_ret; + ret = tsl2563_write(chip->client, 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; } @@ -323,21 +338,23 @@ static int tsl2563_get_adc(struct tsl2563_chip *chip) if (chip->state.event != PM_EVENT_ON) goto out; - 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); + 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 = tsl2563_read(client, - TSL2563_REG_DATA0LOW | TSL2563_CLEARINT, + TSL2563_REG_DATA0LOW, buf0, sizeof(buf0)); if (ret != sizeof(buf0)) goto out; @@ -356,7 +373,8 @@ static int tsl2563_get_adc(struct tsl2563_chip *chip) chip->data0 = normalize_adc(adc0, chip->gainlevel->gaintime); chip->data1 = normalize_adc(adc1, chip->gainlevel->gaintime); - schedule_delayed_work(&chip->poweroff_work, 5 * HZ); + if (!chip->int_enabled) + schedule_delayed_work(&chip->poweroff_work, 5 * HZ); ret = 0; out: @@ -449,11 +467,12 @@ static unsigned int adc_to_lux(u32 adc0, u32 adc1) /* Sysfs interface */ /*--------------------------------------------------------------*/ -static ssize_t tsl2563_adc0_show(struct device *dev, +static ssize_t tsl2563_adc_show(struct device *dev, struct device_attribute *attr, char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct tsl2563_chip *chip = indio_dev->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; mutex_lock(&chip->lock); @@ -462,26 +481,14 @@ static ssize_t tsl2563_adc0_show(struct device *dev, if (ret) goto out; - ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data0); -out: - mutex_unlock(&chip->lock); - return ret; -} - -static ssize_t tsl2563_adc1_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct tsl2563_chip *chip = indio_dev->dev_data; - int ret; - - mutex_lock(&chip->lock); - - ret = tsl2563_get_adc(chip); - if (ret) - goto out; - - ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data1); + switch (this_attr->address) { + case 0: + ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data0); + break; + case 1: + ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data1); + break; + } out: mutex_unlock(&chip->lock); return ret; @@ -527,37 +534,36 @@ static ssize_t format_calib(char *buf, int len, u32 calib) return snprintf(buf, PAGE_SIZE, "%d\n", calib_to_sysfs(calib)); } -static ssize_t tsl2563_calib0_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct tsl2563_chip *chip = indio_dev->dev_data; - int ret; - - mutex_lock(&chip->lock); - ret = format_calib(buf, PAGE_SIZE, chip->calib0); - mutex_unlock(&chip->lock); - return ret; -} - -static ssize_t tsl2563_calib1_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t tsl2563_calib_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct tsl2563_chip *chip = indio_dev->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; mutex_lock(&chip->lock); - ret = format_calib(buf, PAGE_SIZE, chip->calib1); + switch (this_attr->address) { + case 0: + ret = format_calib(buf, PAGE_SIZE, chip->calib0); + break; + case 1: + ret = format_calib(buf, PAGE_SIZE, chip->calib1); + break; + default: + ret = -ENODEV; + } mutex_unlock(&chip->lock); return ret; } -static int do_calib_store(struct device *dev, const char *buf, size_t len, - int ch) +static ssize_t tsl2563_calib_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct tsl2563_chip *chip = indio_dev->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int value; u32 calib; @@ -566,37 +572,27 @@ static int do_calib_store(struct device *dev, const char *buf, size_t len, calib = calib_from_sysfs(value); - if (ch) - chip->calib1 = calib; - else + switch (this_attr->address) { + case 0: chip->calib0 = calib; + break; + case 1: + chip->calib1 = calib; + break; + } return len; } -static ssize_t tsl2563_calib0_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - return do_calib_store(dev, buf, len, 0); -} - -static ssize_t tsl2563_calib1_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - return do_calib_store(dev, buf, len, 1); -} - -/* AmitXXXX: Convert to IIO_DEV_ATTR_LIGHT* as in tsl2561 - * once I understand what they mean */ -static DEVICE_ATTR(adc0, S_IRUGO, tsl2563_adc0_show, NULL); -static DEVICE_ATTR(adc1, S_IRUGO, tsl2563_adc1_show, NULL); +static IIO_DEVICE_ATTR(intensity_both_raw, S_IRUGO, + tsl2563_adc_show, NULL, 0); +static IIO_DEVICE_ATTR(intensity_ir_raw, S_IRUGO, + tsl2563_adc_show, NULL, 1); static DEVICE_ATTR(illuminance0_input, S_IRUGO, tsl2563_lux_show, NULL); -static DEVICE_ATTR(calib0, S_IRUGO | S_IWUSR, - tsl2563_calib0_show, tsl2563_calib0_store); -static DEVICE_ATTR(calib1, S_IRUGO | S_IWUSR, - tsl2563_calib1_show, tsl2563_calib1_store); +static IIO_DEVICE_ATTR(intensity_both_calibgain, S_IRUGO | S_IWUSR, + tsl2563_calib_show, tsl2563_calib_store, 0); +static IIO_DEVICE_ATTR(intensity_ir_calibgain, S_IRUGO | S_IWUSR, + tsl2563_calib_show, tsl2563_calib_store, 1); static ssize_t tsl2563_show_name(struct device *dev, struct device_attribute *attr, @@ -610,11 +606,11 @@ static ssize_t tsl2563_show_name(struct device *dev, static DEVICE_ATTR(name, S_IRUGO, tsl2563_show_name, NULL); static struct attribute *tsl2563_attributes[] = { - &dev_attr_adc0.attr, - &dev_attr_adc1.attr, + &iio_dev_attr_intensity_both_raw.dev_attr.attr, + &iio_dev_attr_intensity_ir_raw.dev_attr.attr, &dev_attr_illuminance0_input.attr, - &dev_attr_calib0.attr, - &dev_attr_calib1.attr, + &iio_dev_attr_intensity_both_calibgain.dev_attr.attr, + &iio_dev_attr_intensity_ir_calibgain.dev_attr.attr, &dev_attr_name.attr, NULL }; @@ -623,6 +619,192 @@ static const struct attribute_group tsl2563_group = { .attrs = tsl2563_attributes, }; +static ssize_t tsl2563_read_thresh(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2563_chip *chip = indio_dev->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + u16 val = 0; + switch (this_attr->address) { + case TSL2563_REG_HIGHLOW: + val = chip->high_thres; + break; + case TSL2563_REG_LOWLOW: + val = chip->low_thres; + break; + } + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t tsl2563_write_thresh(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2563_chip *chip = indio_dev->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + return ret; + mutex_lock(&chip->lock); + ret = tsl2563_write(chip->client, this_attr->address, val & 0xFF); + if (ret) + goto error_ret; + ret = tsl2563_write(chip->client, this_attr->address + 1, + (val >> 8) & 0xFF); + switch (this_attr->address) { + case TSL2563_REG_HIGHLOW: + chip->high_thres = val; + break; + case TSL2563_REG_LOWLOW: + chip->low_thres = val; + break; + } + +error_ret: + mutex_unlock(&chip->lock); + + return ret < 0 ? ret : len; +} + +static IIO_DEVICE_ATTR(intensity_both_thresh_high_value, + S_IRUGO | S_IWUSR, + tsl2563_read_thresh, + tsl2563_write_thresh, + TSL2563_REG_HIGHLOW); + +static IIO_DEVICE_ATTR(intensity_both_thresh_low_value, + S_IRUGO | S_IWUSR, + tsl2563_read_thresh, + tsl2563_write_thresh, + TSL2563_REG_LOWLOW); + +static int tsl2563_int_th(struct iio_dev *dev_info, + int index, + s64 timestamp, + int not_test) +{ + struct tsl2563_chip *chip = dev_info->dev_data; + + chip->event_timestamp = timestamp; + schedule_work(&chip->work_thresh); + + return 0; +} + +static void tsl2563_int_bh(struct work_struct *work_s) +{ + struct tsl2563_chip *chip + = container_of(work_s, + struct tsl2563_chip, work_thresh); + u8 cmd = TSL2563_CMD | TSL2563_CLEARINT; + + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_LIGHT_BASE, + chip->event_timestamp); + + /* reenable_irq */ + enable_irq(chip->client->irq); + /* clear the interrupt and push the event */ + i2c_master_send(chip->client, &cmd, sizeof(cmd)); + +} + +static ssize_t tsl2563_write_interrupt_config(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2563_chip *chip = indio_dev->dev_data; + struct iio_event_attr *this_attr = to_iio_event_attr(attr); + int input, ret = 0; + + ret = sscanf(buf, "%d", &input); + if (ret != 1) + return -EINVAL; + mutex_lock(&chip->lock); + if (input && !(chip->intr & 0x30)) { + iio_add_event_to_list(this_attr->listel, + &indio_dev->interrupts[0]->ev_list); + 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 = tsl2563_write(chip->client, TSL2563_REG_INT, chip->intr); + chip->int_enabled = true; + } + + if (!input && (chip->intr & 0x30)) { + chip->intr |= ~0x30; + ret = tsl2563_write(chip->client, TSL2563_REG_INT, chip->intr); + iio_remove_event_from_list(this_attr->listel, + &indio_dev->interrupts[0]->ev_list); + 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 < 0) ? ret : len; +} + +static ssize_t tsl2563_read_interrupt_config(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2563_chip *chip = indio_dev->dev_data; + int ret; + u8 rxbuf; + ssize_t len; + + mutex_lock(&chip->lock); + ret = tsl2563_read(chip->client, + TSL2563_REG_INT, + &rxbuf, + sizeof(rxbuf)); + mutex_unlock(&chip->lock); + if (ret < 0) + goto error_ret; + len = snprintf(buf, PAGE_SIZE, "%d\n", !!(rxbuf & 0x30)); +error_ret: + + return (ret < 0) ? ret : len; +} + +IIO_EVENT_ATTR(intensity_both_thresh_both_en, + tsl2563_read_interrupt_config, + tsl2563_write_interrupt_config, + 0, + tsl2563_int_th); + +static struct attribute *tsl2563_event_attributes[] = { + &iio_event_attr_intensity_both_thresh_both_en.dev_attr.attr, + &iio_dev_attr_intensity_both_thresh_high_value.dev_attr.attr, + &iio_dev_attr_intensity_both_thresh_low_value.dev_attr.attr, + NULL, +}; + +static struct attribute_group tsl2563_event_attribute_group = { + .attrs = tsl2563_event_attributes, +}; + /*--------------------------------------------------------------*/ /* Probe, Attach, Remove */ /*--------------------------------------------------------------*/ @@ -641,6 +823,7 @@ static int __devinit tsl2563_probe(struct i2c_client *client, if (!chip) return -ENOMEM; + INIT_WORK(&chip->work_thresh, tsl2563_int_bh); i2c_set_clientdata(client, chip); chip->client = client; @@ -679,18 +862,36 @@ static int __devinit tsl2563_probe(struct i2c_client *client, chip->indio_dev->dev_data = (void *)(chip); chip->indio_dev->driver_module = THIS_MODULE; chip->indio_dev->modes = INDIO_DIRECT_MODE; + if (client->irq) { + chip->indio_dev->num_interrupt_lines = 1; + chip->indio_dev->event_attrs + = &tsl2563_event_attribute_group; + } ret = iio_device_register(chip->indio_dev); if (ret) goto fail1; + if (client->irq) { + ret = iio_register_interrupt_line(client->irq, + chip->indio_dev, + 0, + IRQF_TRIGGER_RISING, + client->name); + if (ret) + goto fail2; + } err = tsl2563_configure(chip); if (err) - goto fail2; + goto fail3; 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); return 0; +fail3: + if (client->irq) + iio_unregister_interrupt_line(chip->indio_dev, 0); fail2: iio_device_unregister(chip->indio_dev); fail1: @@ -701,7 +902,15 @@ fail1: static int tsl2563_remove(struct i2c_client *client) { struct tsl2563_chip *chip = i2c_get_clientdata(client); - + if (!chip->int_enabled) + cancel_delayed_work(&chip->poweroff_work); + /* Ensure that interrupts are disabled - then flush any bottom halves */ + chip->intr |= ~0x30; + tsl2563_write(chip->client, TSL2563_REG_INT, chip->intr); + flush_scheduled_work(); + tsl2563_set_power(chip, 0); + if (client->irq) + iio_unregister_interrupt_line(chip->indio_dev, 0); iio_device_unregister(chip->indio_dev); kfree(chip); diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig new file mode 100644 index 00000000000..d01445060f5 --- /dev/null +++ b/drivers/staging/iio/magnetometer/Kconfig @@ -0,0 +1,15 @@ +# +# Magnetometer sensors +# +comment "Magnetometer sensors" + +config SENSORS_HMC5843 + tristate "Honeywell HMC5843 3-Axis Magnetometer" + depends on I2C + help + Say Y here to add support for the Honeywell HMC 5843 3-Axis + Magnetometer (digital compass). + + To compile this driver as a module, choose M here: the module + will be called hmc5843 + diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile new file mode 100644 index 00000000000..f9bfb2e11d7 --- /dev/null +++ b/drivers/staging/iio/magnetometer/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for industrial I/O Magnetometer sensors +# + +obj-$(CONFIG_SENSORS_HMC5843) += hmc5843.o diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c new file mode 100644 index 00000000000..92f6c6fb90f --- /dev/null +++ b/drivers/staging/iio/magnetometer/hmc5843.c @@ -0,0 +1,624 @@ +/* Copyright (C) 2010 Texas Instruments + Author: Shubhrajyoti Datta <shubhrajyoti@ti.com> + Acknowledgement: Jonathan Cameron <jic23@cam.ac.uk> for valuable inputs. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/types.h> +#include "../iio.h" +#include "../sysfs.h" +#include "magnet.h" + +#define HMC5843_I2C_ADDRESS 0x1E + +#define HMC5843_CONFIG_REG_A 0x00 +#define HMC5843_CONFIG_REG_B 0x01 +#define HMC5843_MODE_REG 0x02 +#define HMC5843_DATA_OUT_X_MSB_REG 0x03 +#define HMC5843_DATA_OUT_X_LSB_REG 0x04 +#define HMC5843_DATA_OUT_Y_MSB_REG 0x05 +#define HMC5843_DATA_OUT_Y_LSB_REG 0x06 +#define HMC5843_DATA_OUT_Z_MSB_REG 0x07 +#define HMC5843_DATA_OUT_Z_LSB_REG 0x08 +#define HMC5843_STATUS_REG 0x09 +#define HMC5843_ID_REG_A 0x0A +#define HMC5843_ID_REG_B 0x0B +#define HMC5843_ID_REG_C 0x0C + +#define HMC5843_ID_REG_LENGTH 0x03 +#define HMC5843_ID_STRING "H43" + +/* + * Range settings in (+-)Ga + * */ +#define RANGE_GAIN_OFFSET 0x05 + +#define RANGE_0_7 0x00 +#define RANGE_1_0 0x01 /* default */ +#define RANGE_1_5 0x02 +#define RANGE_2_0 0x03 +#define RANGE_3_2 0x04 +#define RANGE_3_8 0x05 +#define RANGE_4_5 0x06 +#define RANGE_6_5 0x07 /* Not recommended */ + +/* + * Device status + */ +#define DATA_READY 0x01 +#define DATA_OUTPUT_LOCK 0x02 +#define VOLTAGE_REGULATOR_ENABLED 0x04 + +/* + * Mode register configuration + */ +#define MODE_CONVERSION_CONTINUOUS 0x00 +#define MODE_CONVERSION_SINGLE 0x01 +#define MODE_IDLE 0x02 +#define MODE_SLEEP 0x03 + +/* Minimum Data Output Rate in 1/10 Hz */ +#define RATE_OFFSET 0x02 +#define RATE_BITMASK 0x1C +#define RATE_5 0x00 +#define RATE_10 0x01 +#define RATE_20 0x02 +#define RATE_50 0x03 +#define RATE_100 0x04 +#define RATE_200 0x05 +#define RATE_500 0x06 +#define RATE_NOT_USED 0x07 + +/* + * Device Configutration + */ +#define CONF_NORMAL 0x00 +#define CONF_POSITIVE_BIAS 0x01 +#define CONF_NEGATIVE_BIAS 0x02 +#define CONF_NOT_USED 0x03 +#define MEAS_CONF_MASK 0x03 + +static const int regval_to_counts_per_mg[] = { + 1620, + 1300, + 970, + 780, + 530, + 460, + 390, + 280 +}; +static const int regval_to_input_field_mg[] = { + 700, + 1000, + 1500, + 2000, + 3200, + 3800, + 4500, + 6500 +}; +static const char *regval_to_samp_freq[] = { + "0.5", + "1", + "2", + "5", + "10", + "20", + "50", +}; + +/* Addresses to scan: 0x1E */ +static const unsigned short normal_i2c[] = { HMC5843_I2C_ADDRESS, + I2C_CLIENT_END }; + +/* Each client has this additional data */ +struct hmc5843_data { + struct iio_dev *indio_dev; + struct mutex lock; + u8 rate; + u8 meas_conf; + u8 operating_mode; + u8 range; +}; + +static void hmc5843_init_client(struct i2c_client *client); + +static s32 hmc5843_configure(struct i2c_client *client, + u8 operating_mode) +{ + /* The lower two bits contain the current conversion mode */ + return i2c_smbus_write_byte_data(client, + HMC5843_MODE_REG, + (operating_mode & 0x03)); +} + +/* Return the measurement value from the specified channel */ +static ssize_t hmc5843_read_measurement(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); + s16 coordinate_val; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct hmc5843_data *data = indio_dev->dev_data; + s32 result; + + mutex_lock(&data->lock); + + result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG); + while (!(result & DATA_READY)) + result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG); + + result = i2c_smbus_read_word_data(client, this_attr->address); + mutex_unlock(&data->lock); + if (result < 0) + return -EINVAL; + + coordinate_val = (s16)swab16((u16)result); + return sprintf(buf, "%d\n", coordinate_val); +} +static IIO_DEV_ATTR_MAGN_X(hmc5843_read_measurement, + HMC5843_DATA_OUT_X_MSB_REG); +static IIO_DEV_ATTR_MAGN_Y(hmc5843_read_measurement, + HMC5843_DATA_OUT_Y_MSB_REG); +static IIO_DEV_ATTR_MAGN_Z(hmc5843_read_measurement, + HMC5843_DATA_OUT_Z_MSB_REG); + +/* + * From the datasheet + * 0 - Continuous-Conversion Mode: In continuous-conversion mode, the + * device continuously performs conversions an places the result in the + * data register. + * + * 1 - Single-Conversion Mode : device performs a single measurement, + * sets RDY high and returned to sleep mode + * + * 2 - Idle Mode : Device is placed in idle mode. + * + * 3 - Sleep Mode. Device is placed in sleep mode. + * + */ +static ssize_t hmc5843_show_operating_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct hmc5843_data *data = indio_dev->dev_data; + return sprintf(buf, "%d\n", data->operating_mode); +} + +static ssize_t hmc5843_set_operating_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); + struct hmc5843_data *data = indio_dev->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + unsigned long operating_mode = 0; + s32 status; + int error; + mutex_lock(&data->lock); + error = strict_strtoul(buf, 10, &operating_mode); + if (error) + return error; + dev_dbg(dev, "set Conversion mode to %lu\n", operating_mode); + if (operating_mode > MODE_SLEEP) + return -EINVAL; + + status = i2c_smbus_write_byte_data(client, this_attr->address, + operating_mode); + if (status) { + count = -EINVAL; + goto exit; + } + data->operating_mode = operating_mode; + +exit: + mutex_unlock(&data->lock); + return count; +} +static IIO_DEVICE_ATTR(operating_mode, + S_IWUSR | S_IRUGO, + hmc5843_show_operating_mode, + hmc5843_set_operating_mode, + HMC5843_MODE_REG); + +/* + * API for setting the measurement configuration to + * Normal, Positive bias and Negative bias + * From the datasheet + * + * Normal measurement configuration (default): In normal measurement + * configuration the device follows normal measurement flow. Pins BP and BN + * are left floating and high impedance. + * + * Positive bias configuration: In positive bias configuration, a positive + * current is forced across the resistive load on pins BP and BN. + * + * Negative bias configuration. In negative bias configuration, a negative + * current is forced across the resistive load on pins BP and BN. + * + */ +static s32 hmc5843_set_meas_conf(struct i2c_client *client, + u8 meas_conf) +{ + struct hmc5843_data *data = i2c_get_clientdata(client); + u8 reg_val; + reg_val = (meas_conf & MEAS_CONF_MASK) | (data->rate << RATE_OFFSET); + return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val); +} + +static ssize_t hmc5843_show_measurement_configuration(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct hmc5843_data *data = indio_dev->dev_data; + return sprintf(buf, "%d\n", data->meas_conf); +} + +static ssize_t hmc5843_set_measurement_configuration(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); + struct hmc5843_data *data = i2c_get_clientdata(client); + unsigned long meas_conf = 0; + int error = strict_strtoul(buf, 10, &meas_conf); + if (error) + return error; + mutex_lock(&data->lock); + + dev_dbg(dev, "set mode to %lu\n", meas_conf); + if (hmc5843_set_meas_conf(client, meas_conf)) { + count = -EINVAL; + goto exit; + } + data->meas_conf = meas_conf; + +exit: + mutex_unlock(&data->lock); + return count; +} +static IIO_DEVICE_ATTR(meas_conf, + S_IWUSR | S_IRUGO, + hmc5843_show_measurement_configuration, + hmc5843_set_measurement_configuration, + 0); + +/* + * From Datasheet + * The table shows the minimum data output + * Value | Minimum data output rate(Hz) + * 0 | 0.5 + * 1 | 1 + * 2 | 2 + * 3 | 5 + * 4 | 10 (default) + * 5 | 20 + * 6 | 50 + * 7 | Not used + */ +static IIO_CONST_ATTR_AVAIL_SAMP_FREQ("0.5 1 2 5 10 20 50"); + +static s32 hmc5843_set_rate(struct i2c_client *client, + u8 rate) +{ + struct hmc5843_data *data = i2c_get_clientdata(client); + u8 reg_val; + + reg_val = (data->meas_conf) | (rate << RATE_OFFSET); + if (rate >= RATE_NOT_USED) { + dev_err(&client->dev, + "This data output rate is not supported \n"); + return -EINVAL; + } + return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val); +} + +static ssize_t set_sampling_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); + struct hmc5843_data *data = indio_dev->dev_data; + unsigned long rate = 0; + + if (strncmp(buf, "0.5" , 3) == 0) + rate = RATE_5; + else if (strncmp(buf, "1" , 1) == 0) + rate = RATE_10; + else if (strncmp(buf, "2", 1) == 0) + rate = RATE_20; + else if (strncmp(buf, "5", 1) == 0) + rate = RATE_50; + else if (strncmp(buf, "10", 2) == 0) + rate = RATE_100; + else if (strncmp(buf, "20" , 2) == 0) + rate = RATE_200; + else if (strncmp(buf, "50" , 2) == 0) + rate = RATE_500; + else + return -EINVAL; + + mutex_lock(&data->lock); + dev_dbg(dev, "set rate to %lu\n", rate); + if (hmc5843_set_rate(client, rate)) { + count = -EINVAL; + goto exit; + } + data->rate = rate; + +exit: + mutex_unlock(&data->lock); + return count; +} + +static ssize_t show_sampling_frequency(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + u32 rate; + + rate = i2c_smbus_read_byte_data(client, this_attr->address); + if (rate < 0) + return -EINVAL; + rate = (rate & RATE_BITMASK) >> RATE_OFFSET; + return sprintf(buf, "%s\n", regval_to_samp_freq[rate]); +} +static IIO_DEVICE_ATTR(sampling_frequency, + S_IWUSR | S_IRUGO, + show_sampling_frequency, + set_sampling_frequency, + HMC5843_CONFIG_REG_A); + +/* + * From Datasheet + * Nominal gain settings + * Value | Sensor Input Field Range(Ga) | Gain(counts/ milli-gauss) + *0 |(+-)0.7 |1620 + *1 |(+-)1.0 |1300 + *2 |(+-)1.5 |970 + *3 |(+-)2.0 |780 + *4 |(+-)3.2 |530 + *5 |(+-)3.8 |460 + *6 |(+-)4.5 |390 + *7 |(+-)6.5 |280 + */ +static ssize_t show_range(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u8 range; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct hmc5843_data *data = indio_dev->dev_data; + + range = data->range; + return sprintf(buf, "%d\n", regval_to_input_field_mg[range]); +} + +static ssize_t set_range(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct hmc5843_data *data = indio_dev->dev_data; + unsigned long range = 0; + int error; + mutex_lock(&data->lock); + error = strict_strtoul(buf, 10, &range); + if (error) + return error; + dev_dbg(dev, "set range to %lu\n", range); + + if (range > RANGE_6_5) + return -EINVAL; + + data->range = range; + range = range << RANGE_GAIN_OFFSET; + if (i2c_smbus_write_byte_data(client, this_attr->address, range)) + count = -EINVAL; + + mutex_unlock(&data->lock); + return count; + +} +static IIO_DEVICE_ATTR(magn_range, + S_IWUSR | S_IRUGO, + show_range, + set_range, + HMC5843_CONFIG_REG_B); + +static ssize_t show_gain(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct hmc5843_data *data = indio_dev->dev_data; + return sprintf(buf, "%d\n", regval_to_counts_per_mg[data->range]); +} +static IIO_DEVICE_ATTR(magn_gain, + S_IRUGO, + show_gain, + NULL , 0); + +static struct attribute *hmc5843_attributes[] = { + &iio_dev_attr_meas_conf.dev_attr.attr, + &iio_dev_attr_operating_mode.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_dev_attr_magn_range.dev_attr.attr, + &iio_dev_attr_magn_gain.dev_attr.attr, + &iio_dev_attr_magn_x_raw.dev_attr.attr, + &iio_dev_attr_magn_y_raw.dev_attr.attr, + &iio_dev_attr_magn_z_raw.dev_attr.attr, + &iio_const_attr_available_sampling_frequency.dev_attr.attr, + NULL +}; + +static const struct attribute_group hmc5843_group = { + .attrs = hmc5843_attributes, +}; + +static int hmc5843_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + unsigned char id_str[HMC5843_ID_REG_LENGTH]; + + if (client->addr != HMC5843_I2C_ADDRESS) + return -ENODEV; + + if (i2c_smbus_read_i2c_block_data(client, HMC5843_ID_REG_A, + HMC5843_ID_REG_LENGTH, id_str) + != HMC5843_ID_REG_LENGTH) + return -ENODEV; + + if (0 != strncmp(id_str, HMC5843_ID_STRING, HMC5843_ID_REG_LENGTH)) + return -ENODEV; + + return 0; +} + +/* Called when we have found a new HMC5843. */ +static void hmc5843_init_client(struct i2c_client *client) +{ + struct hmc5843_data *data = i2c_get_clientdata(client); + hmc5843_set_meas_conf(client, data->meas_conf); + hmc5843_set_rate(client, data->rate); + hmc5843_configure(client, data->operating_mode); + i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_B, data->range); + mutex_init(&data->lock); + pr_info("HMC5843 initialized\n"); +} + +static int hmc5843_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct hmc5843_data *data; + int err = 0; + + data = kzalloc(sizeof(struct hmc5843_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + /* default settings at probe */ + + data->meas_conf = CONF_NORMAL; + data->range = RANGE_1_0; + data->operating_mode = MODE_CONVERSION_CONTINUOUS; + + i2c_set_clientdata(client, data); + + /* Initialize the HMC5843 chip */ + hmc5843_init_client(client); + + data->indio_dev = iio_allocate_device(); + if (!data->indio_dev) { + err = -ENOMEM; + goto exit_free1; + } + data->indio_dev->attrs = &hmc5843_group; + data->indio_dev->dev.parent = &client->dev; + data->indio_dev->dev_data = (void *)(data); + data->indio_dev->driver_module = THIS_MODULE; + data->indio_dev->modes = INDIO_DIRECT_MODE; + err = iio_device_register(data->indio_dev); + if (err) + goto exit_free2; + return 0; +exit_free2: + iio_free_device(data->indio_dev); +exit_free1: + kfree(data); +exit: + return err; +} + +static int hmc5843_remove(struct i2c_client *client) +{ + struct hmc5843_data *data = i2c_get_clientdata(client); + /* sleep mode to save power */ + hmc5843_configure(client, MODE_SLEEP); + iio_device_unregister(data->indio_dev); + kfree(i2c_get_clientdata(client)); + return 0; +} + +static int hmc5843_suspend(struct i2c_client *client, pm_message_t mesg) +{ + hmc5843_configure(client, MODE_SLEEP); + return 0; +} + +static int hmc5843_resume(struct i2c_client *client) +{ + struct hmc5843_data *data = i2c_get_clientdata(client); + hmc5843_configure(client, data->operating_mode); + return 0; +} + +static const struct i2c_device_id hmc5843_id[] = { + { "hmc5843", 0 }, + { } +}; + +static struct i2c_driver hmc5843_driver = { + .driver = { + .name = "hmc5843", + }, + .id_table = hmc5843_id, + .probe = hmc5843_probe, + .remove = hmc5843_remove, + .detect = hmc5843_detect, + .address_list = normal_i2c, + .suspend = hmc5843_suspend, + .resume = hmc5843_resume, +}; + +static int __init hmc5843_init(void) +{ + return i2c_add_driver(&hmc5843_driver); +} + +static void __exit hmc5843_exit(void) +{ + i2c_del_driver(&hmc5843_driver); +} + +MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com"); +MODULE_DESCRIPTION("HMC5843 driver"); +MODULE_LICENSE("GPL"); + +module_init(hmc5843_init); +module_exit(hmc5843_exit); diff --git a/drivers/staging/iio/ring_generic.h b/drivers/staging/iio/ring_generic.h index 0e443757b02..a872d3904a3 100644 --- a/drivers/staging/iio/ring_generic.h +++ b/drivers/staging/iio/ring_generic.h @@ -11,6 +11,8 @@ #define _IIO_RING_GENERIC_H_ #include "iio.h" +#ifdef CONFIG_IIO_RING_BUFFER + struct iio_handler; struct iio_ring_buffer; struct iio_dev; @@ -98,6 +100,7 @@ struct iio_ring_access_funcs { * @access_id: device id number * @length: [DEVICE] number of datums in ring * @bpd: [DEVICE] size of individual datum including timestamp + * @bpe: [DEVICE] size of individual channel value * @loopcount: [INTERN] number of times the ring has looped * @access_handler: [INTERN] chrdev access handling * @ev_int: [INTERN] chrdev interface for the event chrdev @@ -119,6 +122,7 @@ struct iio_ring_buffer { int access_id; int length; int bpd; + int bpe; int loopcount; struct iio_handler access_handler; struct iio_event_interface ev_int; @@ -213,7 +217,7 @@ ssize_t iio_scan_el_ts_show(struct device *dev, struct device_attribute *attr, * @_label: indentification variable used by drivers. Often a reg address. * @_controlfunc: function used to notify hardware of whether state changes **/ -#define IIO_SCAN_EL_C(_name, _number, _bits, _label, _controlfunc) \ +#define __IIO_SCAN_EL_C(_name, _number, _bits, _label, _controlfunc) \ struct iio_scan_el iio_scan_el_##_name = { \ .dev_attr = __ATTR(_number##_##_name##_en, \ S_IRUGO | S_IWUSR, \ @@ -225,7 +229,10 @@ ssize_t iio_scan_el_ts_show(struct device *dev, struct device_attribute *attr, .set_state = _controlfunc, \ } -#define IIO_SCAN_NAMED_EL_C(_name, _string, _number, _bits, _label, _cf) \ +#define IIO_SCAN_EL_C(_name, _number, _bits, _label, _controlfunc) \ + __IIO_SCAN_EL_C(_name, _number, _bits, _label, _controlfunc) + +#define __IIO_SCAN_NAMED_EL_C(_name, _string, _number, _bits, _label, _cf) \ struct iio_scan_el iio_scan_el_##_name = { \ .dev_attr = __ATTR(_number##_##_string##_en, \ S_IRUGO | S_IWUSR, \ @@ -236,7 +243,8 @@ ssize_t iio_scan_el_ts_show(struct device *dev, struct device_attribute *attr, .label = _label, \ .set_state = _cf, \ } - +#define IIO_SCAN_NAMED_EL_C(_name, _string, _number, _bits, _label, _cf) \ + __IIO_SCAN_NAMED_EL_C(_name, _string, _number, _bits, _label, _cf) /** * IIO_SCAN_EL_TIMESTAMP - declare a special scan element for timestamps * @@ -287,5 +295,14 @@ ssize_t iio_show_ring_enable(struct device *dev, #define IIO_RING_ENABLE_ATTR DEVICE_ATTR(ring_enable, S_IRUGO | S_IWUSR, \ iio_show_ring_enable, \ iio_store_ring_enable) +#else /* CONFIG_IIO_RING_BUFFER */ +static inline int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id) +{ + return 0; +}; +static inline void iio_ring_buffer_unregister(struct iio_ring_buffer *ring) +{}; + +#endif /* CONFIG_IIO_RING_BUFFER */ #endif /* _IIO_RING_GENERIC_H_ */ diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c index 294272d0619..e2f01c640ba 100644 --- a/drivers/staging/iio/ring_sw.c +++ b/drivers/staging/iio/ring_sw.c @@ -13,6 +13,7 @@ #include <linux/device.h> #include <linux/workqueue.h> #include "ring_sw.h" +#include "trigger.h" static inline int __iio_allocate_sw_ring_buffer(struct iio_sw_ring_buffer *ring, int bytes_per_datum, int length) @@ -431,5 +432,73 @@ void iio_sw_rb_free(struct iio_ring_buffer *r) iio_put_ring_buffer(r); } EXPORT_SYMBOL(iio_sw_rb_free); + +int iio_sw_ring_preenable(struct iio_dev *indio_dev) +{ + size_t size; + dev_dbg(&indio_dev->dev, "%s\n", __func__); + /* Check if there are any scan elements enabled, if not fail*/ + if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) + return -EINVAL; + if (indio_dev->scan_timestamp) + if (indio_dev->scan_count) + /* Timestamp (aligned to s64) and data */ + size = (((indio_dev->scan_count * indio_dev->ring->bpe) + + sizeof(s64) - 1) + & ~(sizeof(s64) - 1)) + + sizeof(s64); + else /* Timestamp only */ + size = sizeof(s64); + else /* Data only */ + size = indio_dev->scan_count * indio_dev->ring->bpe; + indio_dev->ring->access.set_bpd(indio_dev->ring, size); + + return 0; +} +EXPORT_SYMBOL(iio_sw_ring_preenable); + +void iio_sw_trigger_bh_to_ring(struct work_struct *work_s) +{ + struct iio_sw_ring_helper_state *st + = container_of(work_s, struct iio_sw_ring_helper_state, + work_trigger_to_ring); + int len = 0; + size_t datasize = st->indio_dev + ->ring->access.get_bpd(st->indio_dev->ring); + char *data = kmalloc(datasize, GFP_KERNEL); + + if (data == NULL) { + dev_err(st->indio_dev->dev.parent, + "memory alloc failed in ring bh"); + return; + } + + if (st->indio_dev->scan_count) + len = st->get_ring_element(st, data); + + /* Guaranteed to be aligned with 8 byte boundary */ + if (st->indio_dev->scan_timestamp) + *(s64 *)(((phys_addr_t)data + len + + sizeof(s64) - 1) & ~(sizeof(s64) - 1)) + = st->last_timestamp; + st->indio_dev->ring->access.store_to(st->indio_dev->ring, + (u8 *)data, + st->last_timestamp); + + iio_trigger_notify_done(st->indio_dev->trig); + kfree(data); + + return; +} +EXPORT_SYMBOL(iio_sw_trigger_bh_to_ring); + +void iio_sw_poll_func_th(struct iio_dev *indio_dev, s64 time) +{ struct iio_sw_ring_helper_state *h + = iio_dev_get_devdata(indio_dev); + h->last_timestamp = time; + schedule_work(&h->work_trigger_to_ring); +} +EXPORT_SYMBOL(iio_sw_poll_func_th); + MODULE_DESCRIPTION("Industrialio I/O software ring buffer"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h index fd677f00836..61f1ed65039 100644 --- a/drivers/staging/iio/ring_sw.h +++ b/drivers/staging/iio/ring_sw.h @@ -207,10 +207,21 @@ struct iio_sw_ring_buffer { struct iio_ring_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev); void iio_sw_rb_free(struct iio_ring_buffer *ring); +int iio_sw_ring_preenable(struct iio_dev *indio_dev); +struct iio_sw_ring_helper_state { + struct work_struct work_trigger_to_ring; + struct iio_dev *indio_dev; + int (*get_ring_element)(struct iio_sw_ring_helper_state *st, u8 *buf); + s64 last_timestamp; +}; + +void iio_sw_poll_func_th(struct iio_dev *indio_dev, s64 time); +void iio_sw_trigger_bh_to_ring(struct work_struct *work_s); #else /* CONFIG_IIO_RING_BUFFER*/ -static inline void iio_ring_sw_register_funcs(struct iio_ring_access_funcs *ra) -{}; +struct iio_sw_ring_helper_state { + struct iio_dev *indio_dev; +}; #endif /* !CONFIG_IIO_RING_BUFFER */ #endif /* _IIO_RING_SW_H_ */ diff --git a/drivers/staging/iio/sysfs.h b/drivers/staging/iio/sysfs.h index afcf5ab85f4..60834162eb3 100644 --- a/drivers/staging/iio/sysfs.h +++ b/drivers/staging/iio/sysfs.h @@ -284,6 +284,14 @@ struct iio_const_attr { .mask = _mask, \ .listel = &_ev_list }; +#define IIO_EVENT_ATTR_NAMED_SH(_vname, _name, _ev_list, _show, _store, _mask) \ + static struct iio_event_attr \ + iio_event_attr_##_vname \ + = { .dev_attr = __ATTR(_name, S_IRUGO | S_IWUSR, \ + _show, _store), \ + .mask = _mask, \ + .listel = &_ev_list }; + /** * IIO_EVENT_ATTR - non-shared event attribute * @_name: event name @@ -293,10 +301,7 @@ struct iio_const_attr { * @_handler: handler function to be called **/ #define IIO_EVENT_ATTR(_name, _show, _store, _mask, _handler) \ - static struct iio_event_handler_list \ - iio_event_##_name = { \ - .handler = _handler, \ - }; \ + IIO_EVENT_SH(_name, _handler); \ static struct \ iio_event_attr \ iio_event_attr_##_name \ @@ -324,6 +329,7 @@ struct iio_const_attr { #define IIO_EVENT_CODE_GYRO_BASE 400 #define IIO_EVENT_CODE_ADC_BASE 500 #define IIO_EVENT_CODE_MISC_BASE 600 +#define IIO_EVENT_CODE_LIGHT_BASE 700 #define IIO_EVENT_CODE_DEVICE_SPECIFIC 1000 diff --git a/drivers/staging/iio/trigger.h b/drivers/staging/iio/trigger.h index 784e7b6fac1..4699586a593 100644 --- a/drivers/staging/iio/trigger.h +++ b/drivers/staging/iio/trigger.h @@ -8,10 +8,6 @@ */ #ifndef _IIO_TRIGGER_H_ #define _IIO_TRIGGER_H_ -#define IIO_TRIGGER_NAME_LENGTH 20 -#define IIO_TRIGGER_ID_PREFIX "iio:trigger" -#define IIO_TRIGGER_ID_FORMAT IIO_TRIGGER_ID_PREFIX "%d" - /** * struct iio_trigger - industrial I/O trigger device @@ -25,7 +21,6 @@ * @pollfunc_list_lock: [INTERN] protection of the polling function list * @pollfunc_list: [INTERN] list of functions to run on trigger. * @control_attrs: [DRIVER] sysfs attributes relevant to trigger type - * @timestamp: [INTERN] timestamp usesd by some trigs (e.g. datardy) * @owner: [DRIVER] used to monitor usage count of the trigger. * @use_count: use count for the trigger * @set_trigger_state: [DRIVER] switch on/off the trigger on demand @@ -43,7 +38,6 @@ struct iio_trigger { spinlock_t pollfunc_list_lock; struct list_head pollfunc_list; const struct attribute_group *control_attrs; - s64 timestamp; struct module *owner; int use_count; @@ -124,7 +118,7 @@ int iio_trigger_dettach_poll_func(struct iio_trigger *trig, * * Typically called in relevant hardware interrupt handler. **/ -void iio_trigger_poll(struct iio_trigger *trig); +void iio_trigger_poll(struct iio_trigger *trig, s64 time); void iio_trigger_notify_done(struct iio_trigger *trig); /** @@ -148,13 +142,27 @@ struct iio_poll_func { struct list_head list; void *private_data; void (*poll_func_immediate)(struct iio_dev *indio_dev); - void (*poll_func_main)(struct iio_dev *private_data); + void (*poll_func_main)(struct iio_dev *private_data, s64 time); }; +int iio_alloc_pollfunc(struct iio_dev *indio_dev, + void (*immediate)(struct iio_dev *indio_dev), + void (*main)(struct iio_dev *private_data, s64 time)); + +/* + * Two functions for common case where all that happens is a pollfunc + * is attached and detached form a trigger + */ +int iio_triggered_ring_postenable(struct iio_dev *indio_dev); +int iio_triggered_ring_predisable(struct iio_dev *indio_dev); + struct iio_trigger *iio_allocate_trigger(void); void iio_free_trigger(struct iio_trigger *trig); +struct iio_simple_trigger { + struct iio_trigger trig; +}; #endif /* _IIO_TRIGGER_H_ */ diff --git a/drivers/staging/iio/trigger/Makefile b/drivers/staging/iio/trigger/Makefile index e5f96d2fe64..10aeca5e347 100644 --- a/drivers/staging/iio/trigger/Makefile +++ b/drivers/staging/iio/trigger/Makefile @@ -1,5 +1,6 @@ # # Makefile for triggers not associated with iio-devices # + obj-$(CONFIG_IIO_PERIODIC_RTC_TRIGGER) += iio-trig-periodic-rtc.o -obj-$(CONFIG_IIO_GPIO_TRIGGER) += iio-trig-gpio.o
\ No newline at end of file +obj-$(CONFIG_IIO_GPIO_TRIGGER) += iio-trig-gpio.o diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c index 1da285d2863..f93cc916983 100644 --- a/drivers/staging/iio/trigger/iio-trig-gpio.c +++ b/drivers/staging/iio/trigger/iio-trig-gpio.c @@ -42,7 +42,8 @@ struct iio_gpio_trigger_info { static irqreturn_t iio_gpio_trigger_poll(int irq, void *private) { - iio_trigger_poll(private); + /* Timestamp not currently provided */ + iio_trigger_poll(private, 0); return IRQ_HANDLED; } @@ -93,16 +94,11 @@ static int iio_gpio_trigger_probe(struct platform_device *pdev) trig->private_data = trig_info; trig_info->irq = irq; trig->owner = THIS_MODULE; - trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, - GFP_KERNEL); - if (!trig->name) { + trig->name = kasprintf(GFP_KERNEL, "irqtrig%d", irq); + if (trig->name == NULL) { ret = -ENOMEM; goto error_free_trig_info; } - snprintf((char *)trig->name, - IIO_TRIGGER_NAME_LENGTH, - "irqtrig%d", irq); - ret = request_irq(irq, iio_gpio_trigger_poll, irqflags, trig->name, trig); if (ret) { diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index 4ee3ae1ef89..b0b52f84edf 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -25,7 +25,6 @@ static DEFINE_MUTEX(iio_prtc_trigger_list_lock); struct iio_prtc_trigger_info { struct rtc_device *rtc; int frequency; - char *name; struct rtc_task task; }; @@ -78,8 +77,7 @@ static ssize_t iio_trig_periodic_read_name(struct device *dev, char *buf) { struct iio_trigger *trig = dev_get_drvdata(dev); - struct iio_prtc_trigger_info *trig_info = trig->private_data; - return sprintf(buf, "%s\n", trig_info->name); + return sprintf(buf, "%s\n", trig->name); } static DEVICE_ATTR(name, S_IRUGO, @@ -100,7 +98,8 @@ static const struct attribute_group iio_trig_prtc_attr_group = { static void iio_prtc_trigger_poll(void *private_data) { - iio_trigger_poll(private_data); + /* Timestamp is not provided currently */ + iio_trigger_poll(private_data, 0); } static int iio_trig_periodic_rtc_probe(struct platform_device *dev) @@ -129,16 +128,12 @@ static int iio_trig_periodic_rtc_probe(struct platform_device *dev) trig->private_data = trig_info; trig->owner = THIS_MODULE; trig->set_trigger_state = &iio_trig_periodic_rtc_set_state; - trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); + trig->name = kasprintf(GFP_KERNEL, "periodic%s", pdata[i]); if (trig->name == NULL) { ret = -ENOMEM; goto error_free_trig_info; } - snprintf((char *)trig->name, - IIO_TRIGGER_NAME_LENGTH, - "periodic%s", - pdata[i]); - trig_info->name = (char *)trig->name; + /* RTC access */ trig_info->rtc = rtc_class_open(pdata[i]); |