From a1427af59977894d20b1b5ea61f4b2856c7d1833 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Sep 2016 11:43:42 +0200 Subject: iio: accel: sca3000_core: avoid potentially uninitialized variable The newly added __sca3000_get_base_freq function handles all valid modes of the SCA3000_REG_ADDR_MODE register, but gcc notices that any other value (i.e. 0x00) causes the base_freq variable to not get initialized: drivers/staging/iio/accel/sca3000_core.c: In function 'sca3000_write_raw': drivers/staging/iio/accel/sca3000_core.c:527:23: error: 'base_freq' may be used uninitialized in this function [-Werror=maybe-uninitialized] This adds explicit error handling for unexpected register values, to ensure this cannot happen. Fixes: e0f3fc9b47e6 ("iio: accel: sca3000_core: implemented IIO_CHAN_INFO_SAMP_FREQ") Signed-off-by: Arnd Bergmann Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/sca3000_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index d626125d7af9..564b36d4f648 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -468,6 +468,8 @@ 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; + default: + ret = -EINVAL; } error_ret: return ret; -- cgit v1.2.3 From 59dc1c8619e9f89987f36f03c5047fc2af642215 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Sep 2016 11:42:30 +0200 Subject: iio:pressure: zpa2326: remove redundant "DEBUG" ifdef The -Wempty-body gcc warning triggers in the newly added zpa2326 driver: drivers/iio/pressure/zpa2326.c: In function 'zpa2326_dequeue_pressure': drivers/iio/pressure/zpa2326.c:578:3: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body] The use of an empty statement behind 'if (...)' is harmless here, but it shows that the dev_dbg() macro is not used correctly: when the "DEBUG" macro is not set, dev_dbg() already defaults to a no-operation, though one that lets the compiler know that the arguments are used, and lets it check the format string. Fixing this also simplifies the driver. Fixes: 03b262f2bbf4 ("iio:pressure: initial zpa2326 barometer support") Signed-off-by: Arnd Bergmann Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/zpa2326.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 19d2eb46fda6..c720c3ac0b9b 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -147,12 +147,8 @@ struct zpa2326_private { #define zpa2326_warn(_idev, _format, _arg...) \ dev_warn(_idev->dev.parent, _format, ##_arg) -#ifdef DEBUG #define zpa2326_dbg(_idev, _format, _arg...) \ dev_dbg(_idev->dev.parent, _format, ##_arg) -#else -#define zpa2326_dbg(_idev, _format, _arg...) -#endif bool zpa2326_isreg_writeable(struct device *dev, unsigned int reg) { -- cgit v1.2.3 From 1b14adcaf659d988adccda778f286d2be628a1e6 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 24 Sep 2016 12:01:54 +0000 Subject: iio: accel: mma7660: fix non static symbol warning Fixes the following sparse warning: drivers/iio/accel/mma7660.c:42:11: warning: symbol 'mma7660_nscale' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma7660.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index 03beadf14ad3..3a40774cca74 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -39,7 +39,7 @@ #define MMA7660_SCALE_AVAIL "0.467142857" -const int mma7660_nscale = 467142857; +static const int mma7660_nscale = 467142857; #define MMA7660_CHANNEL(reg, axis) { \ .type = IIO_ACCEL, \ -- cgit v1.2.3 From 057ac1acdfc4743f066fcefe359385cad00549eb Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 23 Sep 2016 22:30:32 +0200 Subject: iio: Use kmalloc_array() in iio_scan_mask_set() A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 158aaf44dd95..b12830b09c7d 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -307,10 +307,9 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev, const unsigned long *mask; unsigned long *trialmask; - trialmask = kmalloc(sizeof(*trialmask)* - BITS_TO_LONGS(indio_dev->masklength), - GFP_KERNEL); - + trialmask = kmalloc_array(BITS_TO_LONGS(indio_dev->masklength), + sizeof(*trialmask), + GFP_KERNEL); if (trialmask == NULL) return -ENOMEM; if (!indio_dev->masklength) { -- cgit v1.2.3 From 58b90a8d2c397ab8498d1b2a610e6ae40b6ad0f6 Mon Sep 17 00:00:00 2001 From: Sandhya Bankar Date: Sat, 24 Sep 2016 01:34:48 +0530 Subject: drivers: iio: max1027: Fix sparse warning: "dubious: x | !y" Fixing below warning: drivers/iio/adc/max1027.c:241:34: warning: dubious: x | !y . Signed-off-by: Sandhya Bankar Signed-off-by: Jonathan Cameron --- drivers/iio/adc/max1027.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index 712fbd2b1f16..d60181822833 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -238,7 +238,9 @@ static int max1027_read_single_value(struct iio_dev *indio_dev, /* Configure conversion register with the requested chan */ st->reg = MAX1027_CONV_REG | MAX1027_CHAN(chan->channel) | - MAX1027_NOSCAN | !!(chan->type == IIO_TEMP); + MAX1027_NOSCAN; + if (chan->type == IIO_TEMP) + st->reg |= MAX1027_TEMP; ret = spi_write(st->spi, &st->reg, 1); if (ret < 0) { dev_err(&indio_dev->dev, -- cgit v1.2.3 From 38e442fc8ba11b32e57f4837e1aa695f3751b99c Mon Sep 17 00:00:00 2001 From: Sandhya Bankar Date: Sat, 24 Sep 2016 00:50:22 +0530 Subject: drivers: iio: dac: Fix sparse warning Fixing below warnings: drivers/iio/dac/ad5592r.c:58:41: warning: incorrect type in argument 2 (different base types) drivers/iio/dac/ad5592r.c:58:41: expected unsigned short [usertype] *buf drivers/iio/dac/ad5592r.c:58:41: got restricted __be16 * drivers/iio/dac/ad5592r.c:62:41: warning: incorrect type in argument 2 (different base types) drivers/iio/dac/ad5592r.c:62:41: expected unsigned short [usertype] *buf drivers/iio/dac/ad5592r.c:62:41: got restricted __be16 * drivers/iio/dac/ad5592r.c:92:41: warning: incorrect type in argument 2 (different base types) drivers/iio/dac/ad5592r.c:92:41: expected unsigned short [usertype] *buf drivers/iio/dac/ad5592r.c:92:41: got restricted __be16 * drivers/iio/dac/ad5592r.c:110:41: warning: incorrect type in argument 2 (different base types) drivers/iio/dac/ad5592r.c:110:41: expected unsigned short [usertype] *buf drivers/iio/dac/ad5592r.c:110:41: got restricted __be16 * Signed-off-by: Sandhya Bankar Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5592r.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c index 0b235a2c7359..6eed5b7729be 100644 --- a/drivers/iio/dac/ad5592r.c +++ b/drivers/iio/dac/ad5592r.c @@ -17,7 +17,7 @@ #define AD5592R_GPIO_READBACK_EN BIT(10) #define AD5592R_LDAC_READBACK_EN BIT(6) -static int ad5592r_spi_wnop_r16(struct ad5592r_state *st, u16 *buf) +static int ad5592r_spi_wnop_r16(struct ad5592r_state *st, __be16 *buf) { struct spi_device *spi = container_of(st->dev, struct spi_device, dev); struct spi_transfer t = { -- cgit v1.2.3 From 43ece27e70b2c756e45306791955507f0533e248 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 23 Sep 2016 17:19:41 +0200 Subject: iio:trigger: Add helper function to verify that a trigger belongs to the same device Some triggers can only be attached to the IIO device that corresponds to the same physical device. Currently each driver that requires this implements its own trigger validation function. Introduce a new helper function called iio_trigger_validate_own_device() that can be used to do this check. Having a common implementation avoids code duplication and unnecessary boiler-plate code. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-trigger.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index e1e104845e38..978729f6d7c4 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -717,6 +717,27 @@ bool iio_trigger_using_own(struct iio_dev *indio_dev) } EXPORT_SYMBOL(iio_trigger_using_own); +/** + * iio_trigger_validate_own_device - Check if a trigger and IIO device belong to + * the same device + * @trig: The IIO trigger to check + * @indio_dev: the IIO device to check + * + * This function can be used as the validate_device callback for triggers that + * can only be attached to their own device. + * + * Return: 0 if both the trigger and the IIO device belong to the same + * device, -EINVAL otherwise. + */ +int iio_trigger_validate_own_device(struct iio_trigger *trig, + struct iio_dev *indio_dev) +{ + if (indio_dev->dev.parent != trig->dev.parent) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(iio_trigger_validate_own_device); + void iio_device_register_trigger_consumer(struct iio_dev *indio_dev) { indio_dev->groups[indio_dev->groupcounter++] = -- cgit v1.2.3 From 19808e0467a05ee4a3008f9d586ce32d5b34aba8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 23 Sep 2016 17:19:42 +0200 Subject: iio:mma8452: Use new iio_trigger_validate_own_device() helper Use the new iio_trigger_validate_own_device() to verify that the trigger can only be attached to the matching IIO device rather than using a custom variant. While the implementation of iio_trigger_validate_own_device() and the custom variant and are not identical their behaviour is. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index d41e1b588e68..1c7051581513 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1347,20 +1347,9 @@ static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig, return mma8452_change_config(data, MMA8452_CTRL_REG4, reg); } -static int mma8452_validate_device(struct iio_trigger *trig, - struct iio_dev *indio_dev) -{ - struct iio_dev *indio = iio_trigger_get_drvdata(trig); - - if (indio != indio_dev) - return -EINVAL; - - return 0; -} - static const struct iio_trigger_ops mma8452_trigger_ops = { .set_trigger_state = mma8452_data_rdy_trigger_set_state, - .validate_device = mma8452_validate_device, + .validate_device = iio_trigger_validate_own_device, .owner = THIS_MODULE, }; -- cgit v1.2.3 From bea15d5139b9eef3ca368b95c4dbd6621bff9a5c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 23 Sep 2016 17:19:43 +0200 Subject: iio:max1027: Use iio_trigger_validate_own_device() helper Use the new iio_trigger_validate_own_device() to verify that the trigger can only be attached to the matching IIO device rather than using a custom variant. While the implementation of iio_trigger_validate_own_device() and the custom variant and are not identical their behaviour is. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/max1027.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index d60181822833..3b7c4f78f37a 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -362,17 +362,6 @@ static int max1027_set_trigger_state(struct iio_trigger *trig, bool state) return 0; } -static int max1027_validate_device(struct iio_trigger *trig, - struct iio_dev *indio_dev) -{ - struct iio_dev *indio = iio_trigger_get_drvdata(trig); - - if (indio != indio_dev) - return -EINVAL; - - return 0; -} - static irqreturn_t max1027_trigger_handler(int irq, void *private) { struct iio_poll_func *pf = (struct iio_poll_func *)private; @@ -393,7 +382,7 @@ static irqreturn_t max1027_trigger_handler(int irq, void *private) static const struct iio_trigger_ops max1027_trigger_ops = { .owner = THIS_MODULE, - .validate_device = &max1027_validate_device, + .validate_device = &iio_trigger_validate_own_device, .set_trigger_state = &max1027_set_trigger_state, }; -- cgit v1.2.3 From aa16c6bd0e09dc043b6ea200f729c8c440d40b57 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 23 Sep 2016 17:19:44 +0200 Subject: iio:adc: Add support for AD7766/AD7767 Add support for the AD7766, AD7766-1, AD7766-2, AD7767, AD7767-1, AD7767-2 Analog to Digital converters. It's a family of single channel 24-bit SAR ADCs. They are all digital interface compatible and the main difference is the internal decimation rate and analog performance. For communication with the host processor a SPI interface is used. In addition the part has a data ready pin that is pulsed for one MCLK cycle when a conversion has completed and can be used as a IIO trigger. Datasheets: http://www.analog.com/media/en/technical-documentation/data-sheets/AD7766.pdf http://www.analog.com/media/en/technical-documentation/data-sheets/AD7767.pdf Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7766.c | 330 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 drivers/iio/adc/ad7766.c (limited to 'drivers') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7edcf3238620..60426685d55d 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -58,6 +58,18 @@ config AD7476 To compile this driver as a module, choose M here: the module will be called ad7476. +config AD7766 + tristate "Analog Devices AD7766/AD7767 ADC driver" + depends on SPI_MASTER + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Analog Devices AD7766, AD7766-1, + AD7766-2, AD7767, AD7767-1, AD7767-2 SPI analog to digital converters. + + To compile this driver as a module, choose M here: the module will be + called ad7766. + config AD7791 tristate "Analog Devices AD7791 ADC driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 7a40c04c311f..96894b32300d 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7923) += ad7923.o obj-$(CONFIG_AD7476) += ad7476.o +obj-$(CONFIG_AD7766) += ad7766.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7887) += ad7887.o diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c new file mode 100644 index 000000000000..d906686c48eb --- /dev/null +++ b/drivers/iio/adc/ad7766.c @@ -0,0 +1,330 @@ +/* + * AD7766/AD7767 SPI ADC driver + * + * Copyright 2016 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct ad7766_chip_info { + unsigned int decimation_factor; +}; + +enum { + AD7766_SUPPLY_AVDD = 0, + AD7766_SUPPLY_DVDD = 1, + AD7766_SUPPLY_VREF = 2, + AD7766_NUM_SUPPLIES = 3 +}; + +struct ad7766 { + const struct ad7766_chip_info *chip_info; + struct spi_device *spi; + struct clk *mclk; + struct gpio_desc *pd_gpio; + struct regulator_bulk_data reg[AD7766_NUM_SUPPLIES]; + + struct iio_trigger *trig; + + struct spi_transfer xfer; + struct spi_message msg; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + * Make the buffer large enough for one 24 bit sample and one 64 bit + * aligned 64 bit timestamp. + */ + unsigned char data[ALIGN(3, sizeof(s64)) + sizeof(s64)] + ____cacheline_aligned; +}; + +/* + * AD7766 and AD7767 variations are interface compatible, the main difference is + * analog performance. Both parts will use the same ID. + */ +enum ad7766_device_ids { + ID_AD7766, + ID_AD7766_1, + ID_AD7766_2, +}; + +static irqreturn_t ad7766_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad7766 *ad7766 = iio_priv(indio_dev); + int ret; + + ret = spi_sync(ad7766->spi, &ad7766->msg); + if (ret < 0) + goto done; + + iio_push_to_buffers_with_timestamp(indio_dev, ad7766->data, + pf->timestamp); +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int ad7766_preenable(struct iio_dev *indio_dev) +{ + struct ad7766 *ad7766 = iio_priv(indio_dev); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ad7766->reg), ad7766->reg); + if (ret < 0) { + dev_err(&ad7766->spi->dev, "Failed to enable supplies: %d\n", + ret); + return ret; + } + + ret = clk_prepare_enable(ad7766->mclk); + if (ret < 0) { + dev_err(&ad7766->spi->dev, "Failed to enable MCLK: %d\n", ret); + regulator_bulk_disable(ARRAY_SIZE(ad7766->reg), ad7766->reg); + return ret; + } + + if (ad7766->pd_gpio) + gpiod_set_value(ad7766->pd_gpio, 0); + + return 0; +} + +static int ad7766_postdisable(struct iio_dev *indio_dev) +{ + struct ad7766 *ad7766 = iio_priv(indio_dev); + + if (ad7766->pd_gpio) + gpiod_set_value(ad7766->pd_gpio, 1); + + /* + * The PD pin is synchronous to the clock, so give it some time to + * notice the change before we disable the clock. + */ + msleep(20); + + clk_disable_unprepare(ad7766->mclk); + regulator_bulk_disable(ARRAY_SIZE(ad7766->reg), ad7766->reg); + + return 0; +} + +static int ad7766_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, int *val2, long info) +{ + struct ad7766 *ad7766 = iio_priv(indio_dev); + struct regulator *vref = ad7766->reg[AD7766_SUPPLY_VREF].consumer; + int scale_uv; + + switch (info) { + case IIO_CHAN_INFO_SCALE: + scale_uv = regulator_get_voltage(vref); + if (scale_uv < 0) + return scale_uv; + *val = scale_uv / 1000; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = clk_get_rate(ad7766->mclk) / + ad7766->chip_info->decimation_factor; + return IIO_VAL_INT; + } + return -EINVAL; +} + +static const struct iio_chan_spec ad7766_channels[] = { + { + .type = IIO_VOLTAGE, + .indexed = 1, + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + .endianness = IIO_BE, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7766_chip_info ad7766_chip_info[] = { + [ID_AD7766] = { + .decimation_factor = 8, + }, + [ID_AD7766_1] = { + .decimation_factor = 16, + }, + [ID_AD7766_2] = { + .decimation_factor = 32, + }, +}; + +static const struct iio_buffer_setup_ops ad7766_buffer_setup_ops = { + .preenable = &ad7766_preenable, + .postenable = &iio_triggered_buffer_postenable, + .predisable = &iio_triggered_buffer_predisable, + .postdisable = &ad7766_postdisable, +}; + +static const struct iio_info ad7766_info = { + .driver_module = THIS_MODULE, + .read_raw = &ad7766_read_raw, +}; + +static irqreturn_t ad7766_irq(int irq, void *private) +{ + iio_trigger_poll(private); + return IRQ_HANDLED; +} + +static int ad7766_set_trigger_state(struct iio_trigger *trig, bool enable) +{ + struct ad7766 *ad7766 = iio_trigger_get_drvdata(trig); + + if (enable) + enable_irq(ad7766->spi->irq); + else + disable_irq(ad7766->spi->irq); + + return 0; +} + +static const struct iio_trigger_ops ad7766_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = ad7766_set_trigger_state, + .validate_device = iio_trigger_validate_own_device, +}; + +static int ad7766_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct iio_dev *indio_dev; + struct ad7766 *ad7766; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*ad7766)); + if (!indio_dev) + return -ENOMEM; + + ad7766 = iio_priv(indio_dev); + ad7766->chip_info = &ad7766_chip_info[id->driver_data]; + + ad7766->mclk = devm_clk_get(&spi->dev, "mclk"); + if (IS_ERR(ad7766->mclk)) + return PTR_ERR(ad7766->mclk); + + ad7766->reg[AD7766_SUPPLY_AVDD].supply = "avdd"; + ad7766->reg[AD7766_SUPPLY_DVDD].supply = "dvdd"; + ad7766->reg[AD7766_SUPPLY_VREF].supply = "vref"; + + ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(ad7766->reg), + ad7766->reg); + if (IS_ERR(ad7766->reg)) + return PTR_ERR(ad7766->reg); + + ad7766->pd_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(ad7766->pd_gpio)) + return PTR_ERR(ad7766->pd_gpio); + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ad7766_channels; + indio_dev->num_channels = ARRAY_SIZE(ad7766_channels); + indio_dev->info = &ad7766_info; + + if (spi->irq > 0) { + ad7766->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", + indio_dev->name, indio_dev->id); + if (!ad7766->trig) + return -ENOMEM; + + ad7766->trig->ops = &ad7766_trigger_ops; + ad7766->trig->dev.parent = &spi->dev; + iio_trigger_set_drvdata(ad7766->trig, ad7766); + + ret = devm_request_irq(&spi->dev, spi->irq, ad7766_irq, + IRQF_TRIGGER_FALLING, dev_name(&spi->dev), + ad7766->trig); + if (ret < 0) + return ret; + + /* + * The device generates interrupts as long as it is powered up. + * Some platforms might not allow the option to power it down so + * disable the interrupt to avoid extra load on the system + */ + disable_irq(spi->irq); + + ret = devm_iio_trigger_register(&spi->dev, ad7766->trig); + if (ret) + return ret; + } + + spi_set_drvdata(spi, indio_dev); + + ad7766->spi = spi; + + /* First byte always 0 */ + ad7766->xfer.rx_buf = &ad7766->data[1]; + ad7766->xfer.len = 3; + + spi_message_init(&ad7766->msg); + spi_message_add_tail(&ad7766->xfer, &ad7766->msg); + + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + &iio_pollfunc_store_time, &ad7766_trigger_handler, + &ad7766_buffer_setup_ops); + if (ret) + return ret; + + ret = devm_iio_device_register(&spi->dev, indio_dev); + if (ret) + return ret; + return 0; +} + +static const struct spi_device_id ad7766_id[] = { + {"ad7766", ID_AD7766}, + {"ad7766-1", ID_AD7766_1}, + {"ad7766-2", ID_AD7766_2}, + {"ad7767", ID_AD7766}, + {"ad7767-1", ID_AD7766_1}, + {"ad7767-2", ID_AD7766_2}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad7766_id); + +static struct spi_driver ad7766_driver = { + .driver = { + .name = "ad7766", + }, + .probe = ad7766_probe, + .id_table = ad7766_id, +}; +module_spi_driver(ad7766_driver); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("Analog Devices AD7766 and AD7767 ADCs driver support"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 2a20af722dde611b6b060af18dff651a8db96073 Mon Sep 17 00:00:00 2001 From: Sandhya Bankar Date: Sat, 24 Sep 2016 21:44:55 +0530 Subject: drivers: iio: light: Fix sparse warnings Fixing below warnings: drivers/iio/light/max44000.c:217:18: warning: cast to restricted __be16 drivers/iio/light/max44000.c:217:18: warning: cast to restricted __be16 drivers/iio/light/max44000.c:217:18: warning: cast to restricted __be16 drivers/iio/light/max44000.c:217:18: warning: cast to restricted __be16 Signed-off-by: Sandhya Bankar Signed-off-by: Jonathan Cameron --- drivers/iio/light/max44000.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index 6511b20a2a29..a144ca3461fc 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -204,17 +204,18 @@ static int max44000_write_alspga(struct max44000_data *data, int val) static int max44000_read_alsval(struct max44000_data *data) { u16 regval; + __be16 val; int alstim, ret; ret = regmap_bulk_read(data->regmap, MAX44000_REG_ALS_DATA_HI, - ®val, sizeof(regval)); + &val, sizeof(val)); if (ret < 0) return ret; alstim = ret = max44000_read_alstim(data); if (ret < 0) return ret; - regval = be16_to_cpu(regval); + regval = be16_to_cpu(val); /* * Overflow is explained on datasheet page 17. -- cgit v1.2.3 From 0023e67dd8951737588b8af0469446df3ec52afe Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Fri, 23 Sep 2016 23:04:07 -0700 Subject: iio: inkern: add iio_read_channel_offset helper Allow access to underlying channel IIO_CHAN_INFO_OFFSET from a consumer. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index c4757e6367e7..29df11572858 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -658,6 +658,31 @@ err_unlock: } EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); +static int iio_read_channel_attribute(struct iio_channel *chan, + int *val, int *val2, + enum iio_chan_info_enum attribute) +{ + int ret; + + mutex_lock(&chan->indio_dev->info_exist_lock); + if (chan->indio_dev->info == NULL) { + ret = -ENODEV; + goto err_unlock; + } + + ret = iio_channel_read(chan, val, val2, attribute); +err_unlock: + mutex_unlock(&chan->indio_dev->info_exist_lock); + + return ret; +} + +int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2) +{ + return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_OFFSET); +} +EXPORT_SYMBOL_GPL(iio_read_channel_offset); + int iio_read_channel_processed(struct iio_channel *chan, int *val) { int ret; @@ -687,19 +712,7 @@ EXPORT_SYMBOL_GPL(iio_read_channel_processed); int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) { - int ret; - - mutex_lock(&chan->indio_dev->info_exist_lock); - if (chan->indio_dev->info == NULL) { - ret = -ENODEV; - goto err_unlock; - } - - ret = iio_channel_read(chan, val, val2, IIO_CHAN_INFO_SCALE); -err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); - - return ret; + return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_SCALE); } EXPORT_SYMBOL_GPL(iio_read_channel_scale); -- cgit v1.2.3 From 92f0afb5b2be2e137ff223654af51f521dd74c3a Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sun, 18 Sep 2016 15:42:15 -0700 Subject: iio: adc: ti-adc161s626: add regulator support Allow IIO_CHAN_INFO_SCALE and IIO_CHAN_INFO_OFFSET attributes for processing by checking voltage from a regulator. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-adc161s626.c | 55 ++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c index f94b69f9c288..4836a0d7aef5 100644 --- a/drivers/iio/adc/ti-adc161s626.c +++ b/drivers/iio/adc/ti-adc161s626.c @@ -27,6 +27,7 @@ #include #include #include +#include #define TI_ADC_DRV_NAME "ti-adc161s626" @@ -39,7 +40,9 @@ static const struct iio_chan_spec ti_adc141s626_channels[] = { { .type = IIO_VOLTAGE, .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), .scan_index = 0, .scan_type = { .sign = 's', @@ -54,7 +57,9 @@ static const struct iio_chan_spec ti_adc161s626_channels[] = { { .type = IIO_VOLTAGE, .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), .scan_index = 0, .scan_type = { .sign = 's', @@ -68,6 +73,8 @@ static const struct iio_chan_spec ti_adc161s626_channels[] = { struct ti_adc_data { struct iio_dev *indio_dev; struct spi_device *spi; + struct regulator *ref; + u8 read_size; u8 shift; @@ -135,18 +142,32 @@ static int ti_adc_read_raw(struct iio_dev *indio_dev, struct ti_adc_data *data = iio_priv(indio_dev); int ret; - if (mask != IIO_CHAN_INFO_RAW) - return -EINVAL; + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + ret = ti_adc_read_measurement(data, chan, val); + iio_device_release_direct_mode(indio_dev); - ret = ti_adc_read_measurement(data, chan, val); - iio_device_release_direct_mode(indio_dev); + if (ret) + return ret; - if (!ret) return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = regulator_get_voltage(data->ref); + if (ret < 0) + return ret; + + *val = ret / 1000; + *val2 = chan->scan_type.realbits; + + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OFFSET: + *val = 1 << (chan->scan_type.realbits - 1); + return IIO_VAL_INT; + } return 0; } @@ -191,10 +212,17 @@ static int ti_adc_probe(struct spi_device *spi) break; } + data->ref = devm_regulator_get(&spi->dev, "vdda"); + if (!IS_ERR(data->ref)) { + ret = regulator_enable(data->ref); + if (ret < 0) + return ret; + } + ret = iio_triggered_buffer_setup(indio_dev, NULL, ti_adc_trigger_handler, NULL); if (ret) - return ret; + goto error_regulator_disable; ret = iio_device_register(indio_dev); if (ret) @@ -205,15 +233,20 @@ static int ti_adc_probe(struct spi_device *spi) error_unreg_buffer: iio_triggered_buffer_cleanup(indio_dev); +error_regulator_disable: + regulator_disable(data->ref); + return ret; } static int ti_adc_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ti_adc_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); + regulator_disable(data->ref); return 0; } -- cgit v1.2.3 From 67e17300dc1d76091d2d513d6aa57e50af2c9648 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 24 Sep 2016 21:03:00 -0700 Subject: iio: potentiostat: add LMP91000 support Add support for the LMP91000 potentiostat which is used for chemical sensing applications. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/potentiostat/Kconfig | 22 ++ drivers/iio/potentiostat/Makefile | 6 + drivers/iio/potentiostat/lmp91000.c | 446 ++++++++++++++++++++++++++++++++++++ 5 files changed, 476 insertions(+) create mode 100644 drivers/iio/potentiostat/Kconfig create mode 100644 drivers/iio/potentiostat/Makefile create mode 100644 drivers/iio/potentiostat/lmp91000.c (limited to 'drivers') diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 6743b18194fb..a31a8cf2c330 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -87,6 +87,7 @@ if IIO_TRIGGER source "drivers/iio/trigger/Kconfig" endif #IIO_TRIGGER source "drivers/iio/potentiometer/Kconfig" +source "drivers/iio/potentiostat/Kconfig" source "drivers/iio/pressure/Kconfig" source "drivers/iio/proximity/Kconfig" source "drivers/iio/temperature/Kconfig" diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 87e4c4369e2f..2b6e2762a886 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -29,6 +29,7 @@ obj-y += light/ obj-y += magnetometer/ obj-y += orientation/ obj-y += potentiometer/ +obj-y += potentiostat/ obj-y += pressure/ obj-y += proximity/ obj-y += temperature/ diff --git a/drivers/iio/potentiostat/Kconfig b/drivers/iio/potentiostat/Kconfig new file mode 100644 index 000000000000..1e3baf2cc97d --- /dev/null +++ b/drivers/iio/potentiostat/Kconfig @@ -0,0 +1,22 @@ +# +# Potentiostat drivers +# +# When adding new entries keep the list in alphabetical order + +menu "Digital potentiostats" + +config LMP91000 + tristate "Texas Instruments LMP91000 potentiostat driver" + depends on I2C + select REGMAP_I2C + select IIO_BUFFER + select IIO_BUFFER_CB + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the Texas Instruments + LMP91000 digital potentiostat chip. + + To compile this driver as a module, choose M here: the + module will be called lmp91000 + +endmenu diff --git a/drivers/iio/potentiostat/Makefile b/drivers/iio/potentiostat/Makefile new file mode 100644 index 000000000000..64d315ef4449 --- /dev/null +++ b/drivers/iio/potentiostat/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for industrial I/O potentiostat drivers +# + +# When adding new entries keep the list in alphabetical order +obj-$(CONFIG_LMP91000) += lmp91000.o diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c new file mode 100644 index 000000000000..e22714365022 --- /dev/null +++ b/drivers/iio/potentiostat/lmp91000.c @@ -0,0 +1,446 @@ +/* + * lmp91000.c - Support for Texas Instruments digital potentiostats + * + * Copyright (C) 2016 Matt Ranostay + * + * 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. + * + * TODO: bias voltage + polarity control, and multiple chip support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LMP91000_REG_LOCK 0x01 +#define LMP91000_REG_TIACN 0x10 +#define LMP91000_REG_TIACN_GAIN_SHIFT 2 + +#define LMP91000_REG_REFCN 0x11 +#define LMP91000_REG_REFCN_EXT_REF 0x20 +#define LMP91000_REG_REFCN_50_ZERO 0x80 + +#define LMP91000_REG_MODECN 0x12 +#define LMP91000_REG_MODECN_3LEAD 0x03 +#define LMP91000_REG_MODECN_TEMP 0x07 + +#define LMP91000_DRV_NAME "lmp91000" + +static const int lmp91000_tia_gain[] = { 0, 2750, 3500, 7000, 14000, 35000, + 120000, 350000 }; + +static const int lmp91000_rload[] = { 10, 33, 50, 100 }; + +#define LMP91000_TEMP_BASE -40 + +static const u16 lmp91000_temp_lut[] = { + 1875, 1867, 1860, 1852, 1844, 1836, 1828, 1821, 1813, 1805, + 1797, 1789, 1782, 1774, 1766, 1758, 1750, 1742, 1734, 1727, + 1719, 1711, 1703, 1695, 1687, 1679, 1671, 1663, 1656, 1648, + 1640, 1632, 1624, 1616, 1608, 1600, 1592, 1584, 1576, 1568, + 1560, 1552, 1544, 1536, 1528, 1520, 1512, 1504, 1496, 1488, + 1480, 1472, 1464, 1456, 1448, 1440, 1432, 1424, 1415, 1407, + 1399, 1391, 1383, 1375, 1367, 1359, 1351, 1342, 1334, 1326, + 1318, 1310, 1302, 1293, 1285, 1277, 1269, 1261, 1253, 1244, + 1236, 1228, 1220, 1212, 1203, 1195, 1187, 1179, 1170, 1162, + 1154, 1146, 1137, 1129, 1121, 1112, 1104, 1096, 1087, 1079, + 1071, 1063, 1054, 1046, 1038, 1029, 1021, 1012, 1004, 996, + 987, 979, 971, 962, 954, 945, 937, 929, 920, 912, + 903, 895, 886, 878, 870, 861 }; + +static const struct regmap_config lmp91000_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +struct lmp91000_data { + struct regmap *regmap; + struct device *dev; + + struct iio_trigger *trig; + struct iio_cb_buffer *cb_buffer; + struct iio_channel *adc_chan; + + struct completion completion; + u8 chan_select; + + u32 buffer[4]; /* 64-bit data + 64-bit timestamp */ +}; + +static const struct iio_chan_spec lmp91000_channels[] = { + { /* chemical channel mV */ + .type = IIO_VOLTAGE, + .channel = 0, + .address = LMP91000_REG_MODECN_3LEAD, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 32, + .storagebits = 32, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(1), + { /* temperature channel mV */ + .type = IIO_TEMP, + .channel = 1, + .address = LMP91000_REG_MODECN_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .scan_index = -1, + }, +}; + +static int lmp91000_read(struct lmp91000_data *data, int channel, int *val) +{ + int state, ret; + + ret = regmap_read(data->regmap, LMP91000_REG_MODECN, &state); + if (ret) + return -EINVAL; + + ret = regmap_write(data->regmap, LMP91000_REG_MODECN, channel); + if (ret) + return -EINVAL; + + /* delay till first temperature reading is complete */ + if ((state != channel) && (channel == LMP91000_REG_MODECN_TEMP)) + usleep_range(3000, 4000); + + data->chan_select = channel != LMP91000_REG_MODECN_3LEAD; + + iio_trigger_poll_chained(data->trig); + + ret = wait_for_completion_timeout(&data->completion, HZ); + reinit_completion(&data->completion); + + if (!ret) + return -ETIMEDOUT; + + *val = data->buffer[data->chan_select]; + + return 0; +} + +static irqreturn_t lmp91000_buffer_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct lmp91000_data *data = iio_priv(indio_dev); + int ret, val; + + memset(data->buffer, 0, sizeof(data->buffer)); + + ret = lmp91000_read(data, LMP91000_REG_MODECN_3LEAD, &val); + if (!ret) { + data->buffer[0] = val; + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_get_time_ns(indio_dev)); + } + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int lmp91000_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct lmp91000_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: { + int ret = iio_channel_start_all_cb(data->cb_buffer); + + if (ret) + return ret; + + ret = lmp91000_read(data, chan->address, val); + + iio_channel_stop_all_cb(data->cb_buffer); + + if (ret) + return ret; + + if (mask == IIO_CHAN_INFO_PROCESSED) { + int tmp, i; + + ret = iio_convert_raw_to_processed(data->adc_chan, + *val, &tmp, 1); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(lmp91000_temp_lut); i++) + if (lmp91000_temp_lut[i] < tmp) + break; + + *val = (LMP91000_TEMP_BASE + i) * 1000; + } + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_OFFSET: + return iio_read_channel_offset(data->adc_chan, val, val2); + case IIO_CHAN_INFO_SCALE: + return iio_read_channel_scale(data->adc_chan, val, val2); + } + + return -EINVAL; +} + +static const struct iio_info lmp91000_info = { + .driver_module = THIS_MODULE, + .read_raw = lmp91000_read_raw, +}; + +static int lmp91000_read_config(struct lmp91000_data *data) +{ + struct device *dev = data->dev; + struct device_node *np = dev->of_node; + unsigned int reg, val; + int i, ret; + + ret = of_property_read_u32(np, "ti,tia-gain-ohm", &val); + if (ret) { + if (of_property_read_bool(np, "ti,external-tia-resistor")) + val = 0; + else { + dev_err(dev, "no ti,tia-gain-ohm defined"); + return ret; + } + } + + ret = -EINVAL; + for (i = 0; i < ARRAY_SIZE(lmp91000_tia_gain); i++) { + if (lmp91000_tia_gain[i] == val) { + reg = i << LMP91000_REG_TIACN_GAIN_SHIFT; + ret = 0; + break; + } + } + + if (ret) { + dev_err(dev, "invalid ti,tia-gain-ohm %d\n", val); + return ret; + } + + ret = of_property_read_u32(np, "ti,rload-ohm", &val); + if (ret) { + val = 100; + dev_info(dev, "no ti,rload-ohm defined, default to %d\n", val); + } + + ret = -EINVAL; + for (i = 0; i < ARRAY_SIZE(lmp91000_rload); i++) { + if (lmp91000_rload[i] == val) { + reg |= i; + ret = 0; + break; + } + } + + if (ret) { + dev_err(dev, "invalid ti,rload-ohm %d\n", val); + return ret; + } + + regmap_write(data->regmap, LMP91000_REG_LOCK, 0); + regmap_write(data->regmap, LMP91000_REG_TIACN, reg); + regmap_write(data->regmap, LMP91000_REG_REFCN, LMP91000_REG_REFCN_EXT_REF + | LMP91000_REG_REFCN_50_ZERO); + regmap_write(data->regmap, LMP91000_REG_LOCK, 1); + + return 0; +} + +static int lmp91000_buffer_cb(const void *val, void *private) +{ + struct iio_dev *indio_dev = private; + struct lmp91000_data *data = iio_priv(indio_dev); + + data->buffer[data->chan_select] = *((int *)val); + complete_all(&data->completion); + + return 0; +} + +static const struct iio_trigger_ops lmp91000_trigger_ops = { + .owner = THIS_MODULE, +}; + + +static int lmp91000_buffer_preenable(struct iio_dev *indio_dev) +{ + struct lmp91000_data *data = iio_priv(indio_dev); + + return iio_channel_start_all_cb(data->cb_buffer); +} + +static int lmp91000_buffer_predisable(struct iio_dev *indio_dev) +{ + struct lmp91000_data *data = iio_priv(indio_dev); + + iio_channel_stop_all_cb(data->cb_buffer); + + return 0; +} + +static const struct iio_buffer_setup_ops lmp91000_buffer_setup_ops = { + .preenable = lmp91000_buffer_preenable, + .postenable = iio_triggered_buffer_postenable, + .predisable = lmp91000_buffer_predisable, +}; + +static int lmp91000_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct lmp91000_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + indio_dev->info = &lmp91000_info; + indio_dev->channels = lmp91000_channels; + indio_dev->num_channels = ARRAY_SIZE(lmp91000_channels); + indio_dev->name = LMP91000_DRV_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + i2c_set_clientdata(client, indio_dev); + + data = iio_priv(indio_dev); + data->dev = dev; + data->regmap = devm_regmap_init_i2c(client, &lmp91000_regmap_config); + if (IS_ERR(data->regmap)) { + dev_err(dev, "regmap initialization failed.\n"); + return PTR_ERR(data->regmap); + } + + data->trig = devm_iio_trigger_alloc(data->dev, "%s-mux%d", + indio_dev->name, indio_dev->id); + if (!data->trig) { + dev_err(dev, "cannot allocate iio trigger.\n"); + return -ENOMEM; + } + + data->trig->ops = &lmp91000_trigger_ops; + data->trig->dev.parent = dev; + init_completion(&data->completion); + + ret = lmp91000_read_config(data); + if (ret) + return ret; + + ret = iio_trigger_set_immutable(iio_channel_cb_get_iio_dev(data->cb_buffer), + data->trig); + if (ret) { + dev_err(dev, "cannot set immutable trigger.\n"); + return ret; + } + + ret = iio_trigger_register(data->trig); + if (ret) { + dev_err(dev, "cannot register iio trigger.\n"); + return ret; + } + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &lmp91000_buffer_handler, + &lmp91000_buffer_setup_ops); + if (ret) + goto error_unreg_trigger; + + data->cb_buffer = iio_channel_get_all_cb(dev, &lmp91000_buffer_cb, + indio_dev); + + if (IS_ERR(data->cb_buffer)) { + if (PTR_ERR(data->cb_buffer) == -ENODEV) + ret = -EPROBE_DEFER; + else + ret = PTR_ERR(data->cb_buffer); + + goto error_unreg_buffer; + } + + data->adc_chan = iio_channel_cb_get_channels(data->cb_buffer); + + ret = iio_device_register(indio_dev); + if (ret) + goto error_unreg_cb_buffer; + + return 0; + +error_unreg_cb_buffer: + iio_channel_release_all_cb(data->cb_buffer); + +error_unreg_buffer: + iio_triggered_buffer_cleanup(indio_dev); + +error_unreg_trigger: + iio_trigger_unregister(data->trig); + + return ret; +} + +static int lmp91000_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct lmp91000_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + iio_channel_stop_all_cb(data->cb_buffer); + iio_channel_release_all_cb(data->cb_buffer); + + iio_triggered_buffer_cleanup(indio_dev); + iio_trigger_unregister(data->trig); + + return 0; +} + +static const struct of_device_id lmp91000_of_match[] = { + { .compatible = "ti,lmp91000", }, + { }, +}; +MODULE_DEVICE_TABLE(of, lmp91000_of_match); + +static const struct i2c_device_id lmp91000_id[] = { + { "lmp91000", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, lmp91000_id); + +static struct i2c_driver lmp91000_driver = { + .driver = { + .name = LMP91000_DRV_NAME, + .of_match_table = of_match_ptr(lmp91000_of_match), + }, + .probe = lmp91000_probe, + .remove = lmp91000_remove, + .id_table = lmp91000_id, +}; +module_i2c_driver(lmp91000_driver); + +MODULE_AUTHOR("Matt Ranostay "); +MODULE_DESCRIPTION("LMP91000 digital potentiostat"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 69c72ec9c80bbd206c6fac73874d73e69cc623b4 Mon Sep 17 00:00:00 2001 From: Sandhya Bankar Date: Sun, 25 Sep 2016 18:33:17 +0530 Subject: drivers: iio: magnetometer: Fix sparse endianness warnings cast to restricted __be16 Fix the following sparse endianness warnings: drivers/iio/magnetometer/ak8975.c:716:16: warning: cast to restricted __le16 drivers/iio/magnetometer/ak8975.c:837:19: warning: cast to restricted __le16 drivers/iio/magnetometer/ak8975.c:838:19: warning: cast to restricted __le16 drivers/iio/magnetometer/ak8975.c:839:19: warning: cast to restricted __le16 Signed-off-by: Sandhya Bankar Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index af8606cc7812..825369fb1c57 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -690,6 +690,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) struct ak8975_data *data = iio_priv(indio_dev); const struct i2c_client *client = data->client; const struct ak_def *def = data->def; + __le16 rval; u16 buff; int ret; @@ -703,7 +704,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) ret = i2c_smbus_read_i2c_block_data_or_emulated( client, def->data_regs[index], - sizeof(buff), (u8*)&buff); + sizeof(rval), (u8*)&rval); if (ret < 0) goto exit; @@ -713,7 +714,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) pm_runtime_put_autosuspend(&data->client->dev); /* Swap bytes and convert to valid range. */ - buff = le16_to_cpu(buff); + buff = le16_to_cpu(rval); *val = clamp_t(s16, buff, -def->range, def->range); return IIO_VAL_INT; @@ -813,6 +814,7 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) const struct ak_def *def = data->def; int ret; s16 buff[8]; /* 3 x 16 bits axis values + 1 aligned 64 bits timestamp */ + __le16 fval[3]; mutex_lock(&data->lock); @@ -826,17 +828,17 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) */ ret = i2c_smbus_read_i2c_block_data_or_emulated(client, def->data_regs[0], - 3 * sizeof(buff[0]), - (u8 *)buff); + 3 * sizeof(fval[0]), + (u8 *)fval); if (ret < 0) goto unlock; mutex_unlock(&data->lock); /* Clamp to valid range. */ - buff[0] = clamp_t(s16, le16_to_cpu(buff[0]), -def->range, def->range); - buff[1] = clamp_t(s16, le16_to_cpu(buff[1]), -def->range, def->range); - buff[2] = clamp_t(s16, le16_to_cpu(buff[2]), -def->range, def->range); + buff[0] = clamp_t(s16, le16_to_cpu(fval[0]), -def->range, def->range); + buff[1] = clamp_t(s16, le16_to_cpu(fval[1]), -def->range, def->range); + buff[2] = clamp_t(s16, le16_to_cpu(fval[2]), -def->range, def->range); iio_push_to_buffers_with_timestamp(indio_dev, buff, iio_get_time_ns(indio_dev)); -- cgit v1.2.3 From 7fd1accc9fc46c27687f2ea767d84c146790ef1c Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Sun, 25 Sep 2016 07:41:05 -0400 Subject: staging: iio: isl29018: remove unused variable and defines Removes unused variable and associated #defines that was found using make W=1. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index a767a43c995c..2a055d6c32ba 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -62,16 +62,6 @@ #define ISL29035_BOUT_SHIFT 0x07 #define ISL29035_BOUT_MASK (0x01 << ISL29035_BOUT_SHIFT) -#define ISL29018_INT_TIME_AVAIL "0.090000 0.005630 0.000351 0.000021" -#define ISL29023_INT_TIME_AVAIL "0.090000 0.005600 0.000352 0.000022" -#define ISL29035_INT_TIME_AVAIL "0.105000 0.006500 0.000410 0.000025" - -static const char * const int_time_avail[] = { - ISL29018_INT_TIME_AVAIL, - ISL29023_INT_TIME_AVAIL, - ISL29035_INT_TIME_AVAIL, -}; - enum isl29018_int_time { ISL29018_INT_TIME_16, ISL29018_INT_TIME_12, -- cgit v1.2.3 From 528021fcd21fdffad83563710f1186d9b3d21718 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Sun, 25 Sep 2016 07:41:06 -0400 Subject: staging: iio: isl29018: made error handling consistent Changed the processing of IIO_CHAN_INFO_INT_TIME in isl29018_write_raw() to unlock the mutex and return at the end of the function if invalid input is passed in. This makes the error handling code consistent with the processing of IIO_CHAN_INFO_CALIBSCALE and IIO_CHAN_INFO_SCALE within the same function. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 2a055d6c32ba..f03122c66045 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -356,13 +356,8 @@ static int isl29018_write_raw(struct iio_dev *indio_dev, } break; case IIO_CHAN_INFO_INT_TIME: - if (chan->type == IIO_LIGHT) { - if (val) { - mutex_unlock(&chip->lock); - return -EINVAL; - } + if (chan->type == IIO_LIGHT && !val) ret = isl29018_set_integration_time(chip, val2); - } break; case IIO_CHAN_INFO_SCALE: if (chan->type == IIO_LIGHT) -- cgit v1.2.3 From ea908ab69e7531bcebaf42e9c0c6f0b95a04330f Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Sun, 25 Sep 2016 07:41:07 -0400 Subject: staging: iio: isl29018: fix comparison between signed and unsigned integers Fixes warning found by make W=2: warning: comparison between signed and unsigned integer expressions Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index f03122c66045..30dc1da95459 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -100,7 +100,8 @@ struct isl29018_chip { static int isl29018_set_integration_time(struct isl29018_chip *chip, unsigned int utime) { - int i, ret; + unsigned int i; + int ret; unsigned int int_time, new_int_time; for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) { @@ -135,7 +136,8 @@ static int isl29018_set_integration_time(struct isl29018_chip *chip, static int isl29018_set_scale(struct isl29018_chip *chip, int scale, int uscale) { - int i, ret; + unsigned int i; + int ret; struct isl29018_scale new_scale; for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) { @@ -271,7 +273,8 @@ static ssize_t isl29018_show_scale_available(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); - int i, len = 0; + unsigned int i; + int len = 0; for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) len += sprintf(buf + len, "%d.%06d ", @@ -288,7 +291,8 @@ static ssize_t isl29018_show_int_time_available(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); - int i, len = 0; + unsigned int i; + int len = 0; for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) len += sprintf(buf + len, "0.%06d ", -- cgit v1.2.3 From d306ddbad1b21287eb4a779dbc1d1e782f2fb1e1 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Mon, 26 Sep 2016 10:31:38 +0530 Subject: Staging:iio:adc:ad7280a: constify attribute_group structures Check for attribute_group structures that are only stored in the attrs filed of iio_info structure. As the attrs field of iio_info structures is constant, so these attribute_group structures can also be declared constant. Done using coccinelle: @r1 disable optional_qualifier @ identifier i; position p; @@ static struct attribute_group i@p = {...}; @ok1@ identifier r1.i; position p; struct iio_info x; @@ x.attrs=&i@p; @bad@ position p!={r1.p,ok1.p}; identifier r1.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r1.i; @@ static +const struct attribute_group i={...}; @depends on !bad disable optional_qualifier@ identifier r1.i; @@ +const struct attribute_group i; File size before: drivers/staging/iio/adc/ad7280a.o text data bss dec hex filename 6487 584 776 7847 1ea7 drivers/staging/iio/adc/ad7280a.o File size after: drivers/staging/iio/adc/ad7280a.o text data bss dec hex filename 6551 544 776 7871 1ebf drivers/staging/iio/adc/ad7280a.o Signed-off-by: Bhumika Goyal Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7280a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 2177f1dd2b5d..b460dda7eb65 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -478,7 +478,7 @@ static ssize_t ad7280_store_balance_timer(struct device *dev, static struct attribute *ad7280_attributes[AD7280A_MAX_CHAIN * AD7280A_CELLS_PER_DEV * 2 + 1]; -static struct attribute_group ad7280_attrs_group = { +static const struct attribute_group ad7280_attrs_group = { .attrs = ad7280_attributes, }; -- cgit v1.2.3 From 1cb357695849542b71ad8f76b2c2cba308b27e24 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Mon, 26 Sep 2016 10:31:39 +0530 Subject: Staging:iio:light:tsl2583: constify attribute_group structures Check for attribute_group structures that are only stored in the attrs filed of iio_info structure. As the attrs field of iio_info structures is constant, so these attribute_group structures can also be declared constant. Done using coccinelle @r1 disable optional_qualifier @ identifier i; position p; @@ static struct attribute_group i@p = {...}; @ok1@ identifier r1.i; position p; struct iio_info x; @@ x.attrs=&i@p; @bad@ position p!={r1.p,ok1.p}; identifier r1.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r1.i; @@ static +const struct attribute_group i={...}; @depends on !bad disable optional_qualifier@ identifier r1.i; @@ +const struct attribute_group i; File size before: drivers/staging/iio/light/tsl2583.o text data bss dec hex filename 6529 1052 0 7581 1d9d drivers/staging/iio/light/tsl2583.o File size after: drivers/staging/iio/light/tsl2583.o text data bss dec hex filename 6593 988 0 7581 1d9d drivers/staging/iio/light/tsl2583.o Signed-off-by: Bhumika Goyal Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/tsl2583.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c index 05b4ad4e941c..08f1583ee34e 100644 --- a/drivers/staging/iio/light/tsl2583.c +++ b/drivers/staging/iio/light/tsl2583.c @@ -803,7 +803,7 @@ static struct attribute *sysfs_attrs_ctrl[] = { NULL }; -static struct attribute_group tsl2583_attribute_group = { +static const struct attribute_group tsl2583_attribute_group = { .attrs = sysfs_attrs_ctrl, }; -- cgit v1.2.3 From 028199660d8f53f1856bbe8cf6771d3351eaa182 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 26 Sep 2016 20:20:17 -0400 Subject: staging: iio: isl29018: use IIO_DEVICE_ATTR_{RO, RW} macros Use the IIO_DEVICE_ATTR_RO and IIO_DEVICE_ATTR_RW macros to create the device attributes. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 30dc1da95459..19f282c13651 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -268,8 +268,9 @@ static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme, return 0; } -static ssize_t isl29018_show_scale_available(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t in_illuminance_scale_available_show + (struct device *dev, struct device_attribute *attr, + char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); @@ -286,8 +287,9 @@ static ssize_t isl29018_show_scale_available(struct device *dev, return len; } -static ssize_t isl29018_show_int_time_available(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t in_illuminance_integration_time_available_show + (struct device *dev, struct device_attribute *attr, + char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); @@ -303,9 +305,9 @@ static ssize_t isl29018_show_int_time_available(struct device *dev, return len; } -static ssize_t isl29018_show_prox_infrared_suppression(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t proximity_on_chip_ambient_infrared_suppression_show + (struct device *dev, struct device_attribute *attr, + char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); @@ -317,9 +319,9 @@ static ssize_t isl29018_show_prox_infrared_suppression(struct device *dev, return sprintf(buf, "%d\n", chip->prox_scheme); } -static ssize_t isl29018_store_prox_infrared_suppression(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t proximity_on_chip_ambient_infrared_suppression_store + (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); @@ -471,14 +473,9 @@ static const struct iio_chan_spec isl29023_channels[] = { ISL29018_IR_CHANNEL, }; -static IIO_DEVICE_ATTR(in_illuminance_integration_time_available, S_IRUGO, - isl29018_show_int_time_available, NULL, 0); -static IIO_DEVICE_ATTR(in_illuminance_scale_available, S_IRUGO, - isl29018_show_scale_available, NULL, 0); -static IIO_DEVICE_ATTR(proximity_on_chip_ambient_infrared_suppression, - S_IRUGO | S_IWUSR, - isl29018_show_prox_infrared_suppression, - isl29018_store_prox_infrared_suppression, 0); +static IIO_DEVICE_ATTR_RO(in_illuminance_integration_time_available, 0); +static IIO_DEVICE_ATTR_RO(in_illuminance_scale_available, 0); +static IIO_DEVICE_ATTR_RW(proximity_on_chip_ambient_infrared_suppression, 0); #define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) -- cgit v1.2.3 From 5faf98cb319bc7ce7cef080be1bbebba44233332 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 26 Sep 2016 20:20:18 -0400 Subject: staging: iio: isl29018: fixed race condition in in_illuminance_scale_available_show() in_illuminance_scale_available_show() references the isl29018_chip->int_time variable in three places inside a for loop. The value of the int_time variable can be updated by the isl29018_set_integration_time() function, which is called by the isl29018_write_raw() function. isl29018_write_raw() locks a mutex specific to this driver when the integration time variable is updated. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 19f282c13651..990c6e52bafe 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -277,10 +277,12 @@ static ssize_t in_illuminance_scale_available_show unsigned int i; int len = 0; + mutex_lock(&chip->lock); for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) len += sprintf(buf + len, "%d.%06d ", isl29018_scales[chip->int_time][i].scale, isl29018_scales[chip->int_time][i].uscale); + mutex_unlock(&chip->lock); buf[len - 1] = '\n'; -- cgit v1.2.3 From 5611cd6fc61dbccdba61656bea9c5c1634b51e46 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 26 Sep 2016 20:20:19 -0400 Subject: staging: iio: isl29018: change isl29018_read_raw() to only have one exit point When the chip is in a suspended state, isl29018_read_raw() will return -EBUSY. Change the function so that it only has a single exit point. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 990c6e52bafe..3a4d79d7e23c 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -390,8 +390,8 @@ static int isl29018_read_raw(struct iio_dev *indio_dev, mutex_lock(&chip->lock); if (chip->suspended) { - mutex_unlock(&chip->lock); - return -EBUSY; + ret = -EBUSY; + goto read_done; } switch (mask) { case IIO_CHAN_INFO_RAW: @@ -438,6 +438,8 @@ static int isl29018_read_raw(struct iio_dev *indio_dev, default: break; } + +read_done: mutex_unlock(&chip->lock); return ret; } -- cgit v1.2.3 From 00053566385e3e7a2f81f0fd2fa09bccce1589f2 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 26 Sep 2016 20:20:20 -0400 Subject: staging: iio: isl29018: check if the chip is in a suspended state Add a check to isl29018_write_raw() to ensure that the chip is not in a suspended state. This makes the code consistent with what is present in isl29018_read_raw(). Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 3a4d79d7e23c..51226bd337c5 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -355,6 +355,10 @@ static int isl29018_write_raw(struct iio_dev *indio_dev, int ret = -EINVAL; mutex_lock(&chip->lock); + if (chip->suspended) { + ret = -EBUSY; + goto write_done; + } switch (mask) { case IIO_CHAN_INFO_CALIBSCALE: if (chan->type == IIO_LIGHT) { @@ -374,8 +378,9 @@ static int isl29018_write_raw(struct iio_dev *indio_dev, default: break; } - mutex_unlock(&chip->lock); +write_done: + mutex_unlock(&chip->lock); return ret; } -- cgit v1.2.3 From 9ecca12edde435efc6d08f7a1e877ba9929a6c93 Mon Sep 17 00:00:00 2001 From: Marcin Malagowski Date: Mon, 26 Sep 2016 19:23:06 +0200 Subject: iio: pressure: Add driver for Honeywell ABP family This patch adds minimal driver for the Honeywell Amplified Basic Pressure sensors series. Sensors are pretty simple but are available in many variants: - psi/mbar/kPa output, - analog/i2c/spi, - gage/differential measurement, - different measure ranges etc. Refer to datasheets for more details: http://sensing.honeywell.com/honeywell-sensing-basic-board-mount-pressure-sensors-abp-series-datasheet-323005128-c-en.pdf http://sensing.honeywell.com/index.php%3Fci_id%3D45841 Driver internals: - i2c only. measure request is done by the SMBUS QUICK cmd, so if the i2c bus doesn't support it, it is required to send a dummy byte to trigger measurement, - since iio sysfs expects kilopascals, mbar-variants are treated as their respective kPa-s, hence i2c id-table has doubled entries in one line: { "abp060mg", ABP006KG }, { "abp006kg", ABP006KG }, - psi-variants have prescaled values in config, - no temperature reads yet. Work remained: - optional temperature channel, - SPI support, - DT binding. Changes since v1: - mutex is now locked in read_raw(), - corrected error codes, - fixed coding style issues, - renamed few defines and functions abp -> abp060mg (some structs left as they were to keep the sensible meaning). Signed-off-by: Marcin Malagowski Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/Kconfig | 10 ++ drivers/iio/pressure/Makefile | 1 + drivers/iio/pressure/abp060mg.c | 276 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 drivers/iio/pressure/abp060mg.c (limited to 'drivers') diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index cc090d803465..2347bb74521a 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -5,6 +5,16 @@ menu "Pressure sensors" +config ABP060MG + tristate "Honeywell ABP pressure sensor driver" + depends on I2C + help + Say yes here to build support for the Honeywell ABP pressure + sensors. + + To compile this driver as a module, choose M here: the module + will be called abp060mg. + config BMP280 tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver" depends on (I2C || SPI_MASTER) diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index fff77185a5cc..de3dbc81dc5a 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -3,6 +3,7 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_ABP060MG) += abp060mg.o obj-$(CONFIG_BMP280) += bmp280.o bmp280-objs := bmp280-core.o bmp280-regmap.o obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o diff --git a/drivers/iio/pressure/abp060mg.c b/drivers/iio/pressure/abp060mg.c new file mode 100644 index 000000000000..43bdd0b9155f --- /dev/null +++ b/drivers/iio/pressure/abp060mg.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2016 - Marcin Malagowski + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define ABP060MG_ERROR_MASK 0xC000 +#define ABP060MG_RESP_TIME_MS 40 +#define ABP060MG_MIN_COUNTS 1638 /* = 0x0666 (10% of u14) */ +#define ABP060MG_MAX_COUNTS 14745 /* = 0x3999 (90% of u14) */ +#define ABP060MG_NUM_COUNTS (ABP060MG_MAX_COUNTS - ABP060MG_MIN_COUNTS) + +enum abp_variant { + /* gage [kPa] */ + ABP006KG, ABP010KG, ABP016KG, ABP025KG, ABP040KG, ABP060KG, ABP100KG, + ABP160KG, ABP250KG, ABP400KG, ABP600KG, ABP001GG, + /* differential [kPa] */ + ABP006KD, ABP010KD, ABP016KD, ABP025KD, ABP040KD, ABP060KD, ABP100KD, + ABP160KD, ABP250KD, ABP400KD, + /* gage [psi] */ + ABP001PG, ABP005PG, ABP015PG, ABP030PG, ABP060PG, ABP100PG, ABP150PG, + /* differential [psi] */ + ABP001PD, ABP005PD, ABP015PD, ABP030PD, ABP060PD, +}; + +struct abp_config { + int min; + int max; +}; + +static struct abp_config abp_config[] = { + /* mbar & kPa variants */ + [ABP006KG] = { .min = 0, .max = 6000 }, + [ABP010KG] = { .min = 0, .max = 10000 }, + [ABP016KG] = { .min = 0, .max = 16000 }, + [ABP025KG] = { .min = 0, .max = 25000 }, + [ABP040KG] = { .min = 0, .max = 40000 }, + [ABP060KG] = { .min = 0, .max = 60000 }, + [ABP100KG] = { .min = 0, .max = 100000 }, + [ABP160KG] = { .min = 0, .max = 160000 }, + [ABP250KG] = { .min = 0, .max = 250000 }, + [ABP400KG] = { .min = 0, .max = 400000 }, + [ABP600KG] = { .min = 0, .max = 600000 }, + [ABP001GG] = { .min = 0, .max = 1000000 }, + [ABP006KD] = { .min = -6000, .max = 6000 }, + [ABP010KD] = { .min = -10000, .max = 10000 }, + [ABP016KD] = { .min = -16000, .max = 16000 }, + [ABP025KD] = { .min = -25000, .max = 25000 }, + [ABP040KD] = { .min = -40000, .max = 40000 }, + [ABP060KD] = { .min = -60000, .max = 60000 }, + [ABP100KD] = { .min = -100000, .max = 100000 }, + [ABP160KD] = { .min = -160000, .max = 160000 }, + [ABP250KD] = { .min = -250000, .max = 250000 }, + [ABP400KD] = { .min = -400000, .max = 400000 }, + /* psi variants (1 psi ~ 6895 Pa) */ + [ABP001PG] = { .min = 0, .max = 6985 }, + [ABP005PG] = { .min = 0, .max = 34474 }, + [ABP015PG] = { .min = 0, .max = 103421 }, + [ABP030PG] = { .min = 0, .max = 206843 }, + [ABP060PG] = { .min = 0, .max = 413686 }, + [ABP100PG] = { .min = 0, .max = 689476 }, + [ABP150PG] = { .min = 0, .max = 1034214 }, + [ABP001PD] = { .min = -6895, .max = 6895 }, + [ABP005PD] = { .min = -34474, .max = 34474 }, + [ABP015PD] = { .min = -103421, .max = 103421 }, + [ABP030PD] = { .min = -206843, .max = 206843 }, + [ABP060PD] = { .min = -413686, .max = 413686 }, +}; + +struct abp_state { + struct i2c_client *client; + struct mutex lock; + + /* + * bus-dependent MEASURE_REQUEST length. + * If no SMBUS_QUICK support, need to send dummy byte + */ + int mreq_len; + + /* model-dependent values (calculated on probe) */ + int scale; + int offset; +}; + +static const struct iio_chan_spec abp060mg_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static int abp060mg_get_measurement(struct abp_state *state, int *val) +{ + struct i2c_client *client = state->client; + __be16 buf[2]; + u16 pressure; + int ret; + + buf[0] = 0; + ret = i2c_master_send(client, (u8 *)&buf, state->mreq_len); + if (ret < 0) + return ret; + + msleep_interruptible(ABP060MG_RESP_TIME_MS); + + ret = i2c_master_recv(client, (u8 *)&buf, sizeof(buf)); + if (ret < 0) + return ret; + + pressure = be16_to_cpu(buf[0]); + if (pressure & ABP060MG_ERROR_MASK) + return -EIO; + + if (pressure < ABP060MG_MIN_COUNTS || pressure > ABP060MG_MAX_COUNTS) + return -EIO; + + *val = pressure; + + return IIO_VAL_INT; +} + +static int abp060mg_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct abp_state *state = iio_priv(indio_dev); + int ret; + + mutex_lock(&state->lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = abp060mg_get_measurement(state, val); + break; + case IIO_CHAN_INFO_OFFSET: + *val = state->offset; + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SCALE: + *val = state->scale; + *val2 = ABP060MG_NUM_COUNTS * 1000; /* to kPa */ + ret = IIO_VAL_FRACTIONAL; + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&state->lock); + return ret; +} + +static const struct iio_info abp060mg_info = { + .driver_module = THIS_MODULE, + .read_raw = abp060mg_read_raw, +}; + +static void abp060mg_init_device(struct iio_dev *indio_dev, unsigned long id) +{ + struct abp_state *state = iio_priv(indio_dev); + struct abp_config *cfg = &abp_config[id]; + + state->scale = cfg->max - cfg->min; + state->offset = -ABP060MG_MIN_COUNTS; + + if (cfg->min < 0) /* differential */ + state->offset -= ABP060MG_NUM_COUNTS >> 1; +} + +static int abp060mg_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct abp_state *state; + unsigned long cfg_id = id->driver_data; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*state)); + if (!indio_dev) + return -ENOMEM; + + state = iio_priv(indio_dev); + i2c_set_clientdata(client, state); + state->client = client; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_QUICK)) + state->mreq_len = 1; + + abp060mg_init_device(indio_dev, cfg_id); + + indio_dev->dev.parent = &client->dev; + indio_dev->name = dev_name(&client->dev); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &abp060mg_info; + + indio_dev->channels = abp060mg_channels; + indio_dev->num_channels = ARRAY_SIZE(abp060mg_channels); + + mutex_init(&state->lock); + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id abp060mg_id_table[] = { + /* mbar & kPa variants (abp060m [60 mbar] == abp006k [6 kPa]) */ + /* gage: */ + { "abp060mg", ABP006KG }, { "abp006kg", ABP006KG }, + { "abp100mg", ABP010KG }, { "abp010kg", ABP010KG }, + { "abp160mg", ABP016KG }, { "abp016kg", ABP016KG }, + { "abp250mg", ABP025KG }, { "abp025kg", ABP025KG }, + { "abp400mg", ABP040KG }, { "abp040kg", ABP040KG }, + { "abp600mg", ABP060KG }, { "abp060kg", ABP060KG }, + { "abp001bg", ABP100KG }, { "abp100kg", ABP100KG }, + { "abp1_6bg", ABP160KG }, { "abp160kg", ABP160KG }, + { "abp2_5bg", ABP250KG }, { "abp250kg", ABP250KG }, + { "abp004bg", ABP400KG }, { "abp400kg", ABP400KG }, + { "abp006bg", ABP600KG }, { "abp600kg", ABP600KG }, + { "abp010bg", ABP001GG }, { "abp001gg", ABP001GG }, + /* differential: */ + { "abp060md", ABP006KD }, { "abp006kd", ABP006KD }, + { "abp100md", ABP010KD }, { "abp010kd", ABP010KD }, + { "abp160md", ABP016KD }, { "abp016kd", ABP016KD }, + { "abp250md", ABP025KD }, { "abp025kd", ABP025KD }, + { "abp400md", ABP040KD }, { "abp040kd", ABP040KD }, + { "abp600md", ABP060KD }, { "abp060kd", ABP060KD }, + { "abp001bd", ABP100KD }, { "abp100kd", ABP100KD }, + { "abp1_6bd", ABP160KD }, { "abp160kd", ABP160KD }, + { "abp2_5bd", ABP250KD }, { "abp250kd", ABP250KD }, + { "abp004bd", ABP400KD }, { "abp400kd", ABP400KD }, + /* psi variants */ + /* gage: */ + { "abp001pg", ABP001PG }, + { "abp005pg", ABP005PG }, + { "abp015pg", ABP015PG }, + { "abp030pg", ABP030PG }, + { "abp060pg", ABP060PG }, + { "abp100pg", ABP100PG }, + { "abp150pg", ABP150PG }, + /* differential: */ + { "abp001pd", ABP001PD }, + { "abp005pd", ABP005PD }, + { "abp015pd", ABP015PD }, + { "abp030pd", ABP030PD }, + { "abp060pd", ABP060PD }, + { /* empty */ }, +}; +MODULE_DEVICE_TABLE(i2c, abp060mg_id_table); + +static struct i2c_driver abp060mg_driver = { + .driver = { + .name = "abp060mg", + }, + .probe = abp060mg_probe, + .id_table = abp060mg_id_table, +}; +module_i2c_driver(abp060mg_driver); + +MODULE_AUTHOR("Marcin Malagowski "); +MODULE_DESCRIPTION("Honeywell ABP pressure sensor driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 1a8f324aa1f2237caef1c6633734785bbdcffeed Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 28 Sep 2016 13:59:49 -0400 Subject: iio: Implement counter channel type and info constants Quadrature encoders, such as rotary encoders and linear encoders, are devices which are capable of encoding the relative position and direction of motion of a shaft. This patch introduces several IIO constants for supporting quadrature encoder counter devices. IIO_COUNT: Current count (main data provided by the counter device) IIO_INDEX: Counter device index value Signed-off-by: William Breathitt Gray Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index fc340ed3dca1..649725bc15c1 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -81,6 +81,8 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_PH] = "ph", [IIO_UVINDEX] = "uvindex", [IIO_ELECTRICALCONDUCTIVITY] = "electricalconductivity", + [IIO_COUNT] = "count", + [IIO_INDEX] = "index", }; static const char * const iio_modifier_names[] = { -- cgit v1.2.3 From 28e5d3bb0325e71ef9b53a9cb4242cdfb55fd8c5 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 28 Sep 2016 14:00:01 -0400 Subject: iio: 104-quad-8: Add IIO support for the ACCES 104-QUAD-8 The ACCES 104-QUAD-8 is a general purpose quadrature encoder counter/interface board. The 104-QUAD-8 is capable of monitoring the outputs of eight encoders via four on-board LSI/CSI LS7266R1 24-bit dual-axis quadrature counter chips. Core functions handled by the LS7266R1, such as direction and total count, are available. Performing a write to a counter's IIO_CHAN_INFO_RAW sets the counter and also clears the counter's respective error flag. Although the counters have a 25-bit range, only the lower 24 bits may be set, either directly or via a counter's preset attribute. Interrupts are not supported by this driver. This driver adds IIO support for the ACCES 104-QUAD-8 and ACCES 104-QUAD-4. The base port addresses for the devices may be configured via the base array module parameter. Signed-off-by: William Breathitt Gray Signed-off-by: Jonathan Cameron --- drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/counter/104-quad-8.c | 593 +++++++++++++++++++++++++++++++++++++++ drivers/iio/counter/Kconfig | 24 ++ drivers/iio/counter/Makefile | 7 + 5 files changed, 626 insertions(+) create mode 100644 drivers/iio/counter/104-quad-8.c create mode 100644 drivers/iio/counter/Kconfig create mode 100644 drivers/iio/counter/Makefile (limited to 'drivers') diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index a31a8cf2c330..a918270d6f54 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -73,6 +73,7 @@ source "drivers/iio/adc/Kconfig" source "drivers/iio/amplifiers/Kconfig" source "drivers/iio/chemical/Kconfig" source "drivers/iio/common/Kconfig" +source "drivers/iio/counter/Kconfig" source "drivers/iio/dac/Kconfig" source "drivers/iio/dummy/Kconfig" source "drivers/iio/frequency/Kconfig" diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 2b6e2762a886..33fa4026f92c 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -18,6 +18,7 @@ obj-y += amplifiers/ obj-y += buffer/ obj-y += chemical/ obj-y += common/ +obj-y += counter/ obj-y += dac/ obj-y += dummy/ obj-y += gyro/ diff --git a/drivers/iio/counter/104-quad-8.c b/drivers/iio/counter/104-quad-8.c new file mode 100644 index 000000000000..2d2ee353dde7 --- /dev/null +++ b/drivers/iio/counter/104-quad-8.c @@ -0,0 +1,593 @@ +/* + * IIO driver for the ACCES 104-QUAD-8 + * Copyright (C) 2016 William Breathitt Gray + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define QUAD8_EXTENT 32 + +static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)]; +static unsigned int num_quad8; +module_param_array(base, uint, &num_quad8, 0); +MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); + +#define QUAD8_NUM_COUNTERS 8 + +/** + * struct quad8_iio - IIO device private data structure + * @preset: array of preset values + * @count_mode: array of count mode configurations + * @quadrature_mode: array of quadrature mode configurations + * @quadrature_scale: array of quadrature mode scale configurations + * @ab_enable: array of A and B inputs enable configurations + * @preset_enable: array of set_to_preset_on_index attribute configurations + * @synchronous_mode: array of index function synchronous mode configurations + * @index_polarity: array of index function polarity configurations + * @base: base port address of the IIO device + */ +struct quad8_iio { + unsigned int preset[QUAD8_NUM_COUNTERS]; + unsigned int count_mode[QUAD8_NUM_COUNTERS]; + unsigned int quadrature_mode[QUAD8_NUM_COUNTERS]; + unsigned int quadrature_scale[QUAD8_NUM_COUNTERS]; + unsigned int ab_enable[QUAD8_NUM_COUNTERS]; + unsigned int preset_enable[QUAD8_NUM_COUNTERS]; + unsigned int synchronous_mode[QUAD8_NUM_COUNTERS]; + unsigned int index_polarity[QUAD8_NUM_COUNTERS]; + unsigned int base; +}; + +static int quad8_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long mask) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel; + unsigned int flags; + unsigned int borrow; + unsigned int carry; + int i; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type == IIO_INDEX) { + *val = !!(inb(priv->base + 0x16) & BIT(chan->channel)); + return IIO_VAL_INT; + } + + flags = inb(base_offset); + borrow = flags & BIT(0); + carry = !!(flags & BIT(1)); + + /* Borrow XOR Carry effectively doubles count range */ + *val = (borrow ^ carry) << 24; + + /* Reset Byte Pointer; transfer Counter to Output Latch */ + outb(0x11, base_offset + 1); + + for (i = 0; i < 3; i++) + *val |= (unsigned int)inb(base_offset) << (8 * i); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_ENABLE: + *val = priv->ab_enable[chan->channel]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 1; + *val2 = priv->quadrature_scale[chan->channel]; + return IIO_VAL_FRACTIONAL_LOG2; + } + + return -EINVAL; +} + +static int quad8_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel; + int i; + unsigned int ior_cfg; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type == IIO_INDEX) + return -EINVAL; + + /* Only 24-bit values are supported */ + if ((unsigned int)val > 0xFFFFFF) + return -EINVAL; + + /* Reset Byte Pointer */ + outb(0x01, base_offset + 1); + + /* Counter can only be set via Preset Register */ + for (i = 0; i < 3; i++) + outb(val >> (8 * i), base_offset); + + /* Transfer Preset Register to Counter */ + outb(0x08, base_offset + 1); + + /* Reset Byte Pointer */ + outb(0x01, base_offset + 1); + + /* Set Preset Register back to original value */ + val = priv->preset[chan->channel]; + for (i = 0; i < 3; i++) + outb(val >> (8 * i), base_offset); + + /* Reset Borrow, Carry, Compare, and Sign flags */ + outb(0x02, base_offset + 1); + /* Reset Error flag */ + outb(0x06, base_offset + 1); + + return 0; + case IIO_CHAN_INFO_ENABLE: + /* only boolean values accepted */ + if (val < 0 || val > 1) + return -EINVAL; + + priv->ab_enable[chan->channel] = val; + + ior_cfg = val | priv->preset_enable[chan->channel] << 1; + + /* Load I/O control configuration */ + outb(0x40 | ior_cfg, base_offset); + + return 0; + case IIO_CHAN_INFO_SCALE: + /* Quadrature scaling only available in quadrature mode */ + if (!priv->quadrature_mode[chan->channel] && (val2 || val != 1)) + return -EINVAL; + + /* Only three gain states (1, 0.5, 0.25) */ + if (val == 1 && !val2) + priv->quadrature_scale[chan->channel] = 0; + else if (!val) + switch (val2) { + case 500000: + priv->quadrature_scale[chan->channel] = 1; + break; + case 250000: + priv->quadrature_scale[chan->channel] = 2; + break; + default: + return -EINVAL; + } + else + return -EINVAL; + + return 0; + } + + return -EINVAL; +} + +static const struct iio_info quad8_info = { + .driver_module = THIS_MODULE, + .read_raw = quad8_read_raw, + .write_raw = quad8_write_raw +}; + +static ssize_t quad8_read_preset(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset[chan->channel]); +} + +static ssize_t quad8_write_preset(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, const char *buf, size_t len) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel; + unsigned int preset; + int ret; + int i; + + ret = kstrtouint(buf, 0, &preset); + if (ret) + return ret; + + /* Only 24-bit values are supported */ + if (preset > 0xFFFFFF) + return -EINVAL; + + priv->preset[chan->channel] = preset; + + /* Reset Byte Pointer */ + outb(0x01, base_offset + 1); + + /* Set Preset Register */ + for (i = 0; i < 3; i++) + outb(preset >> (8 * i), base_offset); + + return len; +} + +static ssize_t quad8_read_set_to_preset_on_index(struct iio_dev *indio_dev, + uintptr_t private, const struct iio_chan_spec *chan, char *buf) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", + priv->preset_enable[chan->channel]); +} + +static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, + uintptr_t private, const struct iio_chan_spec *chan, const char *buf, + size_t len) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel; + bool preset_enable; + int ret; + unsigned int ior_cfg; + + ret = kstrtobool(buf, &preset_enable); + if (ret) + return ret; + + priv->preset_enable[chan->channel] = preset_enable; + + ior_cfg = priv->ab_enable[chan->channel] | + (unsigned int)preset_enable << 1; + + /* Load I/O control configuration to Input / Output Control Register */ + outb(0x40 | ior_cfg, base_offset); + + return len; +} + +static const char *const quad8_noise_error_states[] = { + "No excessive noise is present at the count inputs", + "Excessive noise is present at the count inputs" +}; + +static int quad8_get_noise_error(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel + 1; + + return !!(inb(base_offset) & BIT(4)); +} + +static const struct iio_enum quad8_noise_error_enum = { + .items = quad8_noise_error_states, + .num_items = ARRAY_SIZE(quad8_noise_error_states), + .get = quad8_get_noise_error +}; + +static const char *const quad8_count_direction_states[] = { + "down", + "up" +}; + +static int quad8_get_count_direction(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel + 1; + + return !!(inb(base_offset) & BIT(5)); +} + +static const struct iio_enum quad8_count_direction_enum = { + .items = quad8_count_direction_states, + .num_items = ARRAY_SIZE(quad8_count_direction_states), + .get = quad8_get_count_direction +}; + +static const char *const quad8_count_modes[] = { + "normal", + "range limit", + "non-recycle", + "modulo-n" +}; + +static int quad8_set_count_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, unsigned int count_mode) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + unsigned int mode_cfg = count_mode << 1; + const int base_offset = priv->base + 2 * chan->channel + 1; + + priv->count_mode[chan->channel] = count_mode; + + /* Add quadrature mode configuration */ + if (priv->quadrature_mode[chan->channel]) + mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; + + /* Load mode configuration to Counter Mode Register */ + outb(0x20 | mode_cfg, base_offset); + + return 0; +} + +static int quad8_get_count_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return priv->count_mode[chan->channel]; +} + +static const struct iio_enum quad8_count_mode_enum = { + .items = quad8_count_modes, + .num_items = ARRAY_SIZE(quad8_count_modes), + .set = quad8_set_count_mode, + .get = quad8_get_count_mode +}; + +static const char *const quad8_synchronous_modes[] = { + "non-synchronous", + "synchronous" +}; + +static int quad8_set_synchronous_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, unsigned int synchronous_mode) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const unsigned int idr_cfg = synchronous_mode | + priv->index_polarity[chan->channel] << 1; + const int base_offset = priv->base + 2 * chan->channel + 1; + + /* Index function must be non-synchronous in non-quadrature mode */ + if (synchronous_mode && !priv->quadrature_mode[chan->channel]) + return -EINVAL; + + priv->synchronous_mode[chan->channel] = synchronous_mode; + + /* Load Index Control configuration to Index Control Register */ + outb(0x40 | idr_cfg, base_offset); + + return 0; +} + +static int quad8_get_synchronous_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return priv->synchronous_mode[chan->channel]; +} + +static const struct iio_enum quad8_synchronous_mode_enum = { + .items = quad8_synchronous_modes, + .num_items = ARRAY_SIZE(quad8_synchronous_modes), + .set = quad8_set_synchronous_mode, + .get = quad8_get_synchronous_mode +}; + +static const char *const quad8_quadrature_modes[] = { + "non-quadrature", + "quadrature" +}; + +static int quad8_set_quadrature_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, unsigned int quadrature_mode) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + unsigned int mode_cfg = priv->count_mode[chan->channel] << 1; + const int base_offset = priv->base + 2 * chan->channel + 1; + + if (quadrature_mode) + mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; + else { + /* Quadrature scaling only available in quadrature mode */ + priv->quadrature_scale[chan->channel] = 0; + + /* Synchronous function not supported in non-quadrature mode */ + if (priv->synchronous_mode[chan->channel]) + quad8_set_synchronous_mode(indio_dev, chan, 0); + } + + priv->quadrature_mode[chan->channel] = quadrature_mode; + + /* Load mode configuration to Counter Mode Register */ + outb(0x20 | mode_cfg, base_offset); + + return 0; +} + +static int quad8_get_quadrature_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return priv->quadrature_mode[chan->channel]; +} + +static const struct iio_enum quad8_quadrature_mode_enum = { + .items = quad8_quadrature_modes, + .num_items = ARRAY_SIZE(quad8_quadrature_modes), + .set = quad8_set_quadrature_mode, + .get = quad8_get_quadrature_mode +}; + +static const char *const quad8_index_polarity_modes[] = { + "negative", + "positive" +}; + +static int quad8_set_index_polarity(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, unsigned int index_polarity) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const unsigned int idr_cfg = priv->synchronous_mode[chan->channel] | + index_polarity << 1; + const int base_offset = priv->base + 2 * chan->channel + 1; + + priv->index_polarity[chan->channel] = index_polarity; + + /* Load Index Control configuration to Index Control Register */ + outb(0x40 | idr_cfg, base_offset); + + return 0; +} + +static int quad8_get_index_polarity(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return priv->index_polarity[chan->channel]; +} + +static const struct iio_enum quad8_index_polarity_enum = { + .items = quad8_index_polarity_modes, + .num_items = ARRAY_SIZE(quad8_index_polarity_modes), + .set = quad8_set_index_polarity, + .get = quad8_get_index_polarity +}; + +static const struct iio_chan_spec_ext_info quad8_count_ext_info[] = { + { + .name = "preset", + .shared = IIO_SEPARATE, + .read = quad8_read_preset, + .write = quad8_write_preset + }, + { + .name = "set_to_preset_on_index", + .shared = IIO_SEPARATE, + .read = quad8_read_set_to_preset_on_index, + .write = quad8_write_set_to_preset_on_index + }, + IIO_ENUM("noise_error", IIO_SEPARATE, &quad8_noise_error_enum), + IIO_ENUM_AVAILABLE("noise_error", &quad8_noise_error_enum), + IIO_ENUM("count_direction", IIO_SEPARATE, &quad8_count_direction_enum), + IIO_ENUM_AVAILABLE("count_direction", &quad8_count_direction_enum), + IIO_ENUM("count_mode", IIO_SEPARATE, &quad8_count_mode_enum), + IIO_ENUM_AVAILABLE("count_mode", &quad8_count_mode_enum), + IIO_ENUM("quadrature_mode", IIO_SEPARATE, &quad8_quadrature_mode_enum), + IIO_ENUM_AVAILABLE("quadrature_mode", &quad8_quadrature_mode_enum), + {} +}; + +static const struct iio_chan_spec_ext_info quad8_index_ext_info[] = { + IIO_ENUM("synchronous_mode", IIO_SEPARATE, + &quad8_synchronous_mode_enum), + IIO_ENUM_AVAILABLE("synchronous_mode", &quad8_synchronous_mode_enum), + IIO_ENUM("index_polarity", IIO_SEPARATE, &quad8_index_polarity_enum), + IIO_ENUM_AVAILABLE("index_polarity", &quad8_index_polarity_enum), + {} +}; + +#define QUAD8_COUNT_CHAN(_chan) { \ + .type = IIO_COUNT, \ + .channel = (_chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), \ + .ext_info = quad8_count_ext_info, \ + .indexed = 1 \ +} + +#define QUAD8_INDEX_CHAN(_chan) { \ + .type = IIO_INDEX, \ + .channel = (_chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .ext_info = quad8_index_ext_info, \ + .indexed = 1 \ +} + +static const struct iio_chan_spec quad8_channels[] = { + QUAD8_COUNT_CHAN(0), QUAD8_INDEX_CHAN(0), + QUAD8_COUNT_CHAN(1), QUAD8_INDEX_CHAN(1), + QUAD8_COUNT_CHAN(2), QUAD8_INDEX_CHAN(2), + QUAD8_COUNT_CHAN(3), QUAD8_INDEX_CHAN(3), + QUAD8_COUNT_CHAN(4), QUAD8_INDEX_CHAN(4), + QUAD8_COUNT_CHAN(5), QUAD8_INDEX_CHAN(5), + QUAD8_COUNT_CHAN(6), QUAD8_INDEX_CHAN(6), + QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7) +}; + +static int quad8_probe(struct device *dev, unsigned int id) +{ + struct iio_dev *indio_dev; + struct quad8_iio *priv; + int i, j; + unsigned int base_offset; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + if (!devm_request_region(dev, base[id], QUAD8_EXTENT, + dev_name(dev))) { + dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", + base[id], base[id] + QUAD8_EXTENT); + return -EBUSY; + } + + indio_dev->info = &quad8_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->num_channels = ARRAY_SIZE(quad8_channels); + indio_dev->channels = quad8_channels; + indio_dev->name = dev_name(dev); + + priv = iio_priv(indio_dev); + priv->base = base[id]; + + /* Reset all counters and disable interrupt function */ + outb(0x01, base[id] + 0x11); + /* Set initial configuration for all counters */ + for (i = 0; i < QUAD8_NUM_COUNTERS; i++) { + base_offset = base[id] + 2 * i; + /* Reset Byte Pointer */ + outb(0x01, base_offset + 1); + /* Reset Preset Register */ + for (j = 0; j < 3; j++) + outb(0x00, base_offset); + /* Reset Borrow, Carry, Compare, and Sign flags */ + outb(0x04, base_offset + 1); + /* Reset Error flag */ + outb(0x06, base_offset + 1); + /* Binary encoding; Normal count; non-quadrature mode */ + outb(0x20, base_offset + 1); + /* Disable A and B inputs; preset on index; FLG1 as Carry */ + outb(0x40, base_offset + 1); + /* Disable index function; negative index polarity */ + outb(0x60, base_offset + 1); + } + /* Enable all counters */ + outb(0x00, base[id] + 0x11); + + return devm_iio_device_register(dev, indio_dev); +} + +static struct isa_driver quad8_driver = { + .probe = quad8_probe, + .driver = { + .name = "104-quad-8" + } +}; + +module_isa_driver(quad8_driver, num_quad8); + +MODULE_AUTHOR("William Breathitt Gray "); +MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/counter/Kconfig b/drivers/iio/counter/Kconfig new file mode 100644 index 000000000000..44627f6e4861 --- /dev/null +++ b/drivers/iio/counter/Kconfig @@ -0,0 +1,24 @@ +# +# Counter devices +# +# When adding new entries keep the list in alphabetical order + +menu "Counters" + +config 104_QUAD_8 + tristate "ACCES 104-QUAD-8 driver" + depends on X86 && ISA_BUS_API + help + Say yes here to build support for the ACCES 104-QUAD-8 quadrature + encoder counter/interface device family (104-QUAD-8, 104-QUAD-4). + + Performing a write to a counter's IIO_CHAN_INFO_RAW sets the counter and + also clears the counter's respective error flag. Although the counters + have a 25-bit range, only the lower 24 bits may be set, either directly + or via a counter's preset attribute. Interrupts are not supported by + this driver. + + The base port addresses for the devices may be configured via the base + array module parameter. + +endmenu diff --git a/drivers/iio/counter/Makefile b/drivers/iio/counter/Makefile new file mode 100644 index 000000000000..007e88411648 --- /dev/null +++ b/drivers/iio/counter/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for IIO counter devices +# + +# When adding new entries keep the list in alphabetical order + +obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o -- cgit v1.2.3 From 6d01a4d3fbd1082b3de976531699953e30f39a15 Mon Sep 17 00:00:00 2001 From: Anchal Jain Date: Mon, 3 Oct 2016 18:38:28 +0530 Subject: staging: iio: cdc: ad7152: Add blank line after declarations to increase readability Add a blank line after the function to increase the readability of the code. Signed-off-by: Anchal Jain Signed-off-by: Jonathan Cameron --- drivers/staging/iio/cdc/ad7152.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c index 485d0a5af53c..928f70085bd1 100644 --- a/drivers/staging/iio/cdc/ad7152.c +++ b/drivers/staging/iio/cdc/ad7152.c @@ -134,6 +134,7 @@ static inline ssize_t ad7152_start_calib(struct device *dev, mutex_unlock(&indio_dev->mlock); return len; } + static ssize_t ad7152_start_offset_calib(struct device *dev, struct device_attribute *attr, const char *buf, @@ -142,6 +143,7 @@ static ssize_t ad7152_start_offset_calib(struct device *dev, return ad7152_start_calib(dev, attr, buf, len, AD7152_CONF_MODE_OFFS_CAL); } + static ssize_t ad7152_start_gain_calib(struct device *dev, struct device_attribute *attr, const char *buf, @@ -317,6 +319,7 @@ out: mutex_unlock(&indio_dev->mlock); return ret; } + static int ad7152_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, @@ -470,6 +473,7 @@ static const struct iio_chan_spec ad7152_channels[] = { BIT(IIO_CHAN_INFO_SCALE), } }; + /* * device probe and remove */ -- cgit v1.2.3 From e0e1bec8550114b0571f3867bb355f79b464b1d4 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sun, 2 Oct 2016 00:45:12 +0530 Subject: Staging: iio: ad7280a: constify attribute_group structures Check for attribute_group structures that are only stored in the event_attrs filed of iio_info structure. As the event_attrs field of iio_info structures is constant, so these attribute_group structures can also be declared constant. Done using coccinelle: @r1 disable optional_qualifier @ identifier i; position p; @@ static struct attribute_group i@p = {...}; @ok1@ identifier r1.i; position p; struct iio_info x; @@ x.event_attrs=&i@p; @bad@ position p!={r1.p,ok1.p}; identifier r1.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r1.i; @@ static +const struct attribute_group i={...}; @depends on !bad disable optional_qualifier@ identifier r1.i; @@ +const struct attribute_group i; File size before: text data bss dec hex filename 6271 672 776 7719 1e27 drivers/staging/iio/adc/ad7280a.o File size after: text data bss dec hex filename 6335 608 776 7719 1e27 drivers/staging/iio/adc/ad7280a.o Signed-off-by: Bhumika Goyal Acked-by: Julia Lawall Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7280a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index b460dda7eb65..ee679ac0368f 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -777,7 +777,7 @@ static struct attribute *ad7280_event_attributes[] = { NULL, }; -static struct attribute_group ad7280_event_attrs_group = { +static const struct attribute_group ad7280_event_attrs_group = { .attrs = ad7280_event_attributes, }; -- cgit v1.2.3 From 0fa90023f23ced839cde3bcc0be4e06b3fc34895 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sun, 2 Oct 2016 00:45:13 +0530 Subject: Staging: iio: ad7816: constify attribute_group structures Check for attribute_group structures that are only stored in the event_attrs filed of iio_info structure. As the event_attrs field of iio_info structures is constant, so these attribute_group structures can also be declared constant. Done using coccinelle: @r1 disable optional_qualifier @ identifier i; position p; @@ static struct attribute_group i@p = {...}; @ok1@ identifier r1.i; position p; struct iio_info x; @@ x.event_attrs=&i@p; @bad@ position p!={r1.p,ok1.p}; identifier r1.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r1.i; @@ static +const struct attribute_group i={...}; @depends on !bad disable optional_qualifier@ identifier r1.i; @@ +const struct attribute_group i; File size before: text data bss dec hex filename 3295 768 0 4063 fdf drivers/staging/iio/adc/ad7816.o File size after: text data bss dec hex filename 3359 736 0 4095 fff drivers/staging/iio/adc/ad7816.o Signed-off-by: Bhumika Goyal Acked-by: Julia Lawall Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7816.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index 5e8115b01011..72551f827382 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -327,7 +327,7 @@ static struct attribute *ad7816_event_attributes[] = { NULL, }; -static struct attribute_group ad7816_event_attribute_group = { +static const struct attribute_group ad7816_event_attribute_group = { .attrs = ad7816_event_attributes, .name = "events", }; -- cgit v1.2.3 From f0c816161c6b66aced601b7f245e10b65d7efe67 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sun, 2 Oct 2016 00:45:14 +0530 Subject: Staging: iio: addac: constify attribute_group structures Check for attribute_group structures that are only stored in the event_attrs filed of iio_info structure. As the event_attrs field of iio_info structures is constant, so these attribute_group structures can also be declared constant. Done using coccinelle: @r1 disable optional_qualifier @ identifier i; position p; @@ static struct attribute_group i@p = {...}; @ok1@ identifier r1.i; position p; struct iio_info x; @@ x.event_attrs=&i@p; @bad@ position p!={r1.p,ok1.p}; identifier r1.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r1.i; @@ static +const struct attribute_group i={...}; @depends on !bad disable optional_qualifier@ identifier r1.i; @@ +const struct attribute_group i; File size before: text data bss dec hex filename 11013 6096 0 17109 42d5 drivers/staging/iio/addac/adt7316.o File size after: text data bss dec hex filename 11141 5968 0 17109 42d5 drivers/staging/iio/addac/adt7316.o Signed-off-by: Bhumika Goyal Acked-by: Julia Lawall Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 3faffe59c933..a7d90c8bac5e 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -2039,7 +2039,7 @@ static struct attribute *adt7316_event_attributes[] = { NULL, }; -static struct attribute_group adt7316_event_attribute_group = { +static const struct attribute_group adt7316_event_attribute_group = { .attrs = adt7316_event_attributes, .name = "events", }; @@ -2060,7 +2060,7 @@ static struct attribute *adt7516_event_attributes[] = { NULL, }; -static struct attribute_group adt7516_event_attribute_group = { +static const struct attribute_group adt7516_event_attribute_group = { .attrs = adt7516_event_attributes, .name = "events", }; -- cgit v1.2.3 From 23123cd8d3384e4f1df4aae0a6a6220347dd0765 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sun, 2 Oct 2016 00:45:15 +0530 Subject: Staging: iio: ad7150: constify attribute_group structures Check for attribute_group structures that are only stored in the event_attrs filed of iio_info structure. As the event_attrs field of iio_info structures is constant, so these attribute_group structures can also be declared constant. Done using coccinelle: @r1 disable optional_qualifier @ identifier i; position p; @@ static struct attribute_group i@p = {...}; @ok1@ identifier r1.i; position p; struct iio_info x; @@ x.event_attrs=&i@p; @bad@ position p!={r1.p,ok1.p}; identifier r1.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r1.i; @@ static +const struct attribute_group i={...}; @depends on !bad disable optional_qualifier@ identifier r1.i; @@ +const struct attribute_group i; File size before: text data bss dec hex filename 3561 1152 8 4721 1271 drivers/staging/iio/cdc/ad7150.o File size after: text data bss dec hex filename 3625 1088 8 4721 1271 drivers/staging/iio/cdc/ad7150.o Signed-off-by: Bhumika Goyal Acked-by: Julia Lawall Signed-off-by: Jonathan Cameron --- drivers/staging/iio/cdc/ad7150.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c index 5578a077fcfb..6998c3ddfb6a 100644 --- a/drivers/staging/iio/cdc/ad7150.c +++ b/drivers/staging/iio/cdc/ad7150.c @@ -562,7 +562,7 @@ static struct attribute *ad7150_event_attributes[] = { NULL, }; -static struct attribute_group ad7150_event_attribute_group = { +static const struct attribute_group ad7150_event_attribute_group = { .attrs = ad7150_event_attributes, .name = "events", }; -- cgit v1.2.3 From 7f709dcda46105f617329630d97f5c97cea5b068 Mon Sep 17 00:00:00 2001 From: Ico Doornekamp Date: Sat, 1 Oct 2016 19:30:14 +0200 Subject: iio: magnetometer: ak8974: small endianness fixes Fixes two cases of 'cast to restricted __le16' as reported by sparse. Signed-off-by: Ico Doornekamp Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8974.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 217353145676..ce09d771c1fb 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -287,7 +287,7 @@ static int ak8974_await_drdy(struct ak8974 *ak8974) return 0; } -static int ak8974_getresult(struct ak8974 *ak8974, s16 *result) +static int ak8974_getresult(struct ak8974 *ak8974, __le16 *result) { unsigned int src; int ret; @@ -395,7 +395,7 @@ static int ak8974_selftest(struct ak8974 *ak8974) static int ak8974_get_u16_val(struct ak8974 *ak8974, u8 reg, u16 *val) { int ret; - u16 bulk; + __le16 bulk; ret = regmap_bulk_read(ak8974->map, reg, &bulk, 2); if (ret) @@ -453,7 +453,7 @@ static int ak8974_read_raw(struct iio_dev *indio_dev, long mask) { struct ak8974 *ak8974 = iio_priv(indio_dev); - s16 hw_values[3]; + __le16 hw_values[3]; int ret = -EINVAL; pm_runtime_get_sync(&ak8974->i2c->dev); @@ -494,7 +494,7 @@ static void ak8974_fill_buffer(struct iio_dev *indio_dev) { struct ak8974 *ak8974 = iio_priv(indio_dev); int ret; - s16 hw_values[8]; /* Three axes + 64bit padding */ + __le16 hw_values[8]; /* Three axes + 64bit padding */ pm_runtime_get_sync(&ak8974->i2c->dev); mutex_lock(&ak8974->lock); -- cgit v1.2.3 From b321a38d2407c7e425c54bc09be909a34e49f740 Mon Sep 17 00:00:00 2001 From: Eva Rachel Retuya Date: Sun, 9 Oct 2016 00:05:39 +0800 Subject: staging: iio: ad7606: fix improper setting of oversampling pins The oversampling ratio is controlled using the oversampling pins, OS [2:0] with OS2 being the MSB control bit, and OS0 the LSB control bit. The gpio connected to the OS2 pin is not being set correctly, only OS0 and OS1 pins are being set. Fix the typo to allow proper control of the oversampling pins. Signed-off-by: Eva Rachel Retuya Fixes: b9618c0 ("staging: IIO: ADC: New driver for AD7606/AD7606-6/AD7606-4") Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index f79ee61851f6..cbd6bc52050f 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -189,7 +189,7 @@ static ssize_t ad7606_store_oversampling_ratio(struct device *dev, mutex_lock(&indio_dev->mlock); gpio_set_value(st->pdata->gpio_os0, (ret >> 0) & 1); gpio_set_value(st->pdata->gpio_os1, (ret >> 1) & 1); - gpio_set_value(st->pdata->gpio_os1, (ret >> 2) & 1); + gpio_set_value(st->pdata->gpio_os2, (ret >> 2) & 1); st->oversampling = lval; mutex_unlock(&indio_dev->mlock); -- cgit v1.2.3 From 4a5936dac5aac2b8a01d861281c0d9fa05251cac Mon Sep 17 00:00:00 2001 From: Eva Rachel Retuya Date: Sun, 9 Oct 2016 00:05:40 +0800 Subject: staging: iio: ad7606: implement IIO_CHAN_INFO_OVERSAMPLING_RATIO This driver predates the availability of IIO_CHAN_INFO_OVERSAMPLING_RATIO attribute wherein usage has some advantages like it can be accessed by in-kernel consumers as well as reduces the code size. Therefore, use IIO_CHAN_INFO_OVERSAMPLING_RATIO to implement the oversampling_ratio attribute instead of using IIO_DEVICE_ATTR() macro. Move code from the functions associated with IIO_DEVICE_ATTR() into the read_raw hook as well as add the write_raw hook with both masks set to IIO_CHAN_INFO_OVERSAMPLING_RATIO. Signed-off-by: Eva Rachel Retuya Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606_core.c | 67 ++++++++++++++++------------------- 1 file changed, 31 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index cbd6bc52050f..204222517a39 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -103,6 +103,9 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, *val = st->range * 2; *val2 = st->chip_info->channels[0].scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = st->oversampling; + return IIO_VAL_INT; } return -EINVAL; } @@ -145,16 +148,6 @@ static IIO_DEVICE_ATTR(in_voltage_range, S_IRUGO | S_IWUSR, ad7606_show_range, ad7606_store_range, 0); static IIO_CONST_ATTR(in_voltage_range_available, "5000 10000"); -static ssize_t ad7606_show_oversampling_ratio(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7606_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%u\n", st->oversampling); -} - static int ad7606_oversampling_get_index(unsigned int val) { unsigned char supported[] = {0, 2, 4, 8, 16, 32, 64}; @@ -167,44 +160,43 @@ static int ad7606_oversampling_get_index(unsigned int val) return -EINVAL; } -static ssize_t ad7606_store_oversampling_ratio(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int ad7606_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7606_state *st = iio_priv(indio_dev); - unsigned long lval; int ret; - ret = kstrtoul(buf, 10, &lval); - if (ret) - return ret; + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + if (val2) + return -EINVAL; + ret = ad7606_oversampling_get_index(val); + if (ret < 0) { + dev_err(st->dev, "oversampling %d is not supported\n", + val); + return ret; + } - ret = ad7606_oversampling_get_index(lval); - if (ret < 0) { - dev_err(dev, "oversampling %lu is not supported\n", lval); - return ret; + mutex_lock(&indio_dev->mlock); + gpio_set_value(st->pdata->gpio_os0, (ret >> 0) & 1); + gpio_set_value(st->pdata->gpio_os1, (ret >> 1) & 1); + gpio_set_value(st->pdata->gpio_os2, (ret >> 2) & 1); + st->oversampling = val; + mutex_unlock(&indio_dev->mlock); + return 0; + default: + return -EINVAL; } - - mutex_lock(&indio_dev->mlock); - gpio_set_value(st->pdata->gpio_os0, (ret >> 0) & 1); - gpio_set_value(st->pdata->gpio_os1, (ret >> 1) & 1); - gpio_set_value(st->pdata->gpio_os2, (ret >> 2) & 1); - st->oversampling = lval; - mutex_unlock(&indio_dev->mlock); - - return count; } -static IIO_DEVICE_ATTR(oversampling_ratio, S_IRUGO | S_IWUSR, - ad7606_show_oversampling_ratio, - ad7606_store_oversampling_ratio, 0); static IIO_CONST_ATTR(oversampling_ratio_available, "0 2 4 8 16 32 64"); static struct attribute *ad7606_attributes_os_and_range[] = { &iio_dev_attr_in_voltage_range.dev_attr.attr, &iio_const_attr_in_voltage_range_available.dev_attr.attr, - &iio_dev_attr_oversampling_ratio.dev_attr.attr, &iio_const_attr_oversampling_ratio_available.dev_attr.attr, NULL, }; @@ -214,7 +206,6 @@ static const struct attribute_group ad7606_attribute_group_os_and_range = { }; static struct attribute *ad7606_attributes_os[] = { - &iio_dev_attr_oversampling_ratio.dev_attr.attr, &iio_const_attr_oversampling_ratio_available.dev_attr.attr, NULL, }; @@ -241,6 +232,8 @@ static const struct attribute_group ad7606_attribute_group_range = { .address = num, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ + .info_mask_shared_by_all = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .scan_index = num, \ .scan_type = { \ .sign = 's', \ @@ -429,12 +422,14 @@ static const struct iio_info ad7606_info_no_os_or_range = { static const struct iio_info ad7606_info_os_and_range = { .driver_module = THIS_MODULE, .read_raw = &ad7606_read_raw, + .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_os_and_range, }; static const struct iio_info ad7606_info_os = { .driver_module = THIS_MODULE, .read_raw = &ad7606_read_raw, + .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_os, }; -- cgit v1.2.3 From 569906e2032ebbdd56e820ba60368cd803234cec Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 Oct 2016 14:34:24 +0200 Subject: iio: accel: Add driver for dmard10 3-axis Accelerometer Add a driver for the Domintech ARD10 3-axis Accelerometer, based on the android driver found here: https://github.com/domintech/dmard10 Signed-off-by: Hans de Goede Acked-by: Rob Herring Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 10 ++ drivers/iio/accel/Makefile | 1 + drivers/iio/accel/dmard10.c | 266 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 drivers/iio/accel/dmard10.c (limited to 'drivers') diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 2b791fe1e2bc..d59cfe7d4e5b 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -73,6 +73,16 @@ config DMARD09 Choosing M will build the driver as a module. If so, the module will be called dmard09. +config DMARD10 + tristate "Domintech DMARD10 3-axis Accelerometer Driver" + depends on I2C + help + Say yes here to get support for the Domintech DMARD10 3-axis + accelerometer. + + Choosing M will build the driver as a module. If so, the module + will be called dmard10. + config HID_SENSOR_ACCEL_3D depends on HID_SENSOR_HUB select IIO_BUFFER diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index f5d3ddee619e..cb0e04b2dcb6 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o obj-$(CONFIG_DMARD06) += dmard06.o obj-$(CONFIG_DMARD09) += dmard09.o +obj-$(CONFIG_DMARD10) += dmard10.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXSD9) += kxsd9.o diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c new file mode 100644 index 000000000000..b8736cc75656 --- /dev/null +++ b/drivers/iio/accel/dmard10.c @@ -0,0 +1,266 @@ +/** + * IIO driver for the 3-axis accelerometer Domintech ARD10. + * + * Copyright (c) 2016 Hans de Goede + * Copyright (c) 2012 Domintech Technology Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#define DMARD10_REG_ACTR 0x00 +#define DMARD10_REG_AFEM 0x0c +#define DMARD10_REG_STADR 0x12 +#define DMARD10_REG_STAINT 0x1c +#define DMARD10_REG_MISC2 0x1f +#define DMARD10_REG_PD 0x21 + +#define DMARD10_MODE_OFF 0x00 +#define DMARD10_MODE_STANDBY 0x02 +#define DMARD10_MODE_ACTIVE 0x06 +#define DMARD10_MODE_READ_OTP 0x12 +#define DMARD10_MODE_RESET_DATA_PATH 0x82 + +/* AFEN set 1, ATM[2:0]=b'000 (normal), EN_Z/Y/X/T=1 */ +#define DMARD10_VALUE_AFEM_AFEN_NORMAL 0x8f +/* ODR[3:0]=b'0111 (100Hz), CCK[3:0]=b'0100 (204.8kHZ) */ +#define DMARD10_VALUE_CKSEL_ODR_100_204 0x74 +/* INTC[6:5]=b'00 */ +#define DMARD10_VALUE_INTC 0x00 +/* TAP1/TAP2 Average 2 */ +#define DMARD10_VALUE_TAPNS_AVE_2 0x11 + +#define DMARD10_VALUE_STADR 0x55 +#define DMARD10_VALUE_STAINT 0xaa +#define DMARD10_VALUE_MISC2_OSCA_EN 0x08 +#define DMARD10_VALUE_PD_RST 0x52 + +/* Offsets into the buffer read in dmard10_read_raw() */ +#define DMARD10_X_OFFSET 1 +#define DMARD10_Y_OFFSET 2 +#define DMARD10_Z_OFFSET 3 + +/* + * a value of + or -128 corresponds to + or - 1G + * scale = 9.81 / 128 = 0.076640625 + */ + +static const int dmard10_nscale = 76640625; + +#define DMARD10_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec dmard10_channels[] = { + DMARD10_CHANNEL(DMARD10_X_OFFSET, X), + DMARD10_CHANNEL(DMARD10_Y_OFFSET, Y), + DMARD10_CHANNEL(DMARD10_Z_OFFSET, Z), +}; + +struct dmard10_data { + struct i2c_client *client; +}; + +/* Init sequence taken from the android driver */ +static int dmard10_reset(struct i2c_client *client) +{ + unsigned char buffer[7]; + int ret; + + /* 1. Powerdown reset */ + ret = i2c_smbus_write_byte_data(client, DMARD10_REG_PD, + DMARD10_VALUE_PD_RST); + if (ret < 0) + return ret; + + /* + * 2. ACTR => Standby mode => Download OTP to parameter reg => + * Standby mode => Reset data path => Standby mode + */ + buffer[0] = DMARD10_REG_ACTR; + buffer[1] = DMARD10_MODE_STANDBY; + buffer[2] = DMARD10_MODE_READ_OTP; + buffer[3] = DMARD10_MODE_STANDBY; + buffer[4] = DMARD10_MODE_RESET_DATA_PATH; + buffer[5] = DMARD10_MODE_STANDBY; + ret = i2c_master_send(client, buffer, 6); + if (ret < 0) + return ret; + + /* 3. OSCA_EN = 1, TSTO = b'000 (INT1 = normal, TEST0 = normal) */ + ret = i2c_smbus_write_byte_data(client, DMARD10_REG_MISC2, + DMARD10_VALUE_MISC2_OSCA_EN); + if (ret < 0) + return ret; + + /* 4. AFEN = 1 (AFE will powerdown after ADC) */ + buffer[0] = DMARD10_REG_AFEM; + buffer[1] = DMARD10_VALUE_AFEM_AFEN_NORMAL; + buffer[2] = DMARD10_VALUE_CKSEL_ODR_100_204; + buffer[3] = DMARD10_VALUE_INTC; + buffer[4] = DMARD10_VALUE_TAPNS_AVE_2; + buffer[5] = 0x00; /* DLYC, no delay timing */ + buffer[6] = 0x07; /* INTD=1 push-pull, INTA=1 active high, AUTOT=1 */ + ret = i2c_master_send(client, buffer, 7); + if (ret < 0) + return ret; + + /* 5. Activation mode */ + ret = i2c_smbus_write_byte_data(client, DMARD10_REG_ACTR, + DMARD10_MODE_ACTIVE); + if (ret < 0) + return ret; + + return 0; +} + +/* Shutdown sequence taken from the android driver */ +static int dmard10_shutdown(struct i2c_client *client) +{ + unsigned char buffer[3]; + + buffer[0] = DMARD10_REG_ACTR; + buffer[1] = DMARD10_MODE_STANDBY; + buffer[2] = DMARD10_MODE_OFF; + + return i2c_master_send(client, buffer, 3); +} + +static int dmard10_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct dmard10_data *data = iio_priv(indio_dev); + __le16 buf[4]; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* + * Read 8 bytes starting at the REG_STADR register, trying to + * read the individual X, Y, Z registers will always read 0. + */ + ret = i2c_smbus_read_i2c_block_data(data->client, + DMARD10_REG_STADR, + sizeof(buf), (u8 *)buf); + if (ret < 0) + return ret; + ret = le16_to_cpu(buf[chan->address]); + *val = sign_extend32(ret, 12); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = dmard10_nscale; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static const struct iio_info dmard10_info = { + .driver_module = THIS_MODULE, + .read_raw = dmard10_read_raw, +}; + +static int dmard10_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct iio_dev *indio_dev; + struct dmard10_data *data; + + /* These 2 registers have special POR reset values used for id */ + ret = i2c_smbus_read_byte_data(client, DMARD10_REG_STADR); + if (ret != DMARD10_VALUE_STADR) + return (ret < 0) ? ret : -ENODEV; + + ret = i2c_smbus_read_byte_data(client, DMARD10_REG_STAINT); + if (ret != DMARD10_VALUE_STAINT) + return (ret < 0) ? ret : -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) { + dev_err(&client->dev, "iio allocation failed!\n"); + return -ENOMEM; + } + + data = iio_priv(indio_dev); + data->client = client; + i2c_set_clientdata(client, indio_dev); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &dmard10_info; + indio_dev->name = "dmard10"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = dmard10_channels; + indio_dev->num_channels = ARRAY_SIZE(dmard10_channels); + + ret = dmard10_reset(client); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "device_register failed\n"); + dmard10_shutdown(client); + } + + return ret; +} + +static int dmard10_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + + return dmard10_shutdown(client); +} + +#ifdef CONFIG_PM_SLEEP +static int dmard10_suspend(struct device *dev) +{ + return dmard10_shutdown(to_i2c_client(dev)); +} + +static int dmard10_resume(struct device *dev) +{ + return dmard10_reset(to_i2c_client(dev)); +} +#endif + +static SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, dmard10_resume); + +static const struct i2c_device_id dmard10_i2c_id[] = { + {"dmard10", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id); + +static struct i2c_driver dmard10_driver = { + .driver = { + .name = "dmard10", + .pm = &dmard10_pm_ops, + }, + .probe = dmard10_probe, + .remove = dmard10_remove, + .id_table = dmard10_i2c_id, +}; + +module_i2c_driver(dmard10_driver); + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("Domintech ARD10 3-Axis Accelerometer driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 598893e9cb64d9c74152db6174c4d7a6036a84e8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 Oct 2016 14:34:25 +0200 Subject: iio: accel: Add driver for the MiraMEMS DA311 3-axis 12-bit digital accelerometer This driver is based on the DA311 Android driver which can be found here: https://git.matricom.net/Firmware/kernel_amlogic_meson-common/tree/1e70113a5befd07debb68f537156def84c5be57a/drivers/amlogic/input/sensor the mir3da_* files are the DA311 driver. Unfortunately there is no datasheet. Signed-off-by: Hans de Goede Acked-by: Rob Herring Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 10 ++ drivers/iio/accel/Makefile | 1 + drivers/iio/accel/da311.c | 305 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 drivers/iio/accel/da311.c (limited to 'drivers') diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index d59cfe7d4e5b..8945e70a797c 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -52,6 +52,16 @@ config BMC150_ACCEL_SPI tristate select REGMAP_SPI +config DA311 + tristate "MiraMEMS DA311 3-axis 12-bit digital accelerometer driver" + depends on I2C + help + Say yes here to build support for the MiraMEMS DA311 3-axis 12-bit + digital accelerometer. + + To compile this driver as a module, choose M here: the + module will be called da311. + config DMARD06 tristate "Domintech DMARD06 Digital Accelerometer Driver" depends on OF || COMPILE_TEST diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index cb0e04b2dcb6..ade13ae5d056 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_BMA220) += bma220_spi.o obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o +obj-$(CONFIG_DA311) += da311.o obj-$(CONFIG_DMARD06) += dmard06.o obj-$(CONFIG_DMARD09) += dmard09.o obj-$(CONFIG_DMARD10) += dmard10.o diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c new file mode 100644 index 000000000000..537cfa8b6edf --- /dev/null +++ b/drivers/iio/accel/da311.c @@ -0,0 +1,305 @@ +/** + * IIO driver for the MiraMEMS DA311 3-axis accelerometer + * + * Copyright (c) 2016 Hans de Goede + * Copyright (c) 2011-2013 MiraMEMS Sensing Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#define DA311_CHIP_ID 0x13 + +/* + * Note register addressed go from 0 - 0x3f and then wrap. + * For some reason there are 2 banks with 0 - 0x3f addresses, + * rather then a single 0-0x7f bank. + */ + +/* Bank 0 regs */ +#define DA311_REG_BANK 0x0000 +#define DA311_REG_LDO_REG 0x0006 +#define DA311_REG_CHIP_ID 0x000f +#define DA311_REG_TEMP_CFG_REG 0x001f +#define DA311_REG_CTRL_REG1 0x0020 +#define DA311_REG_CTRL_REG3 0x0022 +#define DA311_REG_CTRL_REG4 0x0023 +#define DA311_REG_CTRL_REG5 0x0024 +#define DA311_REG_CTRL_REG6 0x0025 +#define DA311_REG_STATUS_REG 0x0027 +#define DA311_REG_OUT_X_L 0x0028 +#define DA311_REG_OUT_X_H 0x0029 +#define DA311_REG_OUT_Y_L 0x002a +#define DA311_REG_OUT_Y_H 0x002b +#define DA311_REG_OUT_Z_L 0x002c +#define DA311_REG_OUT_Z_H 0x002d +#define DA311_REG_INT1_CFG 0x0030 +#define DA311_REG_INT1_SRC 0x0031 +#define DA311_REG_INT1_THS 0x0032 +#define DA311_REG_INT1_DURATION 0x0033 +#define DA311_REG_INT2_CFG 0x0034 +#define DA311_REG_INT2_SRC 0x0035 +#define DA311_REG_INT2_THS 0x0036 +#define DA311_REG_INT2_DURATION 0x0037 +#define DA311_REG_CLICK_CFG 0x0038 +#define DA311_REG_CLICK_SRC 0x0039 +#define DA311_REG_CLICK_THS 0x003a +#define DA311_REG_TIME_LIMIT 0x003b +#define DA311_REG_TIME_LATENCY 0x003c +#define DA311_REG_TIME_WINDOW 0x003d + +/* Bank 1 regs */ +#define DA311_REG_SOFT_RESET 0x0105 +#define DA311_REG_OTP_XOFF_L 0x0110 +#define DA311_REG_OTP_XOFF_H 0x0111 +#define DA311_REG_OTP_YOFF_L 0x0112 +#define DA311_REG_OTP_YOFF_H 0x0113 +#define DA311_REG_OTP_ZOFF_L 0x0114 +#define DA311_REG_OTP_ZOFF_H 0x0115 +#define DA311_REG_OTP_XSO 0x0116 +#define DA311_REG_OTP_YSO 0x0117 +#define DA311_REG_OTP_ZSO 0x0118 +#define DA311_REG_OTP_TRIM_OSC 0x011b +#define DA311_REG_LPF_ABSOLUTE 0x011c +#define DA311_REG_TEMP_OFF1 0x0127 +#define DA311_REG_TEMP_OFF2 0x0128 +#define DA311_REG_TEMP_OFF3 0x0129 +#define DA311_REG_OTP_TRIM_THERM_H 0x011a + +/* + * a value of + or -1024 corresponds to + or - 1G + * scale = 9.81 / 1024 = 0.009580078 + */ + +static const int da311_nscale = 9580078; + +#define DA311_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec da311_channels[] = { + /* | 0x80 comes from the android driver */ + DA311_CHANNEL(DA311_REG_OUT_X_L | 0x80, X), + DA311_CHANNEL(DA311_REG_OUT_Y_L | 0x80, Y), + DA311_CHANNEL(DA311_REG_OUT_Z_L | 0x80, Z), +}; + +struct da311_data { + struct i2c_client *client; +}; + +static int da311_register_mask_write(struct i2c_client *client, u16 addr, + u8 mask, u8 data) +{ + int ret; + u8 tmp_data = 0; + + if (addr & 0xff00) { + /* Select bank 1 */ + ret = i2c_smbus_write_byte_data(client, DA311_REG_BANK, 0x01); + if (ret < 0) + return ret; + } + + if (mask != 0xff) { + ret = i2c_smbus_read_byte_data(client, addr); + if (ret < 0) + return ret; + tmp_data = ret; + } + + tmp_data &= ~mask; + tmp_data |= data & mask; + ret = i2c_smbus_write_byte_data(client, addr & 0xff, tmp_data); + if (ret < 0) + return ret; + + if (addr & 0xff00) { + /* Back to bank 0 */ + ret = i2c_smbus_write_byte_data(client, DA311_REG_BANK, 0x00); + if (ret < 0) + return ret; + } + + return 0; +} + +/* Init sequence taken from the android driver */ +static int da311_reset(struct i2c_client *client) +{ + const struct { + u16 addr; + u8 mask; + u8 data; + } init_data[] = { + { DA311_REG_TEMP_CFG_REG, 0xff, 0x08 }, + { DA311_REG_CTRL_REG5, 0xff, 0x80 }, + { DA311_REG_CTRL_REG4, 0x30, 0x00 }, + { DA311_REG_CTRL_REG1, 0xff, 0x6f }, + { DA311_REG_TEMP_CFG_REG, 0xff, 0x88 }, + { DA311_REG_LDO_REG, 0xff, 0x02 }, + { DA311_REG_OTP_TRIM_OSC, 0xff, 0x27 }, + { DA311_REG_LPF_ABSOLUTE, 0xff, 0x30 }, + { DA311_REG_TEMP_OFF1, 0xff, 0x3f }, + { DA311_REG_TEMP_OFF2, 0xff, 0xff }, + { DA311_REG_TEMP_OFF3, 0xff, 0x0f }, + }; + int i, ret; + + /* Reset */ + ret = da311_register_mask_write(client, DA311_REG_SOFT_RESET, + 0xff, 0xaa); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(init_data); i++) { + ret = da311_register_mask_write(client, + init_data[i].addr, + init_data[i].mask, + init_data[i].data); + if (ret < 0) + return ret; + } + + return 0; +} + +static int da311_enable(struct i2c_client *client, bool enable) +{ + u8 data = enable ? 0x00 : 0x20; + + return da311_register_mask_write(client, DA311_REG_TEMP_CFG_REG, + 0x20, data); +} + +static int da311_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct da311_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = i2c_smbus_read_word_data(data->client, chan->address); + if (ret < 0) + return ret; + /* + * Values are 12 bits, stored as 16 bits with the 4 + * least significant bits always 0. + */ + *val = (short)ret >> 4; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = da311_nscale; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static const struct iio_info da311_info = { + .driver_module = THIS_MODULE, + .read_raw = da311_read_raw, +}; + +static int da311_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct iio_dev *indio_dev; + struct da311_data *data; + + ret = i2c_smbus_read_byte_data(client, DA311_REG_CHIP_ID); + if (ret != DA311_CHIP_ID) + return (ret < 0) ? ret : -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + i2c_set_clientdata(client, indio_dev); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &da311_info; + indio_dev->name = "da311"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = da311_channels; + indio_dev->num_channels = ARRAY_SIZE(da311_channels); + + ret = da311_reset(client); + if (ret < 0) + return ret; + + ret = da311_enable(client, true); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "device_register failed\n"); + da311_enable(client, false); + } + + return ret; +} + +static int da311_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + + return da311_enable(client, false); +} + +#ifdef CONFIG_PM_SLEEP +static int da311_suspend(struct device *dev) +{ + return da311_enable(to_i2c_client(dev), false); +} + +static int da311_resume(struct device *dev) +{ + return da311_enable(to_i2c_client(dev), true); +} +#endif + +static SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume); + +static const struct i2c_device_id da311_i2c_id[] = { + {"da311", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, da311_i2c_id); + +static struct i2c_driver da311_driver = { + .driver = { + .name = "da311", + .pm = &da311_pm_ops, + }, + .probe = da311_probe, + .remove = da311_remove, + .id_table = da311_i2c_id, +}; + +module_i2c_driver(da311_driver); + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("MiraMEMS DA311 3-Axis Accelerometer driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From a13e831fcaa7e8af0387aef629d1835cf39c59f0 Mon Sep 17 00:00:00 2001 From: Eva Rachel Retuya Date: Wed, 5 Oct 2016 11:06:21 +0800 Subject: staging: iio: ad7192: implement IIO_CHAN_INFO_SAMP_FREQ This driver predates the availability of IIO_CHAN_INFO_SAMP_FREQ attribute wherein usage has some advantages like it can be accessed by in-kernel consumers as well as reduces the code size. Therefore, use IIO_CHAN_INFO_SAMP_FREQ to implement the sampling_frequency attribute instead of using IIO_DEV_ATTR_SAMP_FREQ() macro. Move code from the functions associated with IIO_DEV_ATTR_SAMP_FREQ() into respective read and write hooks with the mask set to IIO_CHAN_INFO_SAMP_FREQ. Signed-off-by: Eva Rachel Retuya Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7192.c | 84 ++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index 1cf6b79801a9..bfa12ceb1e1f 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -322,57 +322,6 @@ out: return ret; } -static ssize_t ad7192_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7192_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", st->mclk / - (st->f_order * 1024 * AD7192_MODE_RATE(st->mode))); -} - -static ssize_t ad7192_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7192_state *st = iio_priv(indio_dev); - unsigned long lval; - int div, ret; - - ret = kstrtoul(buf, 10, &lval); - if (ret) - return ret; - if (lval == 0) - return -EINVAL; - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - div = st->mclk / (lval * st->f_order * 1024); - if (div < 1 || div > 1023) { - ret = -EINVAL; - goto out; - } - - st->mode &= ~AD7192_MODE_RATE(-1); - st->mode |= AD7192_MODE_RATE(div); - ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); - -out: - iio_device_release_direct_mode(indio_dev); - - return ret ? ret : len; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - ad7192_read_frequency, - ad7192_write_frequency); - static ssize_t ad7192_show_scale_available(struct device *dev, struct device_attribute *attr, char *buf) @@ -471,7 +420,6 @@ static IIO_DEVICE_ATTR(ac_excitation_en, S_IRUGO | S_IWUSR, AD7192_REG_MODE); static struct attribute *ad7192_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_in_v_m_v_scale_available.dev_attr.attr, &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, &iio_dev_attr_bridge_switch_en.dev_attr.attr, @@ -484,7 +432,6 @@ static const struct attribute_group ad7192_attribute_group = { }; static struct attribute *ad7195_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_in_v_m_v_scale_available.dev_attr.attr, &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, &iio_dev_attr_bridge_switch_en.dev_attr.attr, @@ -536,6 +483,10 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, if (chan->type == IIO_TEMP) *val -= 273 * ad7192_get_temp_scale(unipolar); return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->mclk / + (st->f_order * 1024 * AD7192_MODE_RATE(st->mode)); + return IIO_VAL_INT; } return -EINVAL; @@ -548,7 +499,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, long mask) { struct ad7192_state *st = iio_priv(indio_dev); - int ret, i; + int ret, i, div; unsigned int tmp; ret = iio_device_claim_direct_mode(indio_dev); @@ -572,6 +523,22 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, break; } break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (!val) { + ret = -EINVAL; + break; + } + + div = st->mclk / (val * st->f_order * 1024); + if (div < 1 || div > 1023) { + ret = -EINVAL; + break; + } + + st->mode &= ~AD7192_MODE_RATE(-1); + st->mode |= AD7192_MODE_RATE(div); + ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); + break; default: ret = -EINVAL; } @@ -585,7 +552,14 @@ static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, long mask) { - return IIO_VAL_INT_PLUS_NANO; + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT; + default: + return -EINVAL; + } } static const struct iio_info ad7192_info = { -- cgit v1.2.3 From f225951dbb9d02c80d09cb81b070b3af73a68de9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 Oct 2016 20:15:27 +0200 Subject: iio: accel: Add driver for the MiraMEMS DA280 3-axis 14-bit digital accelerometer Add an iio driver for the MiraMEMS DA280 3-axis 14-bit accelerometer, as well as for the DA226 which is a fully compatible 2-axis version. Datasheets for the DA280 and DA226 can be found at the manufacturers site: http://www.miramems.com/en/products.asp?list=1 Signed-off-by: Hans de Goede Acked-by: Rob Herring Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 10 +++ drivers/iio/accel/Makefile | 1 + drivers/iio/accel/da280.c | 183 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 drivers/iio/accel/da280.c (limited to 'drivers') diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 8945e70a797c..878e3c9449de 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -52,6 +52,16 @@ config BMC150_ACCEL_SPI tristate select REGMAP_SPI +config DA280 + tristate "MiraMEMS DA280 3-axis 14-bit digital accelerometer driver" + depends on I2C + help + Say yes here to build support for the MiraMEMS DA280 3-axis 14-bit + digital accelerometer. + + To compile this driver as a module, choose M here: the + module will be called da280. + config DA311 tristate "MiraMEMS DA311 3-axis 12-bit digital accelerometer driver" depends on I2C diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index ade13ae5d056..0aa574957047 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_BMA220) += bma220_spi.o obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o +obj-$(CONFIG_DA280) += da280.o obj-$(CONFIG_DA311) += da311.o obj-$(CONFIG_DMARD06) += dmard06.o obj-$(CONFIG_DMARD09) += dmard09.o diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c new file mode 100644 index 000000000000..ed8343aeac9c --- /dev/null +++ b/drivers/iio/accel/da280.c @@ -0,0 +1,183 @@ +/** + * IIO driver for the MiraMEMS DA280 3-axis accelerometer and + * IIO driver for the MiraMEMS DA226 2-axis accelerometer + * + * Copyright (c) 2016 Hans de Goede + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#define DA280_REG_CHIP_ID 0x01 +#define DA280_REG_ACC_X_LSB 0x02 +#define DA280_REG_ACC_Y_LSB 0x04 +#define DA280_REG_ACC_Z_LSB 0x06 +#define DA280_REG_MODE_BW 0x11 + +#define DA280_CHIP_ID 0x13 +#define DA280_MODE_ENABLE 0x1e +#define DA280_MODE_DISABLE 0x9e + +enum { da226, da280 }; + +/* + * a value of + or -4096 corresponds to + or - 1G + * scale = 9.81 / 4096 = 0.002395019 + */ + +static const int da280_nscale = 2395019; + +#define DA280_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec da280_channels[] = { + DA280_CHANNEL(DA280_REG_ACC_X_LSB, X), + DA280_CHANNEL(DA280_REG_ACC_Y_LSB, Y), + DA280_CHANNEL(DA280_REG_ACC_Z_LSB, Z), +}; + +struct da280_data { + struct i2c_client *client; +}; + +static int da280_enable(struct i2c_client *client, bool enable) +{ + u8 data = enable ? DA280_MODE_ENABLE : DA280_MODE_DISABLE; + + return i2c_smbus_write_byte_data(client, DA280_REG_MODE_BW, data); +} + +static int da280_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct da280_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = i2c_smbus_read_word_data(data->client, chan->address); + if (ret < 0) + return ret; + /* + * Values are 14 bits, stored as 16 bits with the 2 + * least significant bits always 0. + */ + *val = (short)ret >> 2; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = da280_nscale; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static const struct iio_info da280_info = { + .driver_module = THIS_MODULE, + .read_raw = da280_read_raw, +}; + +static int da280_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct iio_dev *indio_dev; + struct da280_data *data; + + ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID); + if (ret != DA280_CHIP_ID) + return (ret < 0) ? ret : -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + i2c_set_clientdata(client, indio_dev); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &da280_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = da280_channels; + if (id->driver_data == da226) { + indio_dev->name = "da226"; + indio_dev->num_channels = 2; + } else { + indio_dev->name = "da280"; + indio_dev->num_channels = 3; + } + + ret = da280_enable(client, true); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "device_register failed\n"); + da280_enable(client, false); + } + + return ret; +} + +static int da280_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + + return da280_enable(client, false); +} + +#ifdef CONFIG_PM_SLEEP +static int da280_suspend(struct device *dev) +{ + return da280_enable(to_i2c_client(dev), false); +} + +static int da280_resume(struct device *dev) +{ + return da280_enable(to_i2c_client(dev), true); +} +#endif + +static SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume); + +static const struct i2c_device_id da280_i2c_id[] = { + { "da226", da226 }, + { "da280", da280 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, da280_i2c_id); + +static struct i2c_driver da280_driver = { + .driver = { + .name = "da280", + .pm = &da280_pm_ops, + }, + .probe = da280_probe, + .remove = da280_remove, + .id_table = da280_i2c_id, +}; + +module_i2c_driver(da280_driver); + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("MiraMEMS DA280 3-Axis Accelerometer driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 73d2ad96fd9cdb8efff6844368610dcb72dcf7ba Mon Sep 17 00:00:00 2001 From: Sandhya Bankar Date: Tue, 4 Oct 2016 02:29:06 +0530 Subject: Staging: iio: meter: ade7758_core: implement IIO_CHAN_INFO_SAMP_FREQ This driver predates the availability of IIO_CHAN_INFO_SAMP_FREQ attribute wherein usage has some advantages like it can be accessed by in-kernel consumers as well as reduces the code size. Hence moving functionality from IIO_DEV_ATTR_SAMP_FREQ attribute into IIO_CHAN_INFO_SAMP_FREQ handlers. Also Adding ade7758_read_raw() and ade7758_write_raw() to allow reading/writing the element as well. Signed-off-by: Sandhya Bankar Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7758_core.c | 86 +++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index ebb8a1993303..3af8f77b8e41 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -465,38 +465,26 @@ err_ret: return ret; } -static ssize_t ade7758_read_frequency(struct device *dev, - struct device_attribute *attr, char *buf) +static int ade7758_read_samp_freq(struct device *dev, int *val) { int ret; u8 t; - int sps; ret = ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, &t); if (ret) return ret; t = (t >> 5) & 0x3; - sps = 26040 / (1 << t); + *val = 26040 / (1 << t); - return sprintf(buf, "%d SPS\n", sps); + return 0; } -static ssize_t ade7758_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static int ade7758_write_samp_freq(struct device *dev, int val) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - u16 val; int ret; u8 reg, t; - ret = kstrtou16(buf, 10, &val); - if (ret) - return ret; - - mutex_lock(&indio_dev->mlock); - switch (val) { case 26040: t = 0; @@ -525,9 +513,49 @@ static ssize_t ade7758_write_frequency(struct device *dev, ret = ade7758_spi_write_reg_8(dev, ADE7758_WAVMODE, reg); out: - mutex_unlock(&indio_dev->mlock); + return ret; +} - return ret ? ret : len; +static int ade7758_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&indio_dev->mlock); + ret = ade7758_read_samp_freq(&indio_dev->dev, val); + mutex_unlock(&indio_dev->mlock); + return ret; + default: + return -EINVAL; + } + + return ret; +} + +static int ade7758_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) + return -EINVAL; + mutex_lock(&indio_dev->mlock); + ret = ade7758_write_samp_freq(&indio_dev->dev, val); + mutex_unlock(&indio_dev->mlock); + return ret; + default: + return -EINVAL; + } + + return ret; } static IIO_DEV_ATTR_TEMP_RAW(ade7758_read_8bit); @@ -553,17 +581,12 @@ static IIO_DEV_ATTR_BVAHR(ade7758_read_16bit, static IIO_DEV_ATTR_CVAHR(ade7758_read_16bit, ADE7758_CVAHR); -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - ade7758_read_frequency, - ade7758_write_frequency); - static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26040 13020 6510 3255"); static struct attribute *ade7758_attributes[] = { &iio_dev_attr_in_temp_raw.dev_attr.attr, &iio_const_attr_in_temp_offset.dev_attr.attr, &iio_const_attr_in_temp_scale.dev_attr.attr, - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_awatthr.dev_attr.attr, &iio_dev_attr_bwatthr.dev_attr.attr, @@ -611,6 +634,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE), .scan_index = 0, .scan_type = { @@ -622,6 +646,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_CURRENT, .indexed = 1, .channel = 0, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT), .scan_index = 1, .scan_type = { @@ -634,6 +659,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 0, .extend_name = "apparent", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR), .scan_index = 2, .scan_type = { @@ -646,6 +672,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 0, .extend_name = "active", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR), .scan_index = 3, .scan_type = { @@ -658,6 +685,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 0, .extend_name = "reactive", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR), .scan_index = 4, .scan_type = { @@ -669,6 +697,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE), .scan_index = 5, .scan_type = { @@ -680,6 +709,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_CURRENT, .indexed = 1, .channel = 1, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT), .scan_index = 6, .scan_type = { @@ -692,6 +722,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 1, .extend_name = "apparent", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR), .scan_index = 7, .scan_type = { @@ -704,6 +735,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 1, .extend_name = "active", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR), .scan_index = 8, .scan_type = { @@ -716,6 +748,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 1, .extend_name = "reactive", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR), .scan_index = 9, .scan_type = { @@ -727,6 +760,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 2, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE), .scan_index = 10, .scan_type = { @@ -738,6 +772,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_CURRENT, .indexed = 1, .channel = 2, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT), .scan_index = 11, .scan_type = { @@ -750,6 +785,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 2, .extend_name = "apparent", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR), .scan_index = 12, .scan_type = { @@ -762,6 +798,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 2, .extend_name = "active", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR), .scan_index = 13, .scan_type = { @@ -774,6 +811,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 2, .extend_name = "reactive", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR), .scan_index = 14, .scan_type = { @@ -787,6 +825,8 @@ static const struct iio_chan_spec ade7758_channels[] = { static const struct iio_info ade7758_info = { .attrs = &ade7758_attribute_group, + .read_raw = &ade7758_read_raw, + .write_raw = &ade7758_write_raw, .driver_module = THIS_MODULE, }; -- cgit v1.2.3 From e748e2801a70eb0da6dbc2db1407185a2883533d Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 6 Oct 2016 20:48:34 -0400 Subject: staging: iio: isl29018: add documentation about the infrared suppression Add documentation from the ISL29018 Data Sheet (FN6619.4, Oct 8, 2012) about the infrared suppression that can be controlled with the proximity_on_chip_ambient_infrared_suppression sysfs attribute. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 51226bd337c5..52bfb1cbe8e0 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -307,6 +307,24 @@ static ssize_t in_illuminance_integration_time_available_show return len; } +/* + * From ISL29018 Data Sheet (FN6619.4, Oct 8, 2012) regarding the + * infrared suppression: + * + * Proximity Sensing Scheme: Bit 7. This bit programs the function + * of the proximity detection. Logic 0 of this bit, Scheme 0, makes + * full n (4, 8, 12, 16) bits (unsigned) proximity detection. The range + * of Scheme 0 proximity count is from 0 to 2^n. Logic 1 of this bit, + * Scheme 1, makes n-1 (3, 7, 11, 15) bits (2's complementary) + * proximity_less_ambient detection. The range of Scheme 1 + * proximity count is from -2^(n-1) to 2^(n-1) . The sign bit is extended + * for resolutions less than 16. While Scheme 0 has wider dynamic + * range, Scheme 1 proximity detection is less affected by the + * ambient IR noise variation. + * + * 0 Sensing IR from LED and ambient + * 1 Sensing IR from LED with ambient IR rejection + */ static ssize_t proximity_on_chip_ambient_infrared_suppression_show (struct device *dev, struct device_attribute *attr, char *buf) -- cgit v1.2.3 From 6572389bcc1121b4e4112632e289a57a1136989d Mon Sep 17 00:00:00 2001 From: sayli karnik Date: Mon, 10 Oct 2016 21:09:17 +0530 Subject: staging: iio: cdc: ad7152: Implement IIO_CHAN_INFO_SAMP_FREQ attribute Attributes that were once privately defined become standard with time and hence a special global define is used. Hence update driver ad7152 to use IIO_CHAN_INFO_SAMP_FREQ which is a global define instead of IIO_DEV_ATTR_SAMP_FREQ. Move functionality from IIO_DEV_ATTR_SAMP_FREQ attribute into IIO_CHAN_INFO_SAMP_FREQ to implement the sampling_frequency attribute. Modify ad7152_read_raw() and ad7152_write_raw() to allow reading and writing the element as well. Also add a lock in the driver's private data. Signed-off-by: sayli karnik Signed-off-by: Jonathan Cameron --- drivers/staging/iio/cdc/ad7152.c | 118 ++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c index 928f70085bd1..0203c8103750 100644 --- a/drivers/staging/iio/cdc/ad7152.c +++ b/drivers/staging/iio/cdc/ad7152.c @@ -167,63 +167,12 @@ static const unsigned char ad7152_filter_rate_table[][2] = { {200, 5 + 1}, {50, 20 + 1}, {20, 50 + 1}, {17, 60 + 1}, }; -static ssize_t ad7152_show_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7152_chip_info *chip = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", - ad7152_filter_rate_table[chip->filter_rate_setup][0]); -} - -static ssize_t ad7152_store_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7152_chip_info *chip = iio_priv(indio_dev); - u8 data; - int ret, i; - - ret = kstrtou8(buf, 10, &data); - if (ret < 0) - return ret; - - for (i = 0; i < ARRAY_SIZE(ad7152_filter_rate_table); i++) - if (data >= ad7152_filter_rate_table[i][0]) - break; - - if (i >= ARRAY_SIZE(ad7152_filter_rate_table)) - i = ARRAY_SIZE(ad7152_filter_rate_table) - 1; - - mutex_lock(&indio_dev->mlock); - ret = i2c_smbus_write_byte_data(chip->client, - AD7152_REG_CFG2, AD7152_CFG2_OSR(i)); - if (ret < 0) { - mutex_unlock(&indio_dev->mlock); - return ret; - } - - chip->filter_rate_setup = i; - mutex_unlock(&indio_dev->mlock); - - return len; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, - ad7152_show_filter_rate_setup, - ad7152_store_filter_rate_setup); - static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("200 50 20 17"); static IIO_CONST_ATTR(in_capacitance_scale_available, "0.000061050 0.000030525 0.000015263 0.000007631"); static struct attribute *ad7152_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_in_capacitance0_calibbias_calibration.dev_attr.attr, &iio_dev_attr_in_capacitance1_calibbias_calibration.dev_attr.attr, &iio_dev_attr_in_capacitance0_calibscale_calibration.dev_attr.attr, @@ -249,6 +198,51 @@ static const int ad7152_scale_table[] = { 30525, 7631, 15263, 61050 }; +/** + * read_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * + * lock must be held + **/ +static int ad7152_read_raw_samp_freq(struct device *dev, int *val) +{ + struct ad7152_chip_info *chip = iio_priv(dev_to_iio_dev(dev)); + + *val = ad7152_filter_rate_table[chip->filter_rate_setup][0]; + + return 0; +} + +/** + * write_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * + * lock must be held + **/ +static int ad7152_write_raw_samp_freq(struct device *dev, int val) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7152_chip_info *chip = iio_priv(indio_dev); + int ret, i; + + for (i = 0; i < ARRAY_SIZE(ad7152_filter_rate_table); i++) + if (val >= ad7152_filter_rate_table[i][0]) + break; + + if (i >= ARRAY_SIZE(ad7152_filter_rate_table)) + i = ARRAY_SIZE(ad7152_filter_rate_table) - 1; + + mutex_lock(&indio_dev->mlock); + ret = i2c_smbus_write_byte_data(chip->client, + AD7152_REG_CFG2, AD7152_CFG2_OSR(i)); + if (ret < 0) { + mutex_unlock(&indio_dev->mlock); + return ret; + } + + chip->filter_rate_setup = i; + mutex_unlock(&indio_dev->mlock); + + return ret; +} static int ad7152_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, @@ -309,6 +303,17 @@ static int ad7152_write_raw(struct iio_dev *indio_dev, if (ret < 0) goto out; + ret = 0; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) { + ret = -EINVAL; + goto out; + } + ret = ad7152_write_raw_samp_freq(&indio_dev->dev, val); + if (ret < 0) + goto out; + ret = 0; break; default: @@ -406,6 +411,13 @@ static int ad7152_read_raw(struct iio_dev *indio_dev, ret = IIO_VAL_INT_PLUS_NANO; break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = ad7152_read_raw_samp_freq(&indio_dev->dev, val); + if (ret < 0) + goto out; + + ret = IIO_VAL_INT; + break; default: ret = -EINVAL; } @@ -443,6 +455,7 @@ static const struct iio_chan_spec ad7152_channels[] = { BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_CAPACITANCE, .differential = 1, @@ -453,6 +466,7 @@ static const struct iio_chan_spec ad7152_channels[] = { BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_CAPACITANCE, .indexed = 1, @@ -461,6 +475,7 @@ static const struct iio_chan_spec ad7152_channels[] = { BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_CAPACITANCE, .differential = 1, @@ -471,6 +486,7 @@ static const struct iio_chan_spec ad7152_channels[] = { BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), } }; -- cgit v1.2.3 From 2296c0623eb741d4985b4fbd5c2c8e48a2795d2a Mon Sep 17 00:00:00 2001 From: Eva Rachel Retuya Date: Mon, 10 Oct 2016 18:01:31 +0800 Subject: staging: iio: cdc: ad7746: implement IIO_CHAN_INFO_SAMP_FREQ This driver predates the availability of IIO_CHAN_INFO_SAMP_FREQ attribute wherein usage has some advantages like it can be accessed by in-kernel consumers as well as reduces the code size. Therefore, use IIO_CHAN_INFO_SAMP_FREQ to implement the sampling_frequency attribute instead of using IIO_DEVICE_ATTR() macro. Move code from the functions associated with IIO_DEVICE_ATTR() into respective read and write hooks with the mask set to IIO_CHAN_INFO_SAMP_FREQ. Signed-off-by: Eva Rachel Retuya Signed-off-by: Jonathan Cameron --- drivers/staging/iio/cdc/ad7746.c | 120 ++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c index 5771d4ee8ef1..f41251ceeacd 100644 --- a/drivers/staging/iio/cdc/ad7746.c +++ b/drivers/staging/iio/cdc/ad7746.c @@ -122,7 +122,8 @@ static const struct iio_chan_spec ad7746_channels[] = { .indexed = 1, .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_VT_DATA_HIGH << 8 | AD7746_VTSETUP_VTMD_EXT_VIN, }, @@ -132,7 +133,8 @@ static const struct iio_chan_spec ad7746_channels[] = { .channel = 1, .extend_name = "supply", .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_VT_DATA_HIGH << 8 | AD7746_VTSETUP_VTMD_VDD_MON, }, @@ -159,7 +161,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | - BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_CAP_DATA_HIGH << 8, }, [CIN1_DIFF] = { @@ -171,7 +173,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | - BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_CAP_DATA_HIGH << 8 | AD7746_CAPSETUP_CAPDIFF }, @@ -182,7 +184,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | - BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_CAP_DATA_HIGH << 8 | AD7746_CAPSETUP_CIN2, }, @@ -195,7 +197,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | - BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_CAP_DATA_HIGH << 8 | AD7746_CAPSETUP_CAPDIFF | AD7746_CAPSETUP_CIN2, } @@ -355,101 +357,47 @@ static IIO_DEVICE_ATTR(in_capacitance1_calibscale_calibration, static IIO_DEVICE_ATTR(in_voltage0_calibscale_calibration, S_IWUSR, NULL, ad7746_start_gain_calib, VIN); -static ssize_t ad7746_show_cap_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - char *buf) +static int ad7746_store_cap_filter_rate_setup(struct ad7746_chip_info *chip, + int val) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7746_chip_info *chip = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", ad7746_cap_filter_rate_table[ - (chip->config >> 3) & 0x7][0]); -} - -static ssize_t ad7746_store_cap_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7746_chip_info *chip = iio_priv(indio_dev); - u8 data; - int ret, i; - - ret = kstrtou8(buf, 10, &data); - if (ret < 0) - return ret; + int i; for (i = 0; i < ARRAY_SIZE(ad7746_cap_filter_rate_table); i++) - if (data >= ad7746_cap_filter_rate_table[i][0]) + if (val >= ad7746_cap_filter_rate_table[i][0]) break; if (i >= ARRAY_SIZE(ad7746_cap_filter_rate_table)) i = ARRAY_SIZE(ad7746_cap_filter_rate_table) - 1; - mutex_lock(&indio_dev->mlock); chip->config &= ~AD7746_CONF_CAPFS(0x7); chip->config |= AD7746_CONF_CAPFS(i); - mutex_unlock(&indio_dev->mlock); - return len; + return 0; } -static ssize_t ad7746_show_vt_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - char *buf) +static int ad7746_store_vt_filter_rate_setup(struct ad7746_chip_info *chip, + int val) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7746_chip_info *chip = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", ad7746_vt_filter_rate_table[ - (chip->config >> 6) & 0x3][0]); -} - -static ssize_t ad7746_store_vt_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7746_chip_info *chip = iio_priv(indio_dev); - u8 data; - int ret, i; - - ret = kstrtou8(buf, 10, &data); - if (ret < 0) - return ret; + int i; for (i = 0; i < ARRAY_SIZE(ad7746_vt_filter_rate_table); i++) - if (data >= ad7746_vt_filter_rate_table[i][0]) + if (val >= ad7746_vt_filter_rate_table[i][0]) break; if (i >= ARRAY_SIZE(ad7746_vt_filter_rate_table)) i = ARRAY_SIZE(ad7746_vt_filter_rate_table) - 1; - mutex_lock(&indio_dev->mlock); chip->config &= ~AD7746_CONF_VTFS(0x3); chip->config |= AD7746_CONF_VTFS(i); - mutex_unlock(&indio_dev->mlock); - return len; + return 0; } -static IIO_DEVICE_ATTR(in_capacitance_sampling_frequency, - S_IRUGO | S_IWUSR, ad7746_show_cap_filter_rate_setup, - ad7746_store_cap_filter_rate_setup, 0); - -static IIO_DEVICE_ATTR(in_voltage_sampling_frequency, - S_IRUGO | S_IWUSR, ad7746_show_vt_filter_rate_setup, - ad7746_store_vt_filter_rate_setup, 0); - static IIO_CONST_ATTR(in_voltage_sampling_frequency_available, "50 31 16 8"); static IIO_CONST_ATTR(in_capacitance_sampling_frequency_available, "91 84 50 26 16 13 11 9"); static struct attribute *ad7746_attributes[] = { - &iio_dev_attr_in_capacitance_sampling_frequency.dev_attr.attr, - &iio_dev_attr_in_voltage_sampling_frequency.dev_attr.attr, &iio_dev_attr_in_capacitance0_calibbias_calibration.dev_attr.attr, &iio_dev_attr_in_capacitance0_calibscale_calibration.dev_attr.attr, &iio_dev_attr_in_capacitance1_calibscale_calibration.dev_attr.attr, @@ -547,6 +495,23 @@ static int ad7746_write_raw(struct iio_dev *indio_dev, ret = 0; break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) { + ret = -EINVAL; + goto out; + } + + switch (chan->type) { + case IIO_CAPACITANCE: + ret = ad7746_store_cap_filter_rate_setup(chip, val); + break; + case IIO_VOLTAGE: + ret = ad7746_store_vt_filter_rate_setup(chip, val); + break; + default: + ret = -EINVAL; + } + break; default: ret = -EINVAL; } @@ -666,6 +631,21 @@ static int ad7746_read_raw(struct iio_dev *indio_dev, break; } + break; + case IIO_CHAN_INFO_SAMP_FREQ: + switch (chan->type) { + case IIO_CAPACITANCE: + *val = ad7746_cap_filter_rate_table[ + (chip->config >> 3) & 0x7][0]; + ret = IIO_VAL_INT; + break; + case IIO_VOLTAGE: + *val = ad7746_vt_filter_rate_table[ + (chip->config >> 6) & 0x3][0]; + break; + default: + ret = -EINVAL; + } break; default: ret = -EINVAL; -- cgit v1.2.3 From f08a1508476d4501d32a0e82d28d5734243c4b11 Mon Sep 17 00:00:00 2001 From: sayli karnik Date: Mon, 10 Oct 2016 11:50:48 +0530 Subject: staging: iio: cdc: ad7152: Replace mlock with a local mutex lock mlock is intended to protect only switches between modes. Given this driver doesn't support more than one mode (sysfs polled reads only), replace mlock with a local mutex lock. Signed-off-by: sayli karnik Signed-off-by: Jonathan Cameron --- drivers/staging/iio/cdc/ad7152.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c index 0203c8103750..b91b50f345bd 100644 --- a/drivers/staging/iio/cdc/ad7152.c +++ b/drivers/staging/iio/cdc/ad7152.c @@ -89,6 +89,7 @@ struct ad7152_chip_info { */ u8 filter_rate_setup; u8 setup[2]; + struct mutex state_lock; /* protect hardware state */ }; static inline ssize_t ad7152_start_calib(struct device *dev, @@ -115,10 +116,10 @@ static inline ssize_t ad7152_start_calib(struct device *dev, else regval |= AD7152_CONF_CH2EN; - mutex_lock(&indio_dev->mlock); + mutex_lock(&chip->state_lock); ret = i2c_smbus_write_byte_data(chip->client, AD7152_REG_CFG, regval); if (ret < 0) { - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return ret; } @@ -126,12 +127,12 @@ static inline ssize_t ad7152_start_calib(struct device *dev, mdelay(20); ret = i2c_smbus_read_byte_data(chip->client, AD7152_REG_CFG); if (ret < 0) { - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return ret; } } while ((ret == regval) && timeout--); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return len; } @@ -230,16 +231,16 @@ static int ad7152_write_raw_samp_freq(struct device *dev, int val) if (i >= ARRAY_SIZE(ad7152_filter_rate_table)) i = ARRAY_SIZE(ad7152_filter_rate_table) - 1; - mutex_lock(&indio_dev->mlock); + mutex_lock(&chip->state_lock); ret = i2c_smbus_write_byte_data(chip->client, AD7152_REG_CFG2, AD7152_CFG2_OSR(i)); if (ret < 0) { - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return ret; } chip->filter_rate_setup = i; - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return ret; } @@ -252,7 +253,7 @@ static int ad7152_write_raw(struct iio_dev *indio_dev, struct ad7152_chip_info *chip = iio_priv(indio_dev); int ret, i; - mutex_lock(&indio_dev->mlock); + mutex_lock(&chip->state_lock); switch (mask) { case IIO_CHAN_INFO_CALIBSCALE: @@ -321,7 +322,7 @@ static int ad7152_write_raw(struct iio_dev *indio_dev, } out: - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return ret; } @@ -334,7 +335,7 @@ static int ad7152_read_raw(struct iio_dev *indio_dev, int ret; u8 regval = 0; - mutex_lock(&indio_dev->mlock); + mutex_lock(&chip->state_lock); switch (mask) { case IIO_CHAN_INFO_RAW: @@ -422,7 +423,7 @@ static int ad7152_read_raw(struct iio_dev *indio_dev, ret = -EINVAL; } out: - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return ret; } @@ -509,6 +510,7 @@ static int ad7152_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); chip->client = client; + mutex_init(&chip->state_lock); /* Establish that the iio_dev is a child of the i2c device */ indio_dev->name = id->name; -- cgit v1.2.3 From 92da01a08deb4678a2b653f65b9e685d90e261c9 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 Oct 2016 11:38:19 +0100 Subject: staging:iio:TODO drop outdated entries in this todo. There is still stuff to be done in the remaining drivers but pretty much nothing was left from this original TODO. Sorry Greg, should have been keeping this up to date. Signed-off-by: Jonathan Cameron Acked-by: Greg Kroah-Hartman --- drivers/staging/iio/TODO | 70 +----------------------------------------------- 1 file changed, 1 insertion(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO index 93a896883e37..4922402e2e98 100644 --- a/drivers/staging/iio/TODO +++ b/drivers/staging/iio/TODO @@ -1,76 +1,8 @@ -2009 8/18 - -Core: -1) Get reviews -2) Additional testing -3) Ensure all desirable features present by adding more devices. - Major changes not expected except in response to comments - -Max1363 core: -1) Possibly add sysfs exports of constant useful to userspace. -Would be nice -2) Support hardware generated interrupts -3) Expand device set. Lots of other maxim adc's have very - similar interfaces. - -MXS LRADC driver: -This is a classic MFD device as it combines the following subdevices - - touchscreen controller (input subsystem related device) - - general purpose ADC channels - - battery voltage monitor (power subsystem related device) - - die temperature monitor (thermal management) - -At least the battery voltage and die temperature feature is required in-kernel -by a driver of the SoC's battery charging unit to avoid any damage to the -silicon and the battery. - -TSL2561 -Would be nice -1) Open question of userspace vs kernel space balance when -converting to useful light measurements from device ones. -2) Add sysfs elements necessary to allow device agnostic -unit conversion. - -LIS3L02DQ core - -LIS3L02DQ ring - -KXSD9 -Currently minimal driver, would be nice to add: -1) Support for all chip generated interrupts (events), -basically get support up to level of lis3l02dq driver. - -Ring buffer core - -SCA3000 -Would be nice -1) Testing on devices other than sca3000-e05 - -Trigger core support -1) Discussion of approach. Is it general enough? - -Ring Buffer: -1) Discussion of approach. -There are probably better ways of doing this. The -intention is to allow for more than one software ring -buffer implementation as different users will have -different requirements. This one suits mid range -frequencies (100Hz - 4kHz). -2) Lots of testing - -GPIO trigger -1) Add control over the type of interrupt etc. This will -necessitate a header that is also visible from arch board -files. (avoided at the moment to keep the driver set -contained in staging). +2016 10/09 ADI Drivers: CC the device-drivers-devel@blackfin.uclinux.org mailing list when e-mailing the normal IIO list (see below). -Documentation -1) Lots of cleanup and expansion. -2) Some device require individual docs. - Contact: Jonathan Cameron . Mailing list: linux-iio@vger.kernel.org -- cgit v1.2.3 From 744ef62c2ee6ab71cdae944368983dc59b77dc32 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 10 Oct 2016 03:19:55 -0400 Subject: staging: iio: isl29018: add newlines to improve readability Add newlines to improve code readability in preparation for moving the driver out of staging. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 52bfb1cbe8e0..26bbbb87f743 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -399,6 +399,7 @@ static int isl29018_write_raw(struct iio_dev *indio_dev, write_done: mutex_unlock(&chip->lock); + return ret; } @@ -464,6 +465,7 @@ static int isl29018_read_raw(struct iio_dev *indio_dev, read_done: mutex_unlock(&chip->lock); + return ret; } @@ -726,6 +728,7 @@ static int isl29018_probe(struct i2c_client *client, indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); if (!indio_dev) return -ENOMEM; + chip = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); @@ -765,6 +768,7 @@ static int isl29018_probe(struct i2c_client *client, indio_dev->name = name; indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; + return devm_iio_device_register(&client->dev, indio_dev); } @@ -782,6 +786,7 @@ static int isl29018_suspend(struct device *dev) chip->suspended = true; mutex_unlock(&chip->lock); + return 0; } @@ -797,6 +802,7 @@ static int isl29018_resume(struct device *dev) chip->suspended = false; mutex_unlock(&chip->lock); + return err; } -- cgit v1.2.3 From 8281101c2d69dd784baf8bdd0895b40ff041b756 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 10 Oct 2016 03:19:56 -0400 Subject: staging: iio: isl29018: fix poorly named function isl29035_detect() did not just do chip detection. Move functionality directly into isl29018_chip_init() to avoid naming confusion. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 44 ++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 26bbbb87f743..130f2225a6fc 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -529,30 +529,6 @@ static const struct attribute_group isl29023_group = { .attrs = isl29023_attributes, }; -static int isl29035_detect(struct isl29018_chip *chip) -{ - int status; - unsigned int id; - struct device *dev = regmap_get_device(chip->regmap); - - status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id); - if (status < 0) { - dev_err(dev, - "Error reading ID register with error %d\n", - status); - return status; - } - - id = (id & ISL29035_DEVICE_ID_MASK) >> ISL29035_DEVICE_ID_SHIFT; - - if (id != ISL29035_DEVICE_ID) - return -ENODEV; - - /* Clear brownout bit */ - return regmap_update_bits(chip->regmap, ISL29035_REG_DEVICE_ID, - ISL29035_BOUT_MASK, 0); -} - enum { isl29018, isl29023, @@ -565,7 +541,25 @@ static int isl29018_chip_init(struct isl29018_chip *chip) struct device *dev = regmap_get_device(chip->regmap); if (chip->type == isl29035) { - status = isl29035_detect(chip); + unsigned int id; + + status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id); + if (status < 0) { + dev_err(dev, + "Error reading ID register with error %d\n", + status); + return status; + } + + id = (id & ISL29035_DEVICE_ID_MASK) >> ISL29035_DEVICE_ID_SHIFT; + + if (id != ISL29035_DEVICE_ID) + return -ENODEV; + + /* Clear brownout bit */ + status = regmap_update_bits(chip->regmap, + ISL29035_REG_DEVICE_ID, + ISL29035_BOUT_MASK, 0); if (status < 0) return status; } -- cgit v1.2.3 From 19a00a9d4c9027b4ce93b7c500da53dcb36ba1b0 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 10 Oct 2016 03:19:57 -0400 Subject: staging: iio: isl29018: fix multiline comment syntax Change multiline comments from: /* line1 * line2 * ... */ to /* * line1 * line2 * ... */ Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 130f2225a6fc..132de8e93bf8 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -564,7 +564,8 @@ static int isl29018_chip_init(struct isl29018_chip *chip) return status; } - /* Code added per Intersil Application Note 1534: + /* + * Code added per Intersil Application Note 1534: * When VDD sinks to approximately 1.8V or below, some of * the part's registers may change their state. When VDD * recovers to 2.25V (or greater), the part may thus be in an @@ -591,7 +592,8 @@ static int isl29018_chip_init(struct isl29018_chip *chip) return status; } - /* See Intersil AN1534 comments above. + /* + * See Intersil AN1534 comments above. * "Operating Mode" (COMMAND1) register is reprogrammed when * data is read from the device. */ @@ -773,7 +775,8 @@ static int isl29018_suspend(struct device *dev) mutex_lock(&chip->lock); - /* Since this driver uses only polling commands, we are by default in + /* + * Since this driver uses only polling commands, we are by default in * auto shutdown (ie, power-down) mode. * So we do not have much to do here. */ -- cgit v1.2.3 From aba1a8d77fe355d1b698e10b97c74974ca8b7438 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 10 Oct 2016 03:19:58 -0400 Subject: staging: iio: isl29018: combine two return statements into one Use the return value from isl29018_set_integration_time() as the return value for isl29018_chip_init() since this is the last piece of work inside that function. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 132de8e93bf8..6b6c761c801d 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -616,12 +616,10 @@ static int isl29018_chip_init(struct isl29018_chip *chip) status = isl29018_set_integration_time(chip, isl29018_int_utimes[chip->type][chip->int_time]); - if (status < 0) { + if (status < 0) dev_err(dev, "Init of isl29018 fails\n"); - return status; - } - return 0; + return status; } static const struct iio_info isl29018_info = { -- cgit v1.2.3 From b2f85b08c9e7d6c5aadc59f762f5dd77a9efd683 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 10 Oct 2016 03:19:59 -0400 Subject: staging: iio: isl29018: remove blank line for consistency Remove blank line between MODULE_DEVICE_TABLE() and its corresponding structure for consistency with the other device table entries. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 6b6c761c801d..917dd8b43e72 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -821,7 +821,6 @@ static const struct i2c_device_id isl29018_id[] = { {"isl29035", isl29035}, {} }; - MODULE_DEVICE_TABLE(i2c, isl29018_id); static const struct of_device_id isl29018_of_match[] = { -- cgit v1.2.3 From bac80fd0cf889d99461e54e4e1ae31392769f635 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 10 Oct 2016 03:20:00 -0400 Subject: staging: iio: isl29018: rename description in Kconfig for consistency Rename description from "ISL 29018" to "Intersil 29018" in Kconfig for consistency with other drivers in mainline. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig index ca8d6e66c899..5e4e77ef7f98 100644 --- a/drivers/staging/iio/light/Kconfig +++ b/drivers/staging/iio/light/Kconfig @@ -4,7 +4,7 @@ menu "Light sensors" config SENSORS_ISL29018 - tristate "ISL 29018 light and proximity sensor" + tristate "Intersil 29018 light and proximity sensor" depends on I2C select REGMAP_I2C default n -- cgit v1.2.3 From dd4ba3fb22233e69f06399ee0aa7ecb11d2b595c Mon Sep 17 00:00:00 2001 From: sayli karnik Date: Tue, 11 Oct 2016 17:07:21 +0530 Subject: iio: bmi160_core: Fix sparse warning due to incorrect type in assignment There is a type mismatch between the buffer which is of type s16 and the samples stored, which are declared as __le16. Fix the following sparse warning: drivers/iio/imu/bmi160/bmi160_core.c:411:26: warning: incorrect type in assignment (different base types) drivers/iio/imu/bmi160/bmi160_core.c:411:26: expected signed short [signed] [short] [explicitly-signed] drivers/iio/imu/bmi160/bmi160_core.c:411:26: got restricted __le16 [addressable] [usertype] sample This is a cosmetic-type patch since it does not alter code behaviour. The le16 is going into a 16bit buf element, and is labelled as IIO_LE in the channel buffer definition. Signed-off-by: sayli karnik Signed-off-by: Jonathan Cameron --- drivers/iio/imu/bmi160/bmi160_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index e0251b8c1a52..5355507f8fa1 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -398,7 +398,8 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmi160_data *data = iio_priv(indio_dev); - s16 buf[16]; /* 3 sens x 3 axis x s16 + 3 x s16 pad + 4 x s16 tstamp */ + __le16 buf[16]; + /* 3 sens x 3 axis x __le16 + 3 x __le16 pad + 4 x __le16 tstamp */ int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L; __le16 sample; -- cgit v1.2.3 From 3f5def652f6609dd1981be8283de155f15a3df48 Mon Sep 17 00:00:00 2001 From: Crt Mori Date: Fri, 14 Oct 2016 15:43:14 +0200 Subject: iio: ms65611_core: Fixes dereferencing regulator pointer Change in handling of the regulator description means that static checkers correctly assume we could be using dereferenced pointer to the regulator. In reality we will never get the -ENODEV error, as current behavior flow does not predict it, because: If the device tree or board file does not define suitable regulators for the component, it will be substituted by a dummy regulator, or, if regulators are disabled altogether, by stubs. Reported-by: Dan Carpenter Suggested-by: Lars-Peter Clausen Signed-off-by: Crt Mori Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/ms5611_core.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index a74ed1f0c880..6bd53e702667 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -392,17 +392,14 @@ static int ms5611_init(struct iio_dev *indio_dev) /* Enable attached regulator if any. */ st->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd"); - if (!IS_ERR(st->vdd)) { - ret = regulator_enable(st->vdd); - if (ret) { - dev_err(indio_dev->dev.parent, - "failed to enable Vdd supply: %d\n", ret); - return ret; - } - } else { - ret = PTR_ERR(st->vdd); - if (ret != -ENODEV) - return ret; + if (IS_ERR(st->vdd)) + return PTR_ERR(st->vdd); + + ret = regulator_enable(st->vdd); + if (ret) { + dev_err(indio_dev->dev.parent, + "failed to enable Vdd supply: %d\n", ret); + return ret; } ret = ms5611_reset(indio_dev); -- cgit v1.2.3 From b440f1d90ec54fd2586537ea46e958343ad4b151 Mon Sep 17 00:00:00 2001 From: Tomas Novotny Date: Tue, 11 Oct 2016 15:57:40 +0200 Subject: iio: dac: mcp4725: use regulator framework Use a standard framework to get the reference voltage. It is done that way in the iio subsystem and it will simplify extending of the driver. Structure mcp4725_platform_data is left undeleted because it used in the next patch. This change breaks the current users of the driver, but there is no mainline user of struct mcp4725_platform_data. Signed-off-by: Tomas Novotny Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4725.c | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index cca935c06f2b..2b28b1f5b3a2 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -28,10 +29,10 @@ struct mcp4725_data { struct i2c_client *client; - u16 vref_mv; u16 dac_value; bool powerdown; unsigned powerdown_mode; + struct regulator *vdd_reg; }; static int mcp4725_suspend(struct device *dev) @@ -283,13 +284,18 @@ static int mcp4725_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct mcp4725_data *data = iio_priv(indio_dev); + int ret; switch (mask) { case IIO_CHAN_INFO_RAW: *val = data->dac_value; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = data->vref_mv; + ret = regulator_get_voltage(data->vdd_reg); + if (ret < 0) + return ret; + + *val = ret / 1000; *val2 = 12; return IIO_VAL_FRACTIONAL_LOG2; } @@ -328,12 +334,12 @@ static int mcp4725_probe(struct i2c_client *client, { struct mcp4725_data *data; struct iio_dev *indio_dev; - struct mcp4725_platform_data *platform_data = client->dev.platform_data; + struct mcp4725_platform_data *pdata = dev_get_platdata(&client->dev); u8 inbuf[3]; u8 pd; int err; - if (!platform_data || !platform_data->vref_mv) { + if (!pdata) { dev_err(&client->dev, "invalid platform data"); return -EINVAL; } @@ -345,6 +351,14 @@ static int mcp4725_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); data->client = client; + data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(data->vdd_reg)) + return PTR_ERR(data->vdd_reg); + + err = regulator_enable(data->vdd_reg); + if (err) + return err; + indio_dev->dev.parent = &client->dev; indio_dev->name = id->name; indio_dev->info = &mcp4725_info; @@ -352,25 +366,39 @@ static int mcp4725_probe(struct i2c_client *client, indio_dev->num_channels = 1; indio_dev->modes = INDIO_DIRECT_MODE; - data->vref_mv = platform_data->vref_mv; - /* read current DAC value */ err = i2c_master_recv(client, inbuf, 3); if (err < 0) { dev_err(&client->dev, "failed to read DAC value"); - return err; + goto err_disable_vdd_reg; } pd = (inbuf[0] >> 1) & 0x3; data->powerdown = pd > 0 ? true : false; data->powerdown_mode = pd ? pd - 1 : 2; /* largest register to gnd */ data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4); - return iio_device_register(indio_dev); + err = iio_device_register(indio_dev); + if (err) + goto err_disable_vdd_reg; + + return 0; + + +err_disable_vdd_reg: + regulator_disable(data->vdd_reg); + + return err; } static int mcp4725_remove(struct i2c_client *client) { - iio_device_unregister(i2c_get_clientdata(client)); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct mcp4725_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + regulator_disable(data->vdd_reg); + return 0; } -- cgit v1.2.3 From 4d9b0413e29d61e6382b613f4835118504e65e86 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Tue, 11 Oct 2016 12:31:36 -0700 Subject: iio: accel: mma8452: claim direct mode during raw reads Driver was checking for direct mode but not locking it. Use claim/release helper functions to guarantee the device stays in direct mode during raw reads. Signed-off-by: Alison Schofield Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 1c7051581513..7951def89d63 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -459,12 +459,14 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; mutex_lock(&data->lock); ret = mma8452_read(data, buffer); mutex_unlock(&data->lock); + iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; -- cgit v1.2.3 From 79de2ee469aaef0afb25dde7d65d7fbc91600573 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 15 Oct 2016 15:55:06 +0100 Subject: iio: accel: mma8452: claim direct mode during write raw Driver was checking for direct mode but not locking it. Use claim/release helper functions to guarantee the device stays in direct mode during all write raw operations. Signed-off-by: Alison Schofield Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 60 ++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 7951def89d63..f418c588af6a 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -666,37 +666,46 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, struct mma8452_data *data = iio_priv(indio_dev); int i, ret; - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: i = mma8452_get_samp_freq_index(data, val, val2); - if (i < 0) - return i; - + if (i < 0) { + ret = i; + break; + } data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; - return mma8452_change_config(data, MMA8452_CTRL_REG1, - data->ctrl_reg1); + ret = mma8452_change_config(data, MMA8452_CTRL_REG1, + data->ctrl_reg1); + break; case IIO_CHAN_INFO_SCALE: i = mma8452_get_scale_index(data, val, val2); - if (i < 0) - return i; + if (i < 0) { + ret = i; + break; + } data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; data->data_cfg |= i; - return mma8452_change_config(data, MMA8452_DATA_CFG, - data->data_cfg); + ret = mma8452_change_config(data, MMA8452_DATA_CFG, + data->data_cfg); + break; case IIO_CHAN_INFO_CALIBBIAS: - if (val < -128 || val > 127) - return -EINVAL; + if (val < -128 || val > 127) { + ret = -EINVAL; + break; + } - return mma8452_change_config(data, - MMA8452_OFF_X + chan->scan_index, - val); + ret = mma8452_change_config(data, + MMA8452_OFF_X + chan->scan_index, + val); + break; case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: if (val == 0 && val2 == 0) { @@ -705,23 +714,30 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK; ret = mma8452_set_hp_filter_frequency(data, val, val2); if (ret < 0) - return ret; + break; } - return mma8452_change_config(data, MMA8452_DATA_CFG, + ret = mma8452_change_config(data, MMA8452_DATA_CFG, data->data_cfg); + break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: ret = mma8452_get_odr_index(data); for (i = 0; i < ARRAY_SIZE(mma8452_os_ratio); i++) { - if (mma8452_os_ratio[i][ret] == val) - return mma8452_set_power_mode(data, i); + if (mma8452_os_ratio[i][ret] == val) { + ret = mma8452_set_power_mode(data, i); + break; + } } - + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + + iio_device_release_direct_mode(indio_dev); + return ret; } static int mma8452_read_thresh(struct iio_dev *indio_dev, -- cgit v1.2.3 From ac13980584d1fe2493516e1f6e839f0a3c425280 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Tue, 11 Oct 2016 12:33:12 -0700 Subject: iio: pressure: mpl3115: claim direct mode during raw reads Driver was checking for direct mode but not locking it. Use claim/release helper functions to guarantee the device stays in direct mode during raw reads. Signed-off-by: Alison Schofield Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/mpl3115.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index 6392d7b62841..cc3f84139157 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -82,8 +82,9 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; switch (chan->type) { case IIO_PRESSURE: /* in 0.25 pascal / LSB */ @@ -91,32 +92,39 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, ret = mpl3115_request(data); if (ret < 0) { mutex_unlock(&data->lock); - return ret; + break; } ret = i2c_smbus_read_i2c_block_data(data->client, MPL3115_OUT_PRESS, 3, (u8 *) &tmp); mutex_unlock(&data->lock); if (ret < 0) - return ret; + break; *val = be32_to_cpu(tmp) >> 12; - return IIO_VAL_INT; + ret = IIO_VAL_INT; + break; case IIO_TEMP: /* in 0.0625 celsius / LSB */ mutex_lock(&data->lock); ret = mpl3115_request(data); if (ret < 0) { mutex_unlock(&data->lock); - return ret; + break; } ret = i2c_smbus_read_i2c_block_data(data->client, MPL3115_OUT_TEMP, 2, (u8 *) &tmp); mutex_unlock(&data->lock); if (ret < 0) - return ret; + break; *val = sign_extend32(be32_to_cpu(tmp) >> 20, 11); - return IIO_VAL_INT; + ret = IIO_VAL_INT; + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + + iio_device_release_direct_mode(indio_dev); + return ret; + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_PRESSURE: -- cgit v1.2.3 From a57504144c62404472f3cc6a7bf4ada4508d5ddc Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 10 Oct 2016 03:20:02 -0400 Subject: staging: iio: isl29018: move out of staging Move ISL29018/ISL29023/ISL29035 driver out of staging into mainline. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 12 + drivers/iio/light/Makefile | 1 + drivers/iio/light/isl29018.c | 847 +++++++++++++++++++++++++++++++++++ drivers/staging/iio/light/Kconfig | 12 - drivers/staging/iio/light/Makefile | 1 - drivers/staging/iio/light/isl29018.c | 847 ----------------------------------- 6 files changed, 860 insertions(+), 860 deletions(-) create mode 100644 drivers/iio/light/isl29018.c delete mode 100644 drivers/staging/iio/light/isl29018.c (limited to 'drivers') diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index ba2e64d7ee58..d01172089828 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -140,6 +140,18 @@ config GP2AP020A00F To compile this driver as a module, choose M here: the module will be called gp2ap020a00f. +config SENSORS_ISL29018 + tristate "Intersil 29018 light and proximity sensor" + depends on I2C + select REGMAP_I2C + default n + help + If you say yes here you get support for ambient light sensing and + proximity infrared sensing from Intersil ISL29018. + This driver will provide the measurements of ambient light intensity + in lux, proximity infrared sensing and normal infrared sensing. + Data from sensor is accessible via sysfs. + config ISL29125 tristate "Intersil ISL29125 digital color light sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index c5768df87a17..15f24c557f5f 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_CM36651) += cm36651.o obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o +obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o obj-$(CONFIG_ISL29125) += isl29125.o obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c new file mode 100644 index 000000000000..917dd8b43e72 --- /dev/null +++ b/drivers/iio/light/isl29018.c @@ -0,0 +1,847 @@ +/* + * A iio driver for the light sensor ISL 29018/29023/29035. + * + * IIO driver for monitoring ambient light intensity in luxi, proximity + * sensing and infrared sensing. + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ISL29018_CONV_TIME_MS 100 + +#define ISL29018_REG_ADD_COMMAND1 0x00 +#define ISL29018_CMD1_OPMODE_SHIFT 5 +#define ISL29018_CMD1_OPMODE_MASK (7 << ISL29018_CMD1_OPMODE_SHIFT) +#define ISL29018_CMD1_OPMODE_POWER_DOWN 0 +#define ISL29018_CMD1_OPMODE_ALS_ONCE 1 +#define ISL29018_CMD1_OPMODE_IR_ONCE 2 +#define ISL29018_CMD1_OPMODE_PROX_ONCE 3 + +#define ISL29018_REG_ADD_COMMAND2 0x01 +#define ISL29018_CMD2_RESOLUTION_SHIFT 2 +#define ISL29018_CMD2_RESOLUTION_MASK (0x3 << ISL29018_CMD2_RESOLUTION_SHIFT) + +#define ISL29018_CMD2_RANGE_SHIFT 0 +#define ISL29018_CMD2_RANGE_MASK (0x3 << ISL29018_CMD2_RANGE_SHIFT) + +#define ISL29018_CMD2_SCHEME_SHIFT 7 +#define ISL29018_CMD2_SCHEME_MASK (0x1 << ISL29018_CMD2_SCHEME_SHIFT) + +#define ISL29018_REG_ADD_DATA_LSB 0x02 +#define ISL29018_REG_ADD_DATA_MSB 0x03 + +#define ISL29018_REG_TEST 0x08 +#define ISL29018_TEST_SHIFT 0 +#define ISL29018_TEST_MASK (0xFF << ISL29018_TEST_SHIFT) + +#define ISL29035_REG_DEVICE_ID 0x0F +#define ISL29035_DEVICE_ID_SHIFT 0x03 +#define ISL29035_DEVICE_ID_MASK (0x7 << ISL29035_DEVICE_ID_SHIFT) +#define ISL29035_DEVICE_ID 0x5 +#define ISL29035_BOUT_SHIFT 0x07 +#define ISL29035_BOUT_MASK (0x01 << ISL29035_BOUT_SHIFT) + +enum isl29018_int_time { + ISL29018_INT_TIME_16, + ISL29018_INT_TIME_12, + ISL29018_INT_TIME_8, + ISL29018_INT_TIME_4, +}; + +static const unsigned int isl29018_int_utimes[3][4] = { + {90000, 5630, 351, 21}, + {90000, 5600, 352, 22}, + {105000, 6500, 410, 25}, +}; + +static const struct isl29018_scale { + unsigned int scale; + unsigned int uscale; +} isl29018_scales[4][4] = { + { {0, 15258}, {0, 61035}, {0, 244140}, {0, 976562} }, + { {0, 244140}, {0, 976562}, {3, 906250}, {15, 625000} }, + { {3, 906250}, {15, 625000}, {62, 500000}, {250, 0} }, + { {62, 500000}, {250, 0}, {1000, 0}, {4000, 0} } +}; + +struct isl29018_chip { + struct regmap *regmap; + struct mutex lock; + int type; + unsigned int calibscale; + unsigned int ucalibscale; + unsigned int int_time; + struct isl29018_scale scale; + int prox_scheme; + bool suspended; +}; + +static int isl29018_set_integration_time(struct isl29018_chip *chip, + unsigned int utime) +{ + unsigned int i; + int ret; + unsigned int int_time, new_int_time; + + for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) { + if (utime == isl29018_int_utimes[chip->type][i]) { + new_int_time = i; + break; + } + } + + if (i >= ARRAY_SIZE(isl29018_int_utimes[chip->type])) + return -EINVAL; + + ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2, + ISL29018_CMD2_RESOLUTION_MASK, + i << ISL29018_CMD2_RESOLUTION_SHIFT); + if (ret < 0) + return ret; + + /* Keep the same range when integration time changes */ + int_time = chip->int_time; + for (i = 0; i < ARRAY_SIZE(isl29018_scales[int_time]); ++i) { + if (chip->scale.scale == isl29018_scales[int_time][i].scale && + chip->scale.uscale == isl29018_scales[int_time][i].uscale) { + chip->scale = isl29018_scales[new_int_time][i]; + break; + } + } + chip->int_time = new_int_time; + + return 0; +} + +static int isl29018_set_scale(struct isl29018_chip *chip, int scale, int uscale) +{ + unsigned int i; + int ret; + struct isl29018_scale new_scale; + + for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) { + if (scale == isl29018_scales[chip->int_time][i].scale && + uscale == isl29018_scales[chip->int_time][i].uscale) { + new_scale = isl29018_scales[chip->int_time][i]; + break; + } + } + + if (i >= ARRAY_SIZE(isl29018_scales[chip->int_time])) + return -EINVAL; + + ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2, + ISL29018_CMD2_RANGE_MASK, + i << ISL29018_CMD2_RANGE_SHIFT); + if (ret < 0) + return ret; + + chip->scale = new_scale; + + return 0; +} + +static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode) +{ + int status; + unsigned int lsb; + unsigned int msb; + struct device *dev = regmap_get_device(chip->regmap); + + /* Set mode */ + status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, + mode << ISL29018_CMD1_OPMODE_SHIFT); + if (status) { + dev_err(dev, + "Error in setting operating mode err %d\n", status); + return status; + } + msleep(ISL29018_CONV_TIME_MS); + status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb); + if (status < 0) { + dev_err(dev, + "Error in reading LSB DATA with err %d\n", status); + return status; + } + + status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_MSB, &msb); + if (status < 0) { + dev_err(dev, + "Error in reading MSB DATA with error %d\n", status); + return status; + } + dev_vdbg(dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); + + return (msb << 8) | lsb; +} + +static int isl29018_read_lux(struct isl29018_chip *chip, int *lux) +{ + int lux_data; + unsigned int data_x_range; + + lux_data = isl29018_read_sensor_input(chip, + ISL29018_CMD1_OPMODE_ALS_ONCE); + if (lux_data < 0) + return lux_data; + + data_x_range = lux_data * chip->scale.scale + + lux_data * chip->scale.uscale / 1000000; + *lux = data_x_range * chip->calibscale + + data_x_range * chip->ucalibscale / 1000000; + + return 0; +} + +static int isl29018_read_ir(struct isl29018_chip *chip, int *ir) +{ + int ir_data; + + ir_data = isl29018_read_sensor_input(chip, + ISL29018_CMD1_OPMODE_IR_ONCE); + if (ir_data < 0) + return ir_data; + + *ir = ir_data; + + return 0; +} + +static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme, + int *near_ir) +{ + int status; + int prox_data = -1; + int ir_data = -1; + struct device *dev = regmap_get_device(chip->regmap); + + /* Do proximity sensing with required scheme */ + status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2, + ISL29018_CMD2_SCHEME_MASK, + scheme << ISL29018_CMD2_SCHEME_SHIFT); + if (status) { + dev_err(dev, "Error in setting operating mode\n"); + return status; + } + + prox_data = isl29018_read_sensor_input(chip, + ISL29018_CMD1_OPMODE_PROX_ONCE); + if (prox_data < 0) + return prox_data; + + if (scheme == 1) { + *near_ir = prox_data; + return 0; + } + + ir_data = isl29018_read_sensor_input(chip, + ISL29018_CMD1_OPMODE_IR_ONCE); + if (ir_data < 0) + return ir_data; + + if (prox_data >= ir_data) + *near_ir = prox_data - ir_data; + else + *near_ir = 0; + + return 0; +} + +static ssize_t in_illuminance_scale_available_show + (struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct isl29018_chip *chip = iio_priv(indio_dev); + unsigned int i; + int len = 0; + + mutex_lock(&chip->lock); + for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) + len += sprintf(buf + len, "%d.%06d ", + isl29018_scales[chip->int_time][i].scale, + isl29018_scales[chip->int_time][i].uscale); + mutex_unlock(&chip->lock); + + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t in_illuminance_integration_time_available_show + (struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct isl29018_chip *chip = iio_priv(indio_dev); + unsigned int i; + int len = 0; + + for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) + len += sprintf(buf + len, "0.%06d ", + isl29018_int_utimes[chip->type][i]); + + buf[len - 1] = '\n'; + + return len; +} + +/* + * From ISL29018 Data Sheet (FN6619.4, Oct 8, 2012) regarding the + * infrared suppression: + * + * Proximity Sensing Scheme: Bit 7. This bit programs the function + * of the proximity detection. Logic 0 of this bit, Scheme 0, makes + * full n (4, 8, 12, 16) bits (unsigned) proximity detection. The range + * of Scheme 0 proximity count is from 0 to 2^n. Logic 1 of this bit, + * Scheme 1, makes n-1 (3, 7, 11, 15) bits (2's complementary) + * proximity_less_ambient detection. The range of Scheme 1 + * proximity count is from -2^(n-1) to 2^(n-1) . The sign bit is extended + * for resolutions less than 16. While Scheme 0 has wider dynamic + * range, Scheme 1 proximity detection is less affected by the + * ambient IR noise variation. + * + * 0 Sensing IR from LED and ambient + * 1 Sensing IR from LED with ambient IR rejection + */ +static ssize_t proximity_on_chip_ambient_infrared_suppression_show + (struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct isl29018_chip *chip = iio_priv(indio_dev); + + /* + * Return the "proximity scheme" i.e. if the chip does on chip + * infrared suppression (1 means perform on chip suppression) + */ + return sprintf(buf, "%d\n", chip->prox_scheme); +} + +static ssize_t proximity_on_chip_ambient_infrared_suppression_store + (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct isl29018_chip *chip = iio_priv(indio_dev); + int val; + + if (kstrtoint(buf, 10, &val)) + return -EINVAL; + if (!(val == 0 || val == 1)) + return -EINVAL; + + /* + * Get the "proximity scheme" i.e. if the chip does on chip + * infrared suppression (1 means perform on chip suppression) + */ + mutex_lock(&chip->lock); + chip->prox_scheme = val; + mutex_unlock(&chip->lock); + + return count; +} + +static int isl29018_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct isl29018_chip *chip = iio_priv(indio_dev); + int ret = -EINVAL; + + mutex_lock(&chip->lock); + if (chip->suspended) { + ret = -EBUSY; + goto write_done; + } + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + if (chan->type == IIO_LIGHT) { + chip->calibscale = val; + chip->ucalibscale = val2; + ret = 0; + } + break; + case IIO_CHAN_INFO_INT_TIME: + if (chan->type == IIO_LIGHT && !val) + ret = isl29018_set_integration_time(chip, val2); + break; + case IIO_CHAN_INFO_SCALE: + if (chan->type == IIO_LIGHT) + ret = isl29018_set_scale(chip, val, val2); + break; + default: + break; + } + +write_done: + mutex_unlock(&chip->lock); + + return ret; +} + +static int isl29018_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + int ret = -EINVAL; + struct isl29018_chip *chip = iio_priv(indio_dev); + + mutex_lock(&chip->lock); + if (chip->suspended) { + ret = -EBUSY; + goto read_done; + } + switch (mask) { + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_LIGHT: + ret = isl29018_read_lux(chip, val); + break; + case IIO_INTENSITY: + ret = isl29018_read_ir(chip, val); + break; + case IIO_PROXIMITY: + ret = isl29018_read_proximity_ir(chip, + chip->prox_scheme, + val); + break; + default: + break; + } + if (!ret) + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_INT_TIME: + if (chan->type == IIO_LIGHT) { + *val = 0; + *val2 = isl29018_int_utimes[chip->type][chip->int_time]; + ret = IIO_VAL_INT_PLUS_MICRO; + } + break; + case IIO_CHAN_INFO_SCALE: + if (chan->type == IIO_LIGHT) { + *val = chip->scale.scale; + *val2 = chip->scale.uscale; + ret = IIO_VAL_INT_PLUS_MICRO; + } + break; + case IIO_CHAN_INFO_CALIBSCALE: + if (chan->type == IIO_LIGHT) { + *val = chip->calibscale; + *val2 = chip->ucalibscale; + ret = IIO_VAL_INT_PLUS_MICRO; + } + break; + default: + break; + } + +read_done: + mutex_unlock(&chip->lock); + + return ret; +} + +#define ISL29018_LIGHT_CHANNEL { \ + .type = IIO_LIGHT, \ + .indexed = 1, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \ + BIT(IIO_CHAN_INFO_CALIBSCALE) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_INT_TIME), \ +} + +#define ISL29018_IR_CHANNEL { \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .channel2 = IIO_MOD_LIGHT_IR, \ +} + +#define ISL29018_PROXIMITY_CHANNEL { \ + .type = IIO_PROXIMITY, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ +} + +static const struct iio_chan_spec isl29018_channels[] = { + ISL29018_LIGHT_CHANNEL, + ISL29018_IR_CHANNEL, + ISL29018_PROXIMITY_CHANNEL, +}; + +static const struct iio_chan_spec isl29023_channels[] = { + ISL29018_LIGHT_CHANNEL, + ISL29018_IR_CHANNEL, +}; + +static IIO_DEVICE_ATTR_RO(in_illuminance_integration_time_available, 0); +static IIO_DEVICE_ATTR_RO(in_illuminance_scale_available, 0); +static IIO_DEVICE_ATTR_RW(proximity_on_chip_ambient_infrared_suppression, 0); + +#define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) + +static struct attribute *isl29018_attributes[] = { + ISL29018_DEV_ATTR(in_illuminance_scale_available), + ISL29018_DEV_ATTR(in_illuminance_integration_time_available), + ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_suppression), + NULL +}; + +static struct attribute *isl29023_attributes[] = { + ISL29018_DEV_ATTR(in_illuminance_scale_available), + ISL29018_DEV_ATTR(in_illuminance_integration_time_available), + NULL +}; + +static const struct attribute_group isl29018_group = { + .attrs = isl29018_attributes, +}; + +static const struct attribute_group isl29023_group = { + .attrs = isl29023_attributes, +}; + +enum { + isl29018, + isl29023, + isl29035, +}; + +static int isl29018_chip_init(struct isl29018_chip *chip) +{ + int status; + struct device *dev = regmap_get_device(chip->regmap); + + if (chip->type == isl29035) { + unsigned int id; + + status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id); + if (status < 0) { + dev_err(dev, + "Error reading ID register with error %d\n", + status); + return status; + } + + id = (id & ISL29035_DEVICE_ID_MASK) >> ISL29035_DEVICE_ID_SHIFT; + + if (id != ISL29035_DEVICE_ID) + return -ENODEV; + + /* Clear brownout bit */ + status = regmap_update_bits(chip->regmap, + ISL29035_REG_DEVICE_ID, + ISL29035_BOUT_MASK, 0); + if (status < 0) + return status; + } + + /* + * Code added per Intersil Application Note 1534: + * When VDD sinks to approximately 1.8V or below, some of + * the part's registers may change their state. When VDD + * recovers to 2.25V (or greater), the part may thus be in an + * unknown mode of operation. The user can return the part to + * a known mode of operation either by (a) setting VDD = 0V for + * 1 second or more and then powering back up with a slew rate + * of 0.5V/ms or greater, or (b) via I2C disable all ALS/PROX + * conversions, clear the test registers, and then rewrite all + * registers to the desired values. + * ... + * For ISL29011, ISL29018, ISL29021, ISL29023 + * 1. Write 0x00 to register 0x08 (TEST) + * 2. Write 0x00 to register 0x00 (CMD1) + * 3. Rewrite all registers to the desired values + * + * ISL29018 Data Sheet (FN6619.1, Feb 11, 2010) essentially says + * the same thing EXCEPT the data sheet asks for a 1ms delay after + * writing the CMD1 register. + */ + status = regmap_write(chip->regmap, ISL29018_REG_TEST, 0x0); + if (status < 0) { + dev_err(dev, "Failed to clear isl29018 TEST reg.(%d)\n", + status); + return status; + } + + /* + * See Intersil AN1534 comments above. + * "Operating Mode" (COMMAND1) register is reprogrammed when + * data is read from the device. + */ + status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 0); + if (status < 0) { + dev_err(dev, "Failed to clear isl29018 CMD1 reg.(%d)\n", + status); + return status; + } + + usleep_range(1000, 2000); /* per data sheet, page 10 */ + + /* Set defaults */ + status = isl29018_set_scale(chip, chip->scale.scale, + chip->scale.uscale); + if (status < 0) { + dev_err(dev, "Init of isl29018 fails\n"); + return status; + } + + status = isl29018_set_integration_time(chip, + isl29018_int_utimes[chip->type][chip->int_time]); + if (status < 0) + dev_err(dev, "Init of isl29018 fails\n"); + + return status; +} + +static const struct iio_info isl29018_info = { + .attrs = &isl29018_group, + .driver_module = THIS_MODULE, + .read_raw = isl29018_read_raw, + .write_raw = isl29018_write_raw, +}; + +static const struct iio_info isl29023_info = { + .attrs = &isl29023_group, + .driver_module = THIS_MODULE, + .read_raw = isl29018_read_raw, + .write_raw = isl29018_write_raw, +}; + +static bool isl29018_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ISL29018_REG_ADD_DATA_LSB: + case ISL29018_REG_ADD_DATA_MSB: + case ISL29018_REG_ADD_COMMAND1: + case ISL29018_REG_TEST: + case ISL29035_REG_DEVICE_ID: + return true; + default: + return false; + } +} + +static const struct regmap_config isl29018_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = isl29018_is_volatile_reg, + .max_register = ISL29018_REG_TEST, + .num_reg_defaults_raw = ISL29018_REG_TEST + 1, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct regmap_config isl29035_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = isl29018_is_volatile_reg, + .max_register = ISL29035_REG_DEVICE_ID, + .num_reg_defaults_raw = ISL29035_REG_DEVICE_ID + 1, + .cache_type = REGCACHE_RBTREE, +}; + +struct isl29018_chip_info { + const struct iio_chan_spec *channels; + int num_channels; + const struct iio_info *indio_info; + const struct regmap_config *regmap_cfg; +}; + +static const struct isl29018_chip_info isl29018_chip_info_tbl[] = { + [isl29018] = { + .channels = isl29018_channels, + .num_channels = ARRAY_SIZE(isl29018_channels), + .indio_info = &isl29018_info, + .regmap_cfg = &isl29018_regmap_config, + }, + [isl29023] = { + .channels = isl29023_channels, + .num_channels = ARRAY_SIZE(isl29023_channels), + .indio_info = &isl29023_info, + .regmap_cfg = &isl29018_regmap_config, + }, + [isl29035] = { + .channels = isl29023_channels, + .num_channels = ARRAY_SIZE(isl29023_channels), + .indio_info = &isl29023_info, + .regmap_cfg = &isl29035_regmap_config, + }, +}; + +static const char *isl29018_match_acpi_device(struct device *dev, int *data) +{ + const struct acpi_device_id *id; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + + if (!id) + return NULL; + + *data = (int)id->driver_data; + + return dev_name(dev); +} + +static int isl29018_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct isl29018_chip *chip; + struct iio_dev *indio_dev; + int err; + const char *name = NULL; + int dev_id = 0; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + + chip = iio_priv(indio_dev); + + i2c_set_clientdata(client, indio_dev); + + if (id) { + name = id->name; + dev_id = id->driver_data; + } + + if (ACPI_HANDLE(&client->dev)) + name = isl29018_match_acpi_device(&client->dev, &dev_id); + + mutex_init(&chip->lock); + + chip->type = dev_id; + chip->calibscale = 1; + chip->ucalibscale = 0; + chip->int_time = ISL29018_INT_TIME_16; + chip->scale = isl29018_scales[chip->int_time][0]; + chip->suspended = false; + + chip->regmap = devm_regmap_init_i2c(client, + isl29018_chip_info_tbl[dev_id].regmap_cfg); + if (IS_ERR(chip->regmap)) { + err = PTR_ERR(chip->regmap); + dev_err(&client->dev, "regmap initialization fails: %d\n", err); + return err; + } + + err = isl29018_chip_init(chip); + if (err) + return err; + + indio_dev->info = isl29018_chip_info_tbl[dev_id].indio_info; + indio_dev->channels = isl29018_chip_info_tbl[dev_id].channels; + indio_dev->num_channels = isl29018_chip_info_tbl[dev_id].num_channels; + indio_dev->name = name; + indio_dev->dev.parent = &client->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +#ifdef CONFIG_PM_SLEEP +static int isl29018_suspend(struct device *dev) +{ + struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev)); + + mutex_lock(&chip->lock); + + /* + * Since this driver uses only polling commands, we are by default in + * auto shutdown (ie, power-down) mode. + * So we do not have much to do here. + */ + chip->suspended = true; + + mutex_unlock(&chip->lock); + + return 0; +} + +static int isl29018_resume(struct device *dev) +{ + struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev)); + int err; + + mutex_lock(&chip->lock); + + err = isl29018_chip_init(chip); + if (!err) + chip->suspended = false; + + mutex_unlock(&chip->lock); + + return err; +} + +static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume); +#define ISL29018_PM_OPS (&isl29018_pm_ops) +#else +#define ISL29018_PM_OPS NULL +#endif + +static const struct acpi_device_id isl29018_acpi_match[] = { + {"ISL29018", isl29018}, + {"ISL29023", isl29023}, + {"ISL29035", isl29035}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); + +static const struct i2c_device_id isl29018_id[] = { + {"isl29018", isl29018}, + {"isl29023", isl29023}, + {"isl29035", isl29035}, + {} +}; +MODULE_DEVICE_TABLE(i2c, isl29018_id); + +static const struct of_device_id isl29018_of_match[] = { + { .compatible = "isil,isl29018", }, + { .compatible = "isil,isl29023", }, + { .compatible = "isil,isl29035", }, + { }, +}; +MODULE_DEVICE_TABLE(of, isl29018_of_match); + +static struct i2c_driver isl29018_driver = { + .driver = { + .name = "isl29018", + .acpi_match_table = ACPI_PTR(isl29018_acpi_match), + .pm = ISL29018_PM_OPS, + .of_match_table = isl29018_of_match, + }, + .probe = isl29018_probe, + .id_table = isl29018_id, +}; +module_i2c_driver(isl29018_driver); + +MODULE_DESCRIPTION("ISL29018 Ambient Light Sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig index 5e4e77ef7f98..dbf22d396ddf 100644 --- a/drivers/staging/iio/light/Kconfig +++ b/drivers/staging/iio/light/Kconfig @@ -3,18 +3,6 @@ # menu "Light sensors" -config SENSORS_ISL29018 - tristate "Intersil 29018 light and proximity sensor" - depends on I2C - select REGMAP_I2C - default n - help - If you say yes here you get support for ambient light sensing and - proximity infrared sensing from Intersil ISL29018. - This driver will provide the measurements of ambient light intensity - in lux, proximity infrared sensing and normal infrared sensing. - Data from sensor is accessible via sysfs. - config SENSORS_ISL29028 tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor" depends on I2C diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile index 9960fdf7c15b..6480856e1682 100644 --- a/drivers/staging/iio/light/Makefile +++ b/drivers/staging/iio/light/Makefile @@ -2,7 +2,6 @@ # Makefile for industrial I/O Light sensors # -obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o obj-$(CONFIG_TSL2583) += tsl2583.o obj-$(CONFIG_TSL2x7x) += tsl2x7x_core.o diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c deleted file mode 100644 index 917dd8b43e72..000000000000 --- a/drivers/staging/iio/light/isl29018.c +++ /dev/null @@ -1,847 +0,0 @@ -/* - * A iio driver for the light sensor ISL 29018/29023/29035. - * - * IIO driver for monitoring ambient light intensity in luxi, proximity - * sensing and infrared sensing. - * - * Copyright (c) 2010, NVIDIA Corporation. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ISL29018_CONV_TIME_MS 100 - -#define ISL29018_REG_ADD_COMMAND1 0x00 -#define ISL29018_CMD1_OPMODE_SHIFT 5 -#define ISL29018_CMD1_OPMODE_MASK (7 << ISL29018_CMD1_OPMODE_SHIFT) -#define ISL29018_CMD1_OPMODE_POWER_DOWN 0 -#define ISL29018_CMD1_OPMODE_ALS_ONCE 1 -#define ISL29018_CMD1_OPMODE_IR_ONCE 2 -#define ISL29018_CMD1_OPMODE_PROX_ONCE 3 - -#define ISL29018_REG_ADD_COMMAND2 0x01 -#define ISL29018_CMD2_RESOLUTION_SHIFT 2 -#define ISL29018_CMD2_RESOLUTION_MASK (0x3 << ISL29018_CMD2_RESOLUTION_SHIFT) - -#define ISL29018_CMD2_RANGE_SHIFT 0 -#define ISL29018_CMD2_RANGE_MASK (0x3 << ISL29018_CMD2_RANGE_SHIFT) - -#define ISL29018_CMD2_SCHEME_SHIFT 7 -#define ISL29018_CMD2_SCHEME_MASK (0x1 << ISL29018_CMD2_SCHEME_SHIFT) - -#define ISL29018_REG_ADD_DATA_LSB 0x02 -#define ISL29018_REG_ADD_DATA_MSB 0x03 - -#define ISL29018_REG_TEST 0x08 -#define ISL29018_TEST_SHIFT 0 -#define ISL29018_TEST_MASK (0xFF << ISL29018_TEST_SHIFT) - -#define ISL29035_REG_DEVICE_ID 0x0F -#define ISL29035_DEVICE_ID_SHIFT 0x03 -#define ISL29035_DEVICE_ID_MASK (0x7 << ISL29035_DEVICE_ID_SHIFT) -#define ISL29035_DEVICE_ID 0x5 -#define ISL29035_BOUT_SHIFT 0x07 -#define ISL29035_BOUT_MASK (0x01 << ISL29035_BOUT_SHIFT) - -enum isl29018_int_time { - ISL29018_INT_TIME_16, - ISL29018_INT_TIME_12, - ISL29018_INT_TIME_8, - ISL29018_INT_TIME_4, -}; - -static const unsigned int isl29018_int_utimes[3][4] = { - {90000, 5630, 351, 21}, - {90000, 5600, 352, 22}, - {105000, 6500, 410, 25}, -}; - -static const struct isl29018_scale { - unsigned int scale; - unsigned int uscale; -} isl29018_scales[4][4] = { - { {0, 15258}, {0, 61035}, {0, 244140}, {0, 976562} }, - { {0, 244140}, {0, 976562}, {3, 906250}, {15, 625000} }, - { {3, 906250}, {15, 625000}, {62, 500000}, {250, 0} }, - { {62, 500000}, {250, 0}, {1000, 0}, {4000, 0} } -}; - -struct isl29018_chip { - struct regmap *regmap; - struct mutex lock; - int type; - unsigned int calibscale; - unsigned int ucalibscale; - unsigned int int_time; - struct isl29018_scale scale; - int prox_scheme; - bool suspended; -}; - -static int isl29018_set_integration_time(struct isl29018_chip *chip, - unsigned int utime) -{ - unsigned int i; - int ret; - unsigned int int_time, new_int_time; - - for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) { - if (utime == isl29018_int_utimes[chip->type][i]) { - new_int_time = i; - break; - } - } - - if (i >= ARRAY_SIZE(isl29018_int_utimes[chip->type])) - return -EINVAL; - - ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2, - ISL29018_CMD2_RESOLUTION_MASK, - i << ISL29018_CMD2_RESOLUTION_SHIFT); - if (ret < 0) - return ret; - - /* Keep the same range when integration time changes */ - int_time = chip->int_time; - for (i = 0; i < ARRAY_SIZE(isl29018_scales[int_time]); ++i) { - if (chip->scale.scale == isl29018_scales[int_time][i].scale && - chip->scale.uscale == isl29018_scales[int_time][i].uscale) { - chip->scale = isl29018_scales[new_int_time][i]; - break; - } - } - chip->int_time = new_int_time; - - return 0; -} - -static int isl29018_set_scale(struct isl29018_chip *chip, int scale, int uscale) -{ - unsigned int i; - int ret; - struct isl29018_scale new_scale; - - for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) { - if (scale == isl29018_scales[chip->int_time][i].scale && - uscale == isl29018_scales[chip->int_time][i].uscale) { - new_scale = isl29018_scales[chip->int_time][i]; - break; - } - } - - if (i >= ARRAY_SIZE(isl29018_scales[chip->int_time])) - return -EINVAL; - - ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2, - ISL29018_CMD2_RANGE_MASK, - i << ISL29018_CMD2_RANGE_SHIFT); - if (ret < 0) - return ret; - - chip->scale = new_scale; - - return 0; -} - -static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode) -{ - int status; - unsigned int lsb; - unsigned int msb; - struct device *dev = regmap_get_device(chip->regmap); - - /* Set mode */ - status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, - mode << ISL29018_CMD1_OPMODE_SHIFT); - if (status) { - dev_err(dev, - "Error in setting operating mode err %d\n", status); - return status; - } - msleep(ISL29018_CONV_TIME_MS); - status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb); - if (status < 0) { - dev_err(dev, - "Error in reading LSB DATA with err %d\n", status); - return status; - } - - status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_MSB, &msb); - if (status < 0) { - dev_err(dev, - "Error in reading MSB DATA with error %d\n", status); - return status; - } - dev_vdbg(dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); - - return (msb << 8) | lsb; -} - -static int isl29018_read_lux(struct isl29018_chip *chip, int *lux) -{ - int lux_data; - unsigned int data_x_range; - - lux_data = isl29018_read_sensor_input(chip, - ISL29018_CMD1_OPMODE_ALS_ONCE); - if (lux_data < 0) - return lux_data; - - data_x_range = lux_data * chip->scale.scale + - lux_data * chip->scale.uscale / 1000000; - *lux = data_x_range * chip->calibscale + - data_x_range * chip->ucalibscale / 1000000; - - return 0; -} - -static int isl29018_read_ir(struct isl29018_chip *chip, int *ir) -{ - int ir_data; - - ir_data = isl29018_read_sensor_input(chip, - ISL29018_CMD1_OPMODE_IR_ONCE); - if (ir_data < 0) - return ir_data; - - *ir = ir_data; - - return 0; -} - -static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme, - int *near_ir) -{ - int status; - int prox_data = -1; - int ir_data = -1; - struct device *dev = regmap_get_device(chip->regmap); - - /* Do proximity sensing with required scheme */ - status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2, - ISL29018_CMD2_SCHEME_MASK, - scheme << ISL29018_CMD2_SCHEME_SHIFT); - if (status) { - dev_err(dev, "Error in setting operating mode\n"); - return status; - } - - prox_data = isl29018_read_sensor_input(chip, - ISL29018_CMD1_OPMODE_PROX_ONCE); - if (prox_data < 0) - return prox_data; - - if (scheme == 1) { - *near_ir = prox_data; - return 0; - } - - ir_data = isl29018_read_sensor_input(chip, - ISL29018_CMD1_OPMODE_IR_ONCE); - if (ir_data < 0) - return ir_data; - - if (prox_data >= ir_data) - *near_ir = prox_data - ir_data; - else - *near_ir = 0; - - return 0; -} - -static ssize_t in_illuminance_scale_available_show - (struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct isl29018_chip *chip = iio_priv(indio_dev); - unsigned int i; - int len = 0; - - mutex_lock(&chip->lock); - for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) - len += sprintf(buf + len, "%d.%06d ", - isl29018_scales[chip->int_time][i].scale, - isl29018_scales[chip->int_time][i].uscale); - mutex_unlock(&chip->lock); - - buf[len - 1] = '\n'; - - return len; -} - -static ssize_t in_illuminance_integration_time_available_show - (struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct isl29018_chip *chip = iio_priv(indio_dev); - unsigned int i; - int len = 0; - - for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) - len += sprintf(buf + len, "0.%06d ", - isl29018_int_utimes[chip->type][i]); - - buf[len - 1] = '\n'; - - return len; -} - -/* - * From ISL29018 Data Sheet (FN6619.4, Oct 8, 2012) regarding the - * infrared suppression: - * - * Proximity Sensing Scheme: Bit 7. This bit programs the function - * of the proximity detection. Logic 0 of this bit, Scheme 0, makes - * full n (4, 8, 12, 16) bits (unsigned) proximity detection. The range - * of Scheme 0 proximity count is from 0 to 2^n. Logic 1 of this bit, - * Scheme 1, makes n-1 (3, 7, 11, 15) bits (2's complementary) - * proximity_less_ambient detection. The range of Scheme 1 - * proximity count is from -2^(n-1) to 2^(n-1) . The sign bit is extended - * for resolutions less than 16. While Scheme 0 has wider dynamic - * range, Scheme 1 proximity detection is less affected by the - * ambient IR noise variation. - * - * 0 Sensing IR from LED and ambient - * 1 Sensing IR from LED with ambient IR rejection - */ -static ssize_t proximity_on_chip_ambient_infrared_suppression_show - (struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct isl29018_chip *chip = iio_priv(indio_dev); - - /* - * Return the "proximity scheme" i.e. if the chip does on chip - * infrared suppression (1 means perform on chip suppression) - */ - return sprintf(buf, "%d\n", chip->prox_scheme); -} - -static ssize_t proximity_on_chip_ambient_infrared_suppression_store - (struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct isl29018_chip *chip = iio_priv(indio_dev); - int val; - - if (kstrtoint(buf, 10, &val)) - return -EINVAL; - if (!(val == 0 || val == 1)) - return -EINVAL; - - /* - * Get the "proximity scheme" i.e. if the chip does on chip - * infrared suppression (1 means perform on chip suppression) - */ - mutex_lock(&chip->lock); - chip->prox_scheme = val; - mutex_unlock(&chip->lock); - - return count; -} - -static int isl29018_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct isl29018_chip *chip = iio_priv(indio_dev); - int ret = -EINVAL; - - mutex_lock(&chip->lock); - if (chip->suspended) { - ret = -EBUSY; - goto write_done; - } - switch (mask) { - case IIO_CHAN_INFO_CALIBSCALE: - if (chan->type == IIO_LIGHT) { - chip->calibscale = val; - chip->ucalibscale = val2; - ret = 0; - } - break; - case IIO_CHAN_INFO_INT_TIME: - if (chan->type == IIO_LIGHT && !val) - ret = isl29018_set_integration_time(chip, val2); - break; - case IIO_CHAN_INFO_SCALE: - if (chan->type == IIO_LIGHT) - ret = isl29018_set_scale(chip, val, val2); - break; - default: - break; - } - -write_done: - mutex_unlock(&chip->lock); - - return ret; -} - -static int isl29018_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - int ret = -EINVAL; - struct isl29018_chip *chip = iio_priv(indio_dev); - - mutex_lock(&chip->lock); - if (chip->suspended) { - ret = -EBUSY; - goto read_done; - } - switch (mask) { - case IIO_CHAN_INFO_RAW: - case IIO_CHAN_INFO_PROCESSED: - switch (chan->type) { - case IIO_LIGHT: - ret = isl29018_read_lux(chip, val); - break; - case IIO_INTENSITY: - ret = isl29018_read_ir(chip, val); - break; - case IIO_PROXIMITY: - ret = isl29018_read_proximity_ir(chip, - chip->prox_scheme, - val); - break; - default: - break; - } - if (!ret) - ret = IIO_VAL_INT; - break; - case IIO_CHAN_INFO_INT_TIME: - if (chan->type == IIO_LIGHT) { - *val = 0; - *val2 = isl29018_int_utimes[chip->type][chip->int_time]; - ret = IIO_VAL_INT_PLUS_MICRO; - } - break; - case IIO_CHAN_INFO_SCALE: - if (chan->type == IIO_LIGHT) { - *val = chip->scale.scale; - *val2 = chip->scale.uscale; - ret = IIO_VAL_INT_PLUS_MICRO; - } - break; - case IIO_CHAN_INFO_CALIBSCALE: - if (chan->type == IIO_LIGHT) { - *val = chip->calibscale; - *val2 = chip->ucalibscale; - ret = IIO_VAL_INT_PLUS_MICRO; - } - break; - default: - break; - } - -read_done: - mutex_unlock(&chip->lock); - - return ret; -} - -#define ISL29018_LIGHT_CHANNEL { \ - .type = IIO_LIGHT, \ - .indexed = 1, \ - .channel = 0, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \ - BIT(IIO_CHAN_INFO_CALIBSCALE) | \ - BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_INT_TIME), \ -} - -#define ISL29018_IR_CHANNEL { \ - .type = IIO_INTENSITY, \ - .modified = 1, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .channel2 = IIO_MOD_LIGHT_IR, \ -} - -#define ISL29018_PROXIMITY_CHANNEL { \ - .type = IIO_PROXIMITY, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ -} - -static const struct iio_chan_spec isl29018_channels[] = { - ISL29018_LIGHT_CHANNEL, - ISL29018_IR_CHANNEL, - ISL29018_PROXIMITY_CHANNEL, -}; - -static const struct iio_chan_spec isl29023_channels[] = { - ISL29018_LIGHT_CHANNEL, - ISL29018_IR_CHANNEL, -}; - -static IIO_DEVICE_ATTR_RO(in_illuminance_integration_time_available, 0); -static IIO_DEVICE_ATTR_RO(in_illuminance_scale_available, 0); -static IIO_DEVICE_ATTR_RW(proximity_on_chip_ambient_infrared_suppression, 0); - -#define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) - -static struct attribute *isl29018_attributes[] = { - ISL29018_DEV_ATTR(in_illuminance_scale_available), - ISL29018_DEV_ATTR(in_illuminance_integration_time_available), - ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_suppression), - NULL -}; - -static struct attribute *isl29023_attributes[] = { - ISL29018_DEV_ATTR(in_illuminance_scale_available), - ISL29018_DEV_ATTR(in_illuminance_integration_time_available), - NULL -}; - -static const struct attribute_group isl29018_group = { - .attrs = isl29018_attributes, -}; - -static const struct attribute_group isl29023_group = { - .attrs = isl29023_attributes, -}; - -enum { - isl29018, - isl29023, - isl29035, -}; - -static int isl29018_chip_init(struct isl29018_chip *chip) -{ - int status; - struct device *dev = regmap_get_device(chip->regmap); - - if (chip->type == isl29035) { - unsigned int id; - - status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id); - if (status < 0) { - dev_err(dev, - "Error reading ID register with error %d\n", - status); - return status; - } - - id = (id & ISL29035_DEVICE_ID_MASK) >> ISL29035_DEVICE_ID_SHIFT; - - if (id != ISL29035_DEVICE_ID) - return -ENODEV; - - /* Clear brownout bit */ - status = regmap_update_bits(chip->regmap, - ISL29035_REG_DEVICE_ID, - ISL29035_BOUT_MASK, 0); - if (status < 0) - return status; - } - - /* - * Code added per Intersil Application Note 1534: - * When VDD sinks to approximately 1.8V or below, some of - * the part's registers may change their state. When VDD - * recovers to 2.25V (or greater), the part may thus be in an - * unknown mode of operation. The user can return the part to - * a known mode of operation either by (a) setting VDD = 0V for - * 1 second or more and then powering back up with a slew rate - * of 0.5V/ms or greater, or (b) via I2C disable all ALS/PROX - * conversions, clear the test registers, and then rewrite all - * registers to the desired values. - * ... - * For ISL29011, ISL29018, ISL29021, ISL29023 - * 1. Write 0x00 to register 0x08 (TEST) - * 2. Write 0x00 to register 0x00 (CMD1) - * 3. Rewrite all registers to the desired values - * - * ISL29018 Data Sheet (FN6619.1, Feb 11, 2010) essentially says - * the same thing EXCEPT the data sheet asks for a 1ms delay after - * writing the CMD1 register. - */ - status = regmap_write(chip->regmap, ISL29018_REG_TEST, 0x0); - if (status < 0) { - dev_err(dev, "Failed to clear isl29018 TEST reg.(%d)\n", - status); - return status; - } - - /* - * See Intersil AN1534 comments above. - * "Operating Mode" (COMMAND1) register is reprogrammed when - * data is read from the device. - */ - status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 0); - if (status < 0) { - dev_err(dev, "Failed to clear isl29018 CMD1 reg.(%d)\n", - status); - return status; - } - - usleep_range(1000, 2000); /* per data sheet, page 10 */ - - /* Set defaults */ - status = isl29018_set_scale(chip, chip->scale.scale, - chip->scale.uscale); - if (status < 0) { - dev_err(dev, "Init of isl29018 fails\n"); - return status; - } - - status = isl29018_set_integration_time(chip, - isl29018_int_utimes[chip->type][chip->int_time]); - if (status < 0) - dev_err(dev, "Init of isl29018 fails\n"); - - return status; -} - -static const struct iio_info isl29018_info = { - .attrs = &isl29018_group, - .driver_module = THIS_MODULE, - .read_raw = isl29018_read_raw, - .write_raw = isl29018_write_raw, -}; - -static const struct iio_info isl29023_info = { - .attrs = &isl29023_group, - .driver_module = THIS_MODULE, - .read_raw = isl29018_read_raw, - .write_raw = isl29018_write_raw, -}; - -static bool isl29018_is_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case ISL29018_REG_ADD_DATA_LSB: - case ISL29018_REG_ADD_DATA_MSB: - case ISL29018_REG_ADD_COMMAND1: - case ISL29018_REG_TEST: - case ISL29035_REG_DEVICE_ID: - return true; - default: - return false; - } -} - -static const struct regmap_config isl29018_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .volatile_reg = isl29018_is_volatile_reg, - .max_register = ISL29018_REG_TEST, - .num_reg_defaults_raw = ISL29018_REG_TEST + 1, - .cache_type = REGCACHE_RBTREE, -}; - -static const struct regmap_config isl29035_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .volatile_reg = isl29018_is_volatile_reg, - .max_register = ISL29035_REG_DEVICE_ID, - .num_reg_defaults_raw = ISL29035_REG_DEVICE_ID + 1, - .cache_type = REGCACHE_RBTREE, -}; - -struct isl29018_chip_info { - const struct iio_chan_spec *channels; - int num_channels; - const struct iio_info *indio_info; - const struct regmap_config *regmap_cfg; -}; - -static const struct isl29018_chip_info isl29018_chip_info_tbl[] = { - [isl29018] = { - .channels = isl29018_channels, - .num_channels = ARRAY_SIZE(isl29018_channels), - .indio_info = &isl29018_info, - .regmap_cfg = &isl29018_regmap_config, - }, - [isl29023] = { - .channels = isl29023_channels, - .num_channels = ARRAY_SIZE(isl29023_channels), - .indio_info = &isl29023_info, - .regmap_cfg = &isl29018_regmap_config, - }, - [isl29035] = { - .channels = isl29023_channels, - .num_channels = ARRAY_SIZE(isl29023_channels), - .indio_info = &isl29023_info, - .regmap_cfg = &isl29035_regmap_config, - }, -}; - -static const char *isl29018_match_acpi_device(struct device *dev, int *data) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - - if (!id) - return NULL; - - *data = (int)id->driver_data; - - return dev_name(dev); -} - -static int isl29018_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct isl29018_chip *chip; - struct iio_dev *indio_dev; - int err; - const char *name = NULL; - int dev_id = 0; - - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); - if (!indio_dev) - return -ENOMEM; - - chip = iio_priv(indio_dev); - - i2c_set_clientdata(client, indio_dev); - - if (id) { - name = id->name; - dev_id = id->driver_data; - } - - if (ACPI_HANDLE(&client->dev)) - name = isl29018_match_acpi_device(&client->dev, &dev_id); - - mutex_init(&chip->lock); - - chip->type = dev_id; - chip->calibscale = 1; - chip->ucalibscale = 0; - chip->int_time = ISL29018_INT_TIME_16; - chip->scale = isl29018_scales[chip->int_time][0]; - chip->suspended = false; - - chip->regmap = devm_regmap_init_i2c(client, - isl29018_chip_info_tbl[dev_id].regmap_cfg); - if (IS_ERR(chip->regmap)) { - err = PTR_ERR(chip->regmap); - dev_err(&client->dev, "regmap initialization fails: %d\n", err); - return err; - } - - err = isl29018_chip_init(chip); - if (err) - return err; - - indio_dev->info = isl29018_chip_info_tbl[dev_id].indio_info; - indio_dev->channels = isl29018_chip_info_tbl[dev_id].channels; - indio_dev->num_channels = isl29018_chip_info_tbl[dev_id].num_channels; - indio_dev->name = name; - indio_dev->dev.parent = &client->dev; - indio_dev->modes = INDIO_DIRECT_MODE; - - return devm_iio_device_register(&client->dev, indio_dev); -} - -#ifdef CONFIG_PM_SLEEP -static int isl29018_suspend(struct device *dev) -{ - struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev)); - - mutex_lock(&chip->lock); - - /* - * Since this driver uses only polling commands, we are by default in - * auto shutdown (ie, power-down) mode. - * So we do not have much to do here. - */ - chip->suspended = true; - - mutex_unlock(&chip->lock); - - return 0; -} - -static int isl29018_resume(struct device *dev) -{ - struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev)); - int err; - - mutex_lock(&chip->lock); - - err = isl29018_chip_init(chip); - if (!err) - chip->suspended = false; - - mutex_unlock(&chip->lock); - - return err; -} - -static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume); -#define ISL29018_PM_OPS (&isl29018_pm_ops) -#else -#define ISL29018_PM_OPS NULL -#endif - -static const struct acpi_device_id isl29018_acpi_match[] = { - {"ISL29018", isl29018}, - {"ISL29023", isl29023}, - {"ISL29035", isl29035}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); - -static const struct i2c_device_id isl29018_id[] = { - {"isl29018", isl29018}, - {"isl29023", isl29023}, - {"isl29035", isl29035}, - {} -}; -MODULE_DEVICE_TABLE(i2c, isl29018_id); - -static const struct of_device_id isl29018_of_match[] = { - { .compatible = "isil,isl29018", }, - { .compatible = "isil,isl29023", }, - { .compatible = "isil,isl29035", }, - { }, -}; -MODULE_DEVICE_TABLE(of, isl29018_of_match); - -static struct i2c_driver isl29018_driver = { - .driver = { - .name = "isl29018", - .acpi_match_table = ACPI_PTR(isl29018_acpi_match), - .pm = ISL29018_PM_OPS, - .of_match_table = isl29018_of_match, - }, - .probe = isl29018_probe, - .id_table = isl29018_id, -}; -module_i2c_driver(isl29018_driver); - -MODULE_DESCRIPTION("ISL29018 Ambient Light Sensor driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e3ef7532a3d2aabec6aaff0b72db42a6ebf03ab6 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:01 +0100 Subject: staging:iio:accel:sca3000 Fix a use before setting of the indio_dev->buffer pointer. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000_ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index d1cb9b9cf22b..e5de52d05a5c 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -270,8 +270,8 @@ int sca3000_configure_ring(struct iio_dev *indio_dev) return -ENOMEM; indio_dev->modes |= INDIO_BUFFER_HARDWARE; - indio_dev->buffer->access = &sca3000_ring_access_funcs; + buffer->access = &sca3000_ring_access_funcs; iio_device_attach_buffer(indio_dev, buffer); return 0; -- cgit v1.2.3 From ced5c03d360aeebaac6faa7dd8d6d0a77733ab16 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:02 +0100 Subject: staging:iio:accel:sca3000 merge files into one. In the early days of IIO we were much more inclined to keep the impact of the core IIO elements to the minimum. As time has moved on it has become clear that hardly any builds are done without buffer support and that it adds considerable complexity to the drivers. Hence merge down the buffer and non buffer elements of the sca3000 driver also allowing us to drop the header file used for the interfaces between the two. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/Makefile | 1 - drivers/staging/iio/accel/sca3000.c | 1702 ++++++++++++++++++++++++++++++ drivers/staging/iio/accel/sca3000.h | 279 ----- drivers/staging/iio/accel/sca3000_core.c | 1210 --------------------- drivers/staging/iio/accel/sca3000_ring.c | 350 ------ 5 files changed, 1702 insertions(+), 1840 deletions(-) create mode 100644 drivers/staging/iio/accel/sca3000.c delete mode 100644 drivers/staging/iio/accel/sca3000.h delete mode 100644 drivers/staging/iio/accel/sca3000_core.c delete mode 100644 drivers/staging/iio/accel/sca3000_ring.c (limited to 'drivers') diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index 1810a434a755..1d49b6ab87ab 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -14,5 +14,4 @@ obj-$(CONFIG_ADIS16209) += adis16209.o adis16240-y := adis16240_core.o obj-$(CONFIG_ADIS16240) += adis16240.o -sca3000-y := sca3000_core.o sca3000_ring.o obj-$(CONFIG_SCA3000) += sca3000.o diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c new file mode 100644 index 000000000000..62ab1aef2528 --- /dev/null +++ b/drivers/staging/iio/accel/sca3000.c @@ -0,0 +1,1702 @@ +/* + * sca3000_core.c -- support VTI sca3000 series accelerometers via SPI + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * Copyright (c) 2009 Jonathan Cameron + * + * See industrialio/accels/sca3000.h for comments. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../ring_hw.h" + +#define SCA3000_WRITE_REG(a) (((a) << 2) | 0x02) +#define SCA3000_READ_REG(a) ((a) << 2) + +#define SCA3000_REG_ADDR_REVID 0x00 +#define SCA3000_REVID_MAJOR_MASK 0xf0 +#define SCA3000_REVID_MINOR_MASK 0x0f + +#define SCA3000_REG_ADDR_STATUS 0x02 +#define SCA3000_LOCKED 0x20 +#define SCA3000_EEPROM_CS_ERROR 0x02 +#define SCA3000_SPI_FRAME_ERROR 0x01 + +/* All reads done using register decrement so no need to directly access LSBs */ +#define SCA3000_REG_ADDR_X_MSB 0x05 +#define SCA3000_REG_ADDR_Y_MSB 0x07 +#define SCA3000_REG_ADDR_Z_MSB 0x09 + +#define SCA3000_REG_ADDR_RING_OUT 0x0f + +/* Temp read untested - the e05 doesn't have the sensor */ +#define SCA3000_REG_ADDR_TEMP_MSB 0x13 + +#define SCA3000_REG_ADDR_MODE 0x14 +#define SCA3000_MODE_PROT_MASK 0x28 + +#define SCA3000_RING_BUF_ENABLE 0x80 +#define SCA3000_RING_BUF_8BIT 0x40 +/* + * Free fall detection triggers an interrupt if the acceleration + * is below a threshold for equivalent of 25cm drop + */ +#define SCA3000_FREE_FALL_DETECT 0x10 +#define SCA3000_MEAS_MODE_NORMAL 0x00 +#define SCA3000_MEAS_MODE_OP_1 0x01 +#define SCA3000_MEAS_MODE_OP_2 0x02 + +/* + * In motion detection mode the accelerations are band pass filtered + * (approx 1 - 25Hz) and then a programmable threshold used to trigger + * and interrupt. + */ +#define SCA3000_MEAS_MODE_MOT_DET 0x03 + +#define SCA3000_REG_ADDR_BUF_COUNT 0x15 + +#define SCA3000_REG_ADDR_INT_STATUS 0x16 + +#define SCA3000_INT_STATUS_THREE_QUARTERS 0x80 +#define SCA3000_INT_STATUS_HALF 0x40 + +#define SCA3000_INT_STATUS_FREE_FALL 0x08 +#define SCA3000_INT_STATUS_Y_TRIGGER 0x04 +#define SCA3000_INT_STATUS_X_TRIGGER 0x02 +#define SCA3000_INT_STATUS_Z_TRIGGER 0x01 + +/* Used to allow access to multiplexed registers */ +#define SCA3000_REG_ADDR_CTRL_SEL 0x18 +/* Only available for SCA3000-D03 and SCA3000-D01 */ +#define SCA3000_REG_CTRL_SEL_I2C_DISABLE 0x01 +#define SCA3000_REG_CTRL_SEL_MD_CTRL 0x02 +#define SCA3000_REG_CTRL_SEL_MD_Y_TH 0x03 +#define SCA3000_REG_CTRL_SEL_MD_X_TH 0x04 +#define SCA3000_REG_CTRL_SEL_MD_Z_TH 0x05 +/* + * BE VERY CAREFUL WITH THIS, IF 3 BITS ARE NOT SET the device + * will not function + */ +#define SCA3000_REG_CTRL_SEL_OUT_CTRL 0x0B +#define SCA3000_OUT_CTRL_PROT_MASK 0xE0 +#define SCA3000_OUT_CTRL_BUF_X_EN 0x10 +#define SCA3000_OUT_CTRL_BUF_Y_EN 0x08 +#define SCA3000_OUT_CTRL_BUF_Z_EN 0x04 +#define SCA3000_OUT_CTRL_BUF_DIV_MASK 0x03 +#define SCA3000_OUT_CTRL_BUF_DIV_4 0x02 +#define SCA3000_OUT_CTRL_BUF_DIV_2 0x01 + +/* + * Control which motion detector interrupts are on. + * For now only OR combinations are supported. + */ +#define SCA3000_MD_CTRL_PROT_MASK 0xC0 +#define SCA3000_MD_CTRL_OR_Y 0x01 +#define SCA3000_MD_CTRL_OR_X 0x02 +#define SCA3000_MD_CTRL_OR_Z 0x04 +/* Currently unsupported */ +#define SCA3000_MD_CTRL_AND_Y 0x08 +#define SCA3000_MD_CTRL_AND_X 0x10 +#define SAC3000_MD_CTRL_AND_Z 0x20 + +/* + * Some control registers of complex access methods requiring this register to + * be used to remove a lock. + */ +#define SCA3000_REG_ADDR_UNLOCK 0x1e + +#define SCA3000_REG_ADDR_INT_MASK 0x21 +#define SCA3000_INT_MASK_PROT_MASK 0x1C + +#define SCA3000_INT_MASK_RING_THREE_QUARTER 0x80 +#define SCA3000_INT_MASK_RING_HALF 0x40 + +#define SCA3000_INT_MASK_ALL_INTS 0x02 +#define SCA3000_INT_MASK_ACTIVE_HIGH 0x01 +#define SCA3000_INT_MASK_ACTIVE_LOW 0x00 + +/* Values of multiplexed registers (write to ctrl_data after select) */ +#define SCA3000_REG_ADDR_CTRL_DATA 0x22 + +/* + * Measurement modes available on some sca3000 series chips. Code assumes others + * may become available in the future. + * + * Bypass - Bypass the low-pass filter in the signal channel so as to increase + * signal bandwidth. + * + * Narrow - Narrow low-pass filtering of the signal channel and half output + * data rate by decimation. + * + * Wide - Widen low-pass filtering of signal channel to increase bandwidth + */ +#define SCA3000_OP_MODE_BYPASS 0x01 +#define SCA3000_OP_MODE_NARROW 0x02 +#define SCA3000_OP_MODE_WIDE 0x04 +#define SCA3000_MAX_TX 6 +#define SCA3000_MAX_RX 2 + +/** + * struct sca3000_state - device instance state information + * @us: the associated spi device + * @info: chip variant information + * @interrupt_handler_ws: event interrupt handler for all events + * @last_timestamp: the timestamp of the last event + * @mo_det_use_count: reference counter for the motion detection unit + * @lock: lock used to protect elements of sca3000_state + * and the underlying device state. + * @bpse: number of bits per scan element + * @tx: dma-able transmit buffer + * @rx: dma-able receive buffer + **/ +struct sca3000_state { + struct spi_device *us; + const struct sca3000_chip_info *info; + struct work_struct interrupt_handler_ws; + s64 last_timestamp; + int mo_det_use_count; + struct mutex lock; + int bpse; + /* Can these share a cacheline ? */ + u8 rx[2] ____cacheline_aligned; + u8 tx[6] ____cacheline_aligned; +}; + +/** + * struct sca3000_chip_info - model dependent parameters + * @scale: scale * 10^-6 + * @temp_output: some devices have temperature sensors. + * @measurement_mode_freq: normal mode sampling frequency + * @option_mode_1: first optional mode. Not all models have one + * @option_mode_1_freq: option mode 1 sampling frequency + * @option_mode_2: second optional mode. Not all chips have one + * @option_mode_2_freq: option mode 2 sampling frequency + * + * This structure is used to hold information about the functionality of a given + * sca3000 variant. + **/ +struct sca3000_chip_info { + unsigned int scale; + bool temp_output; + int measurement_mode_freq; + int option_mode_1; + int option_mode_1_freq; + int option_mode_2; + int option_mode_2_freq; + int mot_det_mult_xz[6]; + int mot_det_mult_y[7]; +}; + +enum sca3000_variant { + d01, + e02, + e04, + e05, +}; + +/* + * Note where option modes are not defined, the chip simply does not + * support any. + * Other chips in the sca3000 series use i2c and are not included here. + * + * Some of these devices are only listed in the family data sheet and + * do not actually appear to be available. + */ +static const struct sca3000_chip_info sca3000_spi_chip_info_tbl[] = { + [d01] = { + .scale = 7357, + .temp_output = true, + .measurement_mode_freq = 250, + .option_mode_1 = SCA3000_OP_MODE_BYPASS, + .option_mode_1_freq = 250, + .mot_det_mult_xz = {50, 100, 200, 350, 650, 1300}, + .mot_det_mult_y = {50, 100, 150, 250, 450, 850, 1750}, + }, + [e02] = { + .scale = 9810, + .measurement_mode_freq = 125, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 63, + .mot_det_mult_xz = {100, 150, 300, 550, 1050, 2050}, + .mot_det_mult_y = {50, 100, 200, 350, 700, 1350, 2700}, + }, + [e04] = { + .scale = 19620, + .measurement_mode_freq = 100, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 50, + .option_mode_2 = SCA3000_OP_MODE_WIDE, + .option_mode_2_freq = 400, + .mot_det_mult_xz = {200, 300, 600, 1100, 2100, 4100}, + .mot_det_mult_y = {100, 200, 400, 7000, 1400, 2700, 54000}, + }, + [e05] = { + .scale = 61313, + .measurement_mode_freq = 200, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 50, + .option_mode_2 = SCA3000_OP_MODE_WIDE, + .option_mode_2_freq = 400, + .mot_det_mult_xz = {600, 900, 1700, 3200, 6100, 11900}, + .mot_det_mult_y = {300, 600, 1200, 2000, 4100, 7800, 15600}, + }, +}; + +static int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val) +{ + st->tx[0] = SCA3000_WRITE_REG(address); + st->tx[1] = val; + return spi_write(st->us, st->tx, 2); +} + +static int sca3000_read_data_short(struct sca3000_state *st, + u8 reg_address_high, + int len) +{ + struct spi_transfer xfer[2] = { + { + .len = 1, + .tx_buf = st->tx, + }, { + .len = len, + .rx_buf = st->rx, + } + }; + st->tx[0] = SCA3000_READ_REG(reg_address_high); + + return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); +} + +/** + * sca3000_reg_lock_on() test if the ctrl register lock is on + * + * Lock must be held. + **/ +static int sca3000_reg_lock_on(struct sca3000_state *st) +{ + int ret; + + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_STATUS, 1); + if (ret < 0) + return ret; + + return !(st->rx[0] & SCA3000_LOCKED); +} + +/** + * __sca3000_unlock_reg_lock() unlock the control registers + * + * Note the device does not appear to support doing this in a single transfer. + * This should only ever be used as part of ctrl reg read. + * Lock must be held before calling this + **/ +static int __sca3000_unlock_reg_lock(struct sca3000_state *st) +{ + struct spi_transfer xfer[3] = { + { + .len = 2, + .cs_change = 1, + .tx_buf = st->tx, + }, { + .len = 2, + .cs_change = 1, + .tx_buf = st->tx + 2, + }, { + .len = 2, + .tx_buf = st->tx + 4, + }, + }; + st->tx[0] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); + st->tx[1] = 0x00; + st->tx[2] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); + st->tx[3] = 0x50; + st->tx[4] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); + st->tx[5] = 0xA0; + + return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); +} + +/** + * sca3000_write_ctrl_reg() write to a lock protect ctrl register + * @sel: selects which registers we wish to write to + * @val: the value to be written + * + * Certain control registers are protected against overwriting by the lock + * register and use a shared write address. This function allows writing of + * these registers. + * Lock must be held. + **/ +static int sca3000_write_ctrl_reg(struct sca3000_state *st, + u8 sel, + uint8_t val) +{ + int ret; + + ret = sca3000_reg_lock_on(st); + if (ret < 0) + goto error_ret; + if (ret) { + ret = __sca3000_unlock_reg_lock(st); + if (ret) + goto error_ret; + } + + /* Set the control select register */ + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_SEL, sel); + if (ret) + goto error_ret; + + /* Write the actual value into the register */ + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_DATA, val); + +error_ret: + return ret; +} + +/** + * sca3000_read_ctrl_reg() read from lock protected control register. + * + * Lock must be held. + **/ +static int sca3000_read_ctrl_reg(struct sca3000_state *st, + u8 ctrl_reg) +{ + int ret; + + ret = sca3000_reg_lock_on(st); + if (ret < 0) + goto error_ret; + if (ret) { + ret = __sca3000_unlock_reg_lock(st); + if (ret) + goto error_ret; + } + /* Set the control select register */ + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_SEL, ctrl_reg); + if (ret) + goto error_ret; + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_CTRL_DATA, 1); + if (ret) + goto error_ret; + return st->rx[0]; +error_ret: + return ret; +} + +/** + * sca3000_show_rev() - sysfs interface to read the chip revision number + **/ +static ssize_t sca3000_show_rev(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int len = 0, ret; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_REVID, 1); + if (ret < 0) + goto error_ret; + len += sprintf(buf + len, + "major=%d, minor=%d\n", + st->rx[0] & SCA3000_REVID_MAJOR_MASK, + st->rx[0] & SCA3000_REVID_MINOR_MASK); +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +/** + * sca3000_show_available_measurement_modes() display available modes + * + * This is all read from chip specific data in the driver. Not all + * of the sca3000 series support modes other than normal. + **/ +static ssize_t +sca3000_show_available_measurement_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + int len = 0; + + len += sprintf(buf + len, "0 - normal mode"); + switch (st->info->option_mode_1) { + case SCA3000_OP_MODE_NARROW: + len += sprintf(buf + len, ", 1 - narrow mode"); + break; + 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"); + break; + } + /* always supported */ + len += sprintf(buf + len, " 3 - motion detection\n"); + + return len; +} + +/** + * sca3000_show_measurement_mode() sysfs read of current mode + **/ +static ssize_t +sca3000_show_measurement_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + int len = 0, ret; + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + if (ret) + goto error_ret; + /* mask bottom 2 bits - only ones that are relevant */ + st->rx[0] &= 0x03; + switch (st->rx[0]) { + case SCA3000_MEAS_MODE_NORMAL: + len += sprintf(buf + len, "0 - normal mode\n"); + break; + case SCA3000_MEAS_MODE_MOT_DET: + len += sprintf(buf + len, "3 - motion detection\n"); + break; + case SCA3000_MEAS_MODE_OP_1: + switch (st->info->option_mode_1) { + case SCA3000_OP_MODE_NARROW: + len += sprintf(buf + len, "1 - narrow mode\n"); + break; + 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) { + case SCA3000_OP_MODE_WIDE: + len += sprintf(buf + len, "2 - wide mode\n"); + break; + } + break; + } + +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +/** + * sca3000_store_measurement_mode() set the current mode + **/ +static ssize_t +sca3000_store_measurement_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + u8 mask = 0x03; + u8 val; + + mutex_lock(&st->lock); + ret = kstrtou8(buf, 10, &val); + if (ret) + goto error_ret; + if (val > 3) { + ret = -EINVAL; + goto error_ret; + } + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + if (ret) + goto error_ret; + st->rx[0] &= ~mask; + st->rx[0] |= (val & mask); + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, st->rx[0]); + if (ret) + goto error_ret; + mutex_unlock(&st->lock); + + return len; + +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + +/* + * Not even vaguely standard attributes so defined here rather than + * in the relevant IIO core headers + */ +static IIO_DEVICE_ATTR(measurement_mode_available, S_IRUGO, + sca3000_show_available_measurement_modes, + NULL, 0); + +static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR, + sca3000_show_measurement_mode, + sca3000_store_measurement_mode, + 0); + +/* More standard attributes */ + +static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0); + +static const struct iio_event_spec sca3000_event = { + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), +}; + +#define SCA3000_CHAN(index, mod) \ + { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = mod, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + .address = index, \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 11, \ + .storagebits = 16, \ + .shift = 5, \ + }, \ + .event_spec = &sca3000_event, \ + .num_event_specs = 1, \ + } + +static const struct iio_chan_spec sca3000_channels[] = { + SCA3000_CHAN(0, IIO_MOD_X), + SCA3000_CHAN(1, IIO_MOD_Y), + SCA3000_CHAN(2, IIO_MOD_Z), +}; + +static const struct iio_chan_spec sca3000_channels_with_temp[] = { + SCA3000_CHAN(0, IIO_MOD_X), + SCA3000_CHAN(1, IIO_MOD_Y), + SCA3000_CHAN(2, IIO_MOD_Z), + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + /* No buffer support */ + .scan_index = -1, + }, +}; + +static u8 sca3000_addresses[3][3] = { + [0] = {SCA3000_REG_ADDR_X_MSB, SCA3000_REG_CTRL_SEL_MD_X_TH, + SCA3000_MD_CTRL_OR_X}, + [1] = {SCA3000_REG_ADDR_Y_MSB, SCA3000_REG_CTRL_SEL_MD_Y_TH, + SCA3000_MD_CTRL_OR_Y}, + [2] = {SCA3000_REG_ADDR_Z_MSB, SCA3000_REG_CTRL_SEL_MD_Z_TH, + SCA3000_MD_CTRL_OR_Z}, +}; + +/** + * __sca3000_get_base_freq() obtain mode specific base frequency + * + * lock must be held + **/ +static inline int __sca3000_get_base_freq(struct sca3000_state *st, + const struct sca3000_chip_info *info, + int *base_freq) +{ + int ret; + + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + if (ret) + goto error_ret; + switch (0x03 & st->rx[0]) { + case SCA3000_MEAS_MODE_NORMAL: + *base_freq = info->measurement_mode_freq; + break; + case SCA3000_MEAS_MODE_OP_1: + *base_freq = info->option_mode_1_freq; + break; + case SCA3000_MEAS_MODE_OP_2: + *base_freq = info->option_mode_2_freq; + break; + default: + ret = -EINVAL; + } +error_ret: + return ret; +} + +/** + * read_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * + * lock must be held + **/ +static int read_raw_samp_freq(struct sca3000_state *st, int *val) +{ + int ret; + + ret = __sca3000_get_base_freq(st, st->info, val); + if (ret) + return ret; + + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); + if (ret < 0) + return ret; + + if (*val > 0) { + ret &= SCA3000_OUT_CTRL_BUF_DIV_MASK; + switch (ret) { + case SCA3000_OUT_CTRL_BUF_DIV_2: + *val /= 2; + break; + case SCA3000_OUT_CTRL_BUF_DIV_4: + *val /= 4; + break; + } + } + + return 0; +} + +/** + * write_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * + * lock must be held + **/ +static int write_raw_samp_freq(struct sca3000_state *st, int val) +{ + int ret, base_freq, ctrlval; + + ret = __sca3000_get_base_freq(st, st->info, &base_freq); + if (ret) + return ret; + + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); + if (ret < 0) + return ret; + + ctrlval = ret & ~SCA3000_OUT_CTRL_BUF_DIV_MASK; + + if (val == base_freq / 2) + ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_2; + if (val == base_freq / 4) + ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_4; + else if (val != base_freq) + return -EINVAL; + + return sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, + ctrlval); +} + +static int sca3000_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + u8 address; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&st->lock); + if (chan->type == IIO_ACCEL) { + if (st->mo_det_use_count) { + mutex_unlock(&st->lock); + return -EBUSY; + } + address = sca3000_addresses[chan->address][0]; + ret = sca3000_read_data_short(st, address, 2); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } + *val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF; + *val = ((*val) << (sizeof(*val) * 8 - 13)) >> + (sizeof(*val) * 8 - 13); + } else { + /* get the temperature when available */ + ret = sca3000_read_data_short(st, + SCA3000_REG_ADDR_TEMP_MSB, + 2); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } + *val = ((st->rx[0] & 0x3F) << 3) | + ((st->rx[1] & 0xE0) >> 5); + } + mutex_unlock(&st->lock); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + if (chan->type == IIO_ACCEL) + *val2 = st->info->scale; + else /* temperature */ + *val2 = 555556; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = -214; + *val2 = 600000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&st->lock); + ret = read_raw_samp_freq(st, val); + mutex_unlock(&st->lock); + return ret ? ret : IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int sca3000_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) + return -EINVAL; + mutex_lock(&st->lock); + ret = write_raw_samp_freq(st, val); + mutex_unlock(&st->lock); + return ret; + default: + return -EINVAL; + } + + return ret; +} + +/** + * sca3000_read_av_freq() sysfs function to get available frequencies + * + * The later modes are only relevant to the ring buffer - and depend on current + * mode. Note that data sheet gives rather wide tolerances for these so integer + * division will give good enough answer and not all chips have them specified + * at all. + **/ +static ssize_t sca3000_read_av_freq(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + int len = 0, ret, val; + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + val = st->rx[0]; + mutex_unlock(&st->lock); + if (ret) + goto error_ret; + + switch (val & 0x03) { + case SCA3000_MEAS_MODE_NORMAL: + len += sprintf(buf + len, "%d %d %d\n", + st->info->measurement_mode_freq, + st->info->measurement_mode_freq / 2, + st->info->measurement_mode_freq / 4); + break; + case SCA3000_MEAS_MODE_OP_1: + len += sprintf(buf + len, "%d %d %d\n", + st->info->option_mode_1_freq, + st->info->option_mode_1_freq / 2, + st->info->option_mode_1_freq / 4); + break; + case SCA3000_MEAS_MODE_OP_2: + len += sprintf(buf + len, "%d %d %d\n", + st->info->option_mode_2_freq, + st->info->option_mode_2_freq / 2, + st->info->option_mode_2_freq / 4); + break; + } + return len; +error_ret: + return ret; +} + +/* + * Should only really be registered if ring buffer support is compiled in. + * Does no harm however and doing it right would add a fair bit of complexity + */ +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sca3000_read_av_freq); + +/** + * sca3000_read_thresh() - query of a threshold + **/ +static int sca3000_read_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + int ret, i; + struct sca3000_state *st = iio_priv(indio_dev); + int num = chan->channel2; + + mutex_lock(&st->lock); + ret = sca3000_read_ctrl_reg(st, sca3000_addresses[num][1]); + mutex_unlock(&st->lock); + if (ret < 0) + return ret; + *val = 0; + if (num == 1) + for_each_set_bit(i, (unsigned long *)&ret, + ARRAY_SIZE(st->info->mot_det_mult_y)) + *val += st->info->mot_det_mult_y[i]; + else + for_each_set_bit(i, (unsigned long *)&ret, + ARRAY_SIZE(st->info->mot_det_mult_xz)) + *val += st->info->mot_det_mult_xz[i]; + + return IIO_VAL_INT; +} + +/** + * sca3000_write_thresh() control of threshold + **/ +static int sca3000_write_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int num = chan->channel2; + int ret; + int i; + u8 nonlinear = 0; + + if (num == 1) { + i = ARRAY_SIZE(st->info->mot_det_mult_y); + while (i > 0) + if (val >= st->info->mot_det_mult_y[--i]) { + nonlinear |= (1 << i); + val -= st->info->mot_det_mult_y[i]; + } + } else { + i = ARRAY_SIZE(st->info->mot_det_mult_xz); + while (i > 0) + if (val >= st->info->mot_det_mult_xz[--i]) { + nonlinear |= (1 << i); + val -= st->info->mot_det_mult_xz[i]; + } + } + + mutex_lock(&st->lock); + ret = sca3000_write_ctrl_reg(st, sca3000_addresses[num][1], nonlinear); + mutex_unlock(&st->lock); + + return ret; +} + +static struct attribute *sca3000_attributes[] = { + &iio_dev_attr_revision.dev_attr.attr, + &iio_dev_attr_measurement_mode_available.dev_attr.attr, + &iio_dev_attr_measurement_mode.dev_attr.attr, + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group sca3000_attribute_group = { + .attrs = sca3000_attributes, +}; + +/** + * sca3000_ring_int_process() ring specific interrupt handling. + * + * This is only split from the main interrupt handler so as to + * reduce the amount of code if the ring buffer is not enabled. + **/ +static void sca3000_ring_int_process(u8 val, struct iio_buffer *ring) +{ + if (val & (SCA3000_INT_STATUS_THREE_QUARTERS | + SCA3000_INT_STATUS_HALF)) { + ring->stufftoread = true; + wake_up_interruptible(&ring->pollq); + } +} + +/** + * sca3000_event_handler() - handling ring and non ring events + * + * Ring related interrupt handler. Depending on event, push to + * the ring buffer event chrdev or the event one. + * + * This function is complicated by the fact that the devices can signify ring + * and non ring events via the same interrupt line and they can only + * be distinguished via a read of the relevant status register. + **/ +static irqreturn_t sca3000_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct sca3000_state *st = iio_priv(indio_dev); + int ret, val; + s64 last_timestamp = iio_get_time_ns(indio_dev); + + /* + * Could lead if badly timed to an extra read of status reg, + * but ensures no interrupt is missed. + */ + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_STATUS, 1); + val = st->rx[0]; + mutex_unlock(&st->lock); + if (ret) + goto done; + + sca3000_ring_int_process(val, indio_dev->buffer); + + if (val & SCA3000_INT_STATUS_FREE_FALL) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_FALLING), + last_timestamp); + + if (val & SCA3000_INT_STATUS_Y_TRIGGER) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Y, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + last_timestamp); + + if (val & SCA3000_INT_STATUS_X_TRIGGER) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + last_timestamp); + + if (val & SCA3000_INT_STATUS_Z_TRIGGER) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + last_timestamp); + +done: + return IRQ_HANDLED; +} + +/** + * sca3000_read_event_config() what events are enabled + **/ +static int sca3000_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + u8 protect_mask = 0x03; + int num = chan->channel2; + + /* read current value of mode register */ + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + if (ret) + goto error_ret; + + if ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET) { + ret = 0; + } else { + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); + if (ret < 0) + goto error_ret; + /* only supporting logical or's for now */ + ret = !!(ret & sca3000_addresses[num][2]); + } +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + +/** + * sca3000_query_free_fall_mode() is free fall mode enabled + **/ +static ssize_t sca3000_query_free_fall_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + int val; + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + val = st->rx[0]; + mutex_unlock(&st->lock); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", !!(val & SCA3000_FREE_FALL_DETECT)); +} + +/** + * sca3000_set_free_fall_mode() simple on off control for free fall int + * + * In these chips the free fall detector should send an interrupt if + * the device falls more than 25cm. This has not been tested due + * to fragile wiring. + **/ +static ssize_t sca3000_set_free_fall_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + u8 val; + int ret; + u8 protect_mask = SCA3000_FREE_FALL_DETECT; + + mutex_lock(&st->lock); + ret = kstrtou8(buf, 10, &val); + if (ret) + goto error_ret; + + /* read current value of mode register */ + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + if (ret) + goto error_ret; + + /* if off and should be on */ + if (val && !(st->rx[0] & protect_mask)) + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + (st->rx[0] | SCA3000_FREE_FALL_DETECT)); + /* if on and should be off */ + else if (!val && (st->rx[0] & protect_mask)) + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + (st->rx[0] & ~protect_mask)); +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +/** + * sca3000_write_event_config() simple on off control for motion detector + * + * This is a per axis control, but enabling any will result in the + * motion detector unit being enabled. + * N.B. enabling motion detector stops normal data acquisition. + * There is a complexity in knowing which mode to return to when + * this mode is disabled. Currently normal mode is assumed. + **/ +static int sca3000_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret, ctrlval; + u8 protect_mask = 0x03; + int num = chan->channel2; + + mutex_lock(&st->lock); + /* + * First read the motion detector config to find out if + * this axis is on + */ + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); + if (ret < 0) + goto exit_point; + ctrlval = ret; + /* if off and should be on */ + if (state && !(ctrlval & sca3000_addresses[num][2])) { + ret = sca3000_write_ctrl_reg(st, + SCA3000_REG_CTRL_SEL_MD_CTRL, + ctrlval | + sca3000_addresses[num][2]); + if (ret) + goto exit_point; + st->mo_det_use_count++; + } else if (!state && (ctrlval & sca3000_addresses[num][2])) { + ret = sca3000_write_ctrl_reg(st, + SCA3000_REG_CTRL_SEL_MD_CTRL, + ctrlval & + ~(sca3000_addresses[num][2])); + if (ret) + goto exit_point; + st->mo_det_use_count--; + } + + /* read current value of mode register */ + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + if (ret) + goto exit_point; + /* if off and should be on */ + if ((st->mo_det_use_count) && + ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET)) + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + (st->rx[0] & ~protect_mask) + | SCA3000_MEAS_MODE_MOT_DET); + /* if on and should be off */ + else if (!(st->mo_det_use_count) && + ((st->rx[0] & protect_mask) == SCA3000_MEAS_MODE_MOT_DET)) + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + (st->rx[0] & ~protect_mask)); +exit_point: + mutex_unlock(&st->lock); + + return ret; +} + +/* Free fall detector related event attribute */ +static IIO_DEVICE_ATTR_NAMED(accel_xayaz_mag_falling_en, + in_accel_x & y & z_mag_falling_en, + S_IRUGO | S_IWUSR, + sca3000_query_free_fall_mode, + sca3000_set_free_fall_mode, + 0); + +static IIO_CONST_ATTR_NAMED(accel_xayaz_mag_falling_period, + in_accel_x & y & z_mag_falling_period, + "0.226"); + +static struct attribute *sca3000_event_attributes[] = { + &iio_dev_attr_accel_xayaz_mag_falling_en.dev_attr.attr, + &iio_const_attr_accel_xayaz_mag_falling_period.dev_attr.attr, + NULL, +}; + +static struct attribute_group sca3000_event_attribute_group = { + .attrs = sca3000_event_attributes, + .name = "events", +}; + +static int sca3000_read_data(struct sca3000_state *st, + u8 reg_address_high, + u8 **rx_p, + int len) +{ + int ret; + struct spi_transfer xfer[2] = { + { + .len = 1, + .tx_buf = st->tx, + }, { + .len = len, + } + }; + *rx_p = kmalloc(len, GFP_KERNEL); + if (!*rx_p) { + ret = -ENOMEM; + goto error_ret; + } + xfer[1].rx_buf = *rx_p; + st->tx[0] = SCA3000_READ_REG(reg_address_high); + ret = spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); + if (ret) { + dev_err(get_device(&st->us->dev), "problem reading register"); + goto error_free_rx; + } + + return 0; +error_free_rx: + kfree(*rx_p); +error_ret: + return ret; +} + +/** + * sca3000_read_first_n_hw_rb() - main ring access, pulls data from ring + * @r: the ring + * @count: number of samples to try and pull + * @data: output the actual samples pulled from the hw ring + * + * Currently does not provide timestamps. As the hardware doesn't add them they + * can only be inferred approximately from ring buffer events such as 50% full + * and knowledge of when buffer was last emptied. This is left to userspace. + **/ +static int sca3000_read_first_n_hw_rb(struct iio_buffer *r, + size_t count, char __user *buf) +{ + struct iio_hw_buffer *hw_ring = iio_to_hw_buf(r); + struct iio_dev *indio_dev = hw_ring->private; + struct sca3000_state *st = iio_priv(indio_dev); + u8 *rx; + int ret, i, num_available, num_read = 0; + int bytes_per_sample = 1; + + if (st->bpse == 11) + bytes_per_sample = 2; + + mutex_lock(&st->lock); + if (count % bytes_per_sample) { + ret = -EINVAL; + goto error_ret; + } + + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_BUF_COUNT, 1); + if (ret) + goto error_ret; + num_available = st->rx[0]; + /* + * num_available is the total number of samples available + * i.e. number of time points * number of channels. + */ + if (count > num_available * bytes_per_sample) + num_read = num_available * bytes_per_sample; + else + num_read = count; + + ret = sca3000_read_data(st, + SCA3000_REG_ADDR_RING_OUT, + &rx, num_read); + if (ret) + goto error_ret; + + for (i = 0; i < num_read / sizeof(u16); i++) + *(((u16 *)rx) + i) = be16_to_cpup((__be16 *)rx + i); + + if (copy_to_user(buf, rx, num_read)) + ret = -EFAULT; + kfree(rx); + r->stufftoread = 0; +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : num_read; +} + +static size_t sca3000_ring_buf_data_available(struct iio_buffer *r) +{ + return r->stufftoread ? r->watermark : 0; +} + +/** + * sca3000_query_ring_int() is the hardware ring status interrupt enabled + **/ +static ssize_t sca3000_query_ring_int(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret, val; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); + val = st->rx[0]; + mutex_unlock(&st->lock); + if (ret) + return ret; + + return sprintf(buf, "%d\n", !!(val & this_attr->address)); +} + +/** + * sca3000_set_ring_int() set state of ring status interrupt + **/ +static ssize_t sca3000_set_ring_int(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + u8 val; + int ret; + + mutex_lock(&st->lock); + ret = kstrtou8(buf, 10, &val); + if (ret) + goto error_ret; + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); + if (ret) + goto error_ret; + if (val) + ret = sca3000_write_reg(st, + SCA3000_REG_ADDR_INT_MASK, + st->rx[0] | this_attr->address); + else + ret = sca3000_write_reg(st, + SCA3000_REG_ADDR_INT_MASK, + st->rx[0] & ~this_attr->address); +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static IIO_DEVICE_ATTR(50_percent, S_IRUGO | S_IWUSR, + sca3000_query_ring_int, + sca3000_set_ring_int, + SCA3000_INT_MASK_RING_HALF); + +static IIO_DEVICE_ATTR(75_percent, S_IRUGO | S_IWUSR, + sca3000_query_ring_int, + sca3000_set_ring_int, + SCA3000_INT_MASK_RING_THREE_QUARTER); + +static ssize_t sca3000_show_buffer_scale(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + + return sprintf(buf, "0.%06d\n", 4 * st->info->scale); +} + +static IIO_DEVICE_ATTR(in_accel_scale, + S_IRUGO, + sca3000_show_buffer_scale, + NULL, + 0); + +/* + * Ring buffer attributes + * This device is a bit unusual in that the sampling frequency and bpse + * only apply to the ring buffer. At all times full rate and accuracy + * is available via direct reading from registers. + */ +static const struct attribute *sca3000_ring_attributes[] = { + &iio_dev_attr_50_percent.dev_attr.attr, + &iio_dev_attr_75_percent.dev_attr.attr, + &iio_dev_attr_in_accel_scale.dev_attr.attr, + NULL, +}; + +static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev) +{ + struct iio_buffer *buf; + struct iio_hw_buffer *ring; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) + return NULL; + + ring->private = indio_dev; + buf = &ring->buf; + buf->stufftoread = 0; + buf->length = 64; + buf->attrs = sca3000_ring_attributes; + iio_buffer_init(buf); + + return buf; +} + +static void sca3000_ring_release(struct iio_buffer *r) +{ + kfree(iio_to_hw_buf(r)); +} + +static const struct iio_buffer_access_funcs sca3000_ring_access_funcs = { + .read_first_n = &sca3000_read_first_n_hw_rb, + .data_available = sca3000_ring_buf_data_available, + .release = sca3000_ring_release, + + .modes = INDIO_BUFFER_HARDWARE, +}; + +static int sca3000_configure_ring(struct iio_dev *indio_dev) +{ + struct iio_buffer *buffer; + + buffer = sca3000_rb_allocate(indio_dev); + if (!buffer) + return -ENOMEM; + indio_dev->modes |= INDIO_BUFFER_HARDWARE; + + buffer->access = &sca3000_ring_access_funcs; + iio_device_attach_buffer(indio_dev, buffer); + + return 0; +} + +static void sca3000_unconfigure_ring(struct iio_dev *indio_dev) +{ + iio_buffer_put(indio_dev->buffer); +} + +static inline +int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + if (ret) + goto error_ret; + if (state) { + dev_info(&indio_dev->dev, "supposedly enabling ring buffer\n"); + ret = sca3000_write_reg(st, + SCA3000_REG_ADDR_MODE, + (st->rx[0] | SCA3000_RING_BUF_ENABLE)); + } else + ret = sca3000_write_reg(st, + SCA3000_REG_ADDR_MODE, + (st->rx[0] & ~SCA3000_RING_BUF_ENABLE)); +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + +/** + * sca3000_hw_ring_preenable() hw ring buffer preenable function + * + * Very simple enable function as the chip will allows normal reads + * during ring buffer operation so as long as it is indeed running + * before we notify the core, the precise ordering does not matter. + **/ +static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) +{ + return __sca3000_hw_ring_state_set(indio_dev, 1); +} + +static int sca3000_hw_ring_postdisable(struct iio_dev *indio_dev) +{ + return __sca3000_hw_ring_state_set(indio_dev, 0); +} + +static const struct iio_buffer_setup_ops sca3000_ring_setup_ops = { + .preenable = &sca3000_hw_ring_preenable, + .postdisable = &sca3000_hw_ring_postdisable, +}; + +static void sca3000_register_ring_funcs(struct iio_dev *indio_dev) +{ + indio_dev->setup_ops = &sca3000_ring_setup_ops; +} + +/** + * sca3000_clean_setup() get the device into a predictable state + * + * Devices use flash memory to store many of the register values + * and hence can come up in somewhat unpredictable states. + * Hence reset everything on driver load. + **/ +static int sca3000_clean_setup(struct sca3000_state *st) +{ + int ret; + + mutex_lock(&st->lock); + /* Ensure all interrupts have been acknowledged */ + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_STATUS, 1); + if (ret) + goto error_ret; + + /* Turn off all motion detection channels */ + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); + if (ret < 0) + goto error_ret; + ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL, + ret & SCA3000_MD_CTRL_PROT_MASK); + if (ret) + goto error_ret; + + /* Disable ring buffer */ + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); + if (ret < 0) + goto error_ret; + ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, + (ret & SCA3000_OUT_CTRL_PROT_MASK) + | SCA3000_OUT_CTRL_BUF_X_EN + | SCA3000_OUT_CTRL_BUF_Y_EN + | SCA3000_OUT_CTRL_BUF_Z_EN + | SCA3000_OUT_CTRL_BUF_DIV_4); + if (ret) + goto error_ret; + /* Enable interrupts, relevant to mode and set up as active low */ + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); + if (ret) + goto error_ret; + ret = sca3000_write_reg(st, + SCA3000_REG_ADDR_INT_MASK, + (ret & SCA3000_INT_MASK_PROT_MASK) + | SCA3000_INT_MASK_ACTIVE_LOW); + if (ret) + goto error_ret; + /* + * Select normal measurement mode, free fall off, ring off + * Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5 + * as that occurs in one of the example on the datasheet + */ + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + if (ret) + goto error_ret; + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + (st->rx[0] & SCA3000_MODE_PROT_MASK)); + st->bpse = 11; + +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static const struct iio_info sca3000_info = { + .attrs = &sca3000_attribute_group, + .read_raw = &sca3000_read_raw, + .write_raw = &sca3000_write_raw, + .event_attrs = &sca3000_event_attribute_group, + .read_event_value = &sca3000_read_thresh, + .write_event_value = &sca3000_write_thresh, + .read_event_config = &sca3000_read_event_config, + .write_event_config = &sca3000_write_event_config, + .driver_module = THIS_MODULE, +}; + +static int sca3000_probe(struct spi_device *spi) +{ + int ret; + struct sca3000_state *st; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + spi_set_drvdata(spi, indio_dev); + st->us = spi; + mutex_init(&st->lock); + st->info = &sca3000_spi_chip_info_tbl[spi_get_device_id(spi) + ->driver_data]; + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->info = &sca3000_info; + if (st->info->temp_output) { + indio_dev->channels = sca3000_channels_with_temp; + indio_dev->num_channels = + ARRAY_SIZE(sca3000_channels_with_temp); + } else { + indio_dev->channels = sca3000_channels; + indio_dev->num_channels = ARRAY_SIZE(sca3000_channels); + } + indio_dev->modes = INDIO_DIRECT_MODE; + + sca3000_configure_ring(indio_dev); + ret = iio_device_register(indio_dev); + if (ret < 0) + return ret; + + if (spi->irq) { + ret = request_threaded_irq(spi->irq, + NULL, + &sca3000_event_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "sca3000", + indio_dev); + if (ret) + goto error_unregister_dev; + } + sca3000_register_ring_funcs(indio_dev); + ret = sca3000_clean_setup(st); + if (ret) + goto error_free_irq; + return 0; + +error_free_irq: + if (spi->irq) + free_irq(spi->irq, indio_dev); +error_unregister_dev: + iio_device_unregister(indio_dev); + return ret; +} + +static int sca3000_stop_all_interrupts(struct sca3000_state *st) +{ + int ret; + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); + if (ret) + goto error_ret; + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_INT_MASK, + (st->rx[0] & + ~(SCA3000_INT_MASK_RING_THREE_QUARTER | + SCA3000_INT_MASK_RING_HALF | + SCA3000_INT_MASK_ALL_INTS))); +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static int sca3000_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct sca3000_state *st = iio_priv(indio_dev); + + /* Must ensure no interrupts can be generated after this! */ + sca3000_stop_all_interrupts(st); + if (spi->irq) + free_irq(spi->irq, indio_dev); + iio_device_unregister(indio_dev); + sca3000_unconfigure_ring(indio_dev); + + return 0; +} + +static const struct spi_device_id sca3000_id[] = { + {"sca3000_d01", d01}, + {"sca3000_e02", e02}, + {"sca3000_e04", e04}, + {"sca3000_e05", e05}, + {} +}; +MODULE_DEVICE_TABLE(spi, sca3000_id); + +static struct spi_driver sca3000_driver = { + .driver = { + .name = "sca3000", + }, + .probe = sca3000_probe, + .remove = sca3000_remove, + .id_table = sca3000_id, +}; +module_spi_driver(sca3000_driver); + +MODULE_AUTHOR("Jonathan Cameron "); +MODULE_DESCRIPTION("VTI SCA3000 Series Accelerometers SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/accel/sca3000.h b/drivers/staging/iio/accel/sca3000.h deleted file mode 100644 index 4dcc8575cbe3..000000000000 --- a/drivers/staging/iio/accel/sca3000.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * sca3000.c -- support VTI sca3000 series accelerometers - * via SPI - * - * Copyright (c) 2007 Jonathan Cameron - * - * Partly based upon tle62x0.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Initial mode is direct measurement. - * - * Untested things - * - * Temperature reading (the e05 I'm testing with doesn't have a sensor) - * - * Free fall detection mode - supported but untested as I'm not droping my - * dubious wire rig far enough to test it. - * - * Unsupported as yet - * - * Time stamping of data from ring. Various ideas on how to do this but none - * are remotely simple. Suggestions welcome. - * - * Individual enabling disabling of channels going into ring buffer - * - * Overflow handling (this is signaled for all but 8 bit ring buffer mode.) - * - * Motion detector using AND combinations of signals. - * - * Note: Be very careful about not touching an register bytes marked - * as reserved on the data sheet. They really mean it as changing convents of - * some will cause the device to lock up. - * - * Known issues - on rare occasions the interrupts lock up. Not sure why as yet. - * Can probably alleviate this by reading the interrupt register on start, but - * that is really just brushing the problem under the carpet. - */ -#ifndef _SCA3000 -#define _SCA3000 - -#define SCA3000_WRITE_REG(a) (((a) << 2) | 0x02) -#define SCA3000_READ_REG(a) ((a) << 2) - -#define SCA3000_REG_ADDR_REVID 0x00 -#define SCA3000_REVID_MAJOR_MASK 0xf0 -#define SCA3000_REVID_MINOR_MASK 0x0f - -#define SCA3000_REG_ADDR_STATUS 0x02 -#define SCA3000_LOCKED 0x20 -#define SCA3000_EEPROM_CS_ERROR 0x02 -#define SCA3000_SPI_FRAME_ERROR 0x01 - -/* All reads done using register decrement so no need to directly access LSBs */ -#define SCA3000_REG_ADDR_X_MSB 0x05 -#define SCA3000_REG_ADDR_Y_MSB 0x07 -#define SCA3000_REG_ADDR_Z_MSB 0x09 - -#define SCA3000_REG_ADDR_RING_OUT 0x0f - -/* Temp read untested - the e05 doesn't have the sensor */ -#define SCA3000_REG_ADDR_TEMP_MSB 0x13 - -#define SCA3000_REG_ADDR_MODE 0x14 -#define SCA3000_MODE_PROT_MASK 0x28 - -#define SCA3000_RING_BUF_ENABLE 0x80 -#define SCA3000_RING_BUF_8BIT 0x40 -/* - * Free fall detection triggers an interrupt if the acceleration - * is below a threshold for equivalent of 25cm drop - */ -#define SCA3000_FREE_FALL_DETECT 0x10 -#define SCA3000_MEAS_MODE_NORMAL 0x00 -#define SCA3000_MEAS_MODE_OP_1 0x01 -#define SCA3000_MEAS_MODE_OP_2 0x02 - -/* - * In motion detection mode the accelerations are band pass filtered - * (approx 1 - 25Hz) and then a programmable threshold used to trigger - * and interrupt. - */ -#define SCA3000_MEAS_MODE_MOT_DET 0x03 - -#define SCA3000_REG_ADDR_BUF_COUNT 0x15 - -#define SCA3000_REG_ADDR_INT_STATUS 0x16 - -#define SCA3000_INT_STATUS_THREE_QUARTERS 0x80 -#define SCA3000_INT_STATUS_HALF 0x40 - -#define SCA3000_INT_STATUS_FREE_FALL 0x08 -#define SCA3000_INT_STATUS_Y_TRIGGER 0x04 -#define SCA3000_INT_STATUS_X_TRIGGER 0x02 -#define SCA3000_INT_STATUS_Z_TRIGGER 0x01 - -/* Used to allow access to multiplexed registers */ -#define SCA3000_REG_ADDR_CTRL_SEL 0x18 -/* Only available for SCA3000-D03 and SCA3000-D01 */ -#define SCA3000_REG_CTRL_SEL_I2C_DISABLE 0x01 -#define SCA3000_REG_CTRL_SEL_MD_CTRL 0x02 -#define SCA3000_REG_CTRL_SEL_MD_Y_TH 0x03 -#define SCA3000_REG_CTRL_SEL_MD_X_TH 0x04 -#define SCA3000_REG_CTRL_SEL_MD_Z_TH 0x05 -/* - * BE VERY CAREFUL WITH THIS, IF 3 BITS ARE NOT SET the device - * will not function - */ -#define SCA3000_REG_CTRL_SEL_OUT_CTRL 0x0B -#define SCA3000_OUT_CTRL_PROT_MASK 0xE0 -#define SCA3000_OUT_CTRL_BUF_X_EN 0x10 -#define SCA3000_OUT_CTRL_BUF_Y_EN 0x08 -#define SCA3000_OUT_CTRL_BUF_Z_EN 0x04 -#define SCA3000_OUT_CTRL_BUF_DIV_MASK 0x03 -#define SCA3000_OUT_CTRL_BUF_DIV_4 0x02 -#define SCA3000_OUT_CTRL_BUF_DIV_2 0x01 - -/* - * Control which motion detector interrupts are on. - * For now only OR combinations are supported. - */ -#define SCA3000_MD_CTRL_PROT_MASK 0xC0 -#define SCA3000_MD_CTRL_OR_Y 0x01 -#define SCA3000_MD_CTRL_OR_X 0x02 -#define SCA3000_MD_CTRL_OR_Z 0x04 -/* Currently unsupported */ -#define SCA3000_MD_CTRL_AND_Y 0x08 -#define SCA3000_MD_CTRL_AND_X 0x10 -#define SAC3000_MD_CTRL_AND_Z 0x20 - -/* - * Some control registers of complex access methods requiring this register to - * be used to remove a lock. - */ -#define SCA3000_REG_ADDR_UNLOCK 0x1e - -#define SCA3000_REG_ADDR_INT_MASK 0x21 -#define SCA3000_INT_MASK_PROT_MASK 0x1C - -#define SCA3000_INT_MASK_RING_THREE_QUARTER 0x80 -#define SCA3000_INT_MASK_RING_HALF 0x40 - -#define SCA3000_INT_MASK_ALL_INTS 0x02 -#define SCA3000_INT_MASK_ACTIVE_HIGH 0x01 -#define SCA3000_INT_MASK_ACTIVE_LOW 0x00 - -/* Values of multiplexed registers (write to ctrl_data after select) */ -#define SCA3000_REG_ADDR_CTRL_DATA 0x22 - -/* - * Measurement modes available on some sca3000 series chips. Code assumes others - * may become available in the future. - * - * Bypass - Bypass the low-pass filter in the signal channel so as to increase - * signal bandwidth. - * - * Narrow - Narrow low-pass filtering of the signal channel and half output - * data rate by decimation. - * - * Wide - Widen low-pass filtering of signal channel to increase bandwidth - */ -#define SCA3000_OP_MODE_BYPASS 0x01 -#define SCA3000_OP_MODE_NARROW 0x02 -#define SCA3000_OP_MODE_WIDE 0x04 -#define SCA3000_MAX_TX 6 -#define SCA3000_MAX_RX 2 - -/** - * struct sca3000_state - device instance state information - * @us: the associated spi device - * @info: chip variant information - * @interrupt_handler_ws: event interrupt handler for all events - * @last_timestamp: the timestamp of the last event - * @mo_det_use_count: reference counter for the motion detection unit - * @lock: lock used to protect elements of sca3000_state - * and the underlying device state. - * @bpse: number of bits per scan element - * @tx: dma-able transmit buffer - * @rx: dma-able receive buffer - **/ -struct sca3000_state { - struct spi_device *us; - const struct sca3000_chip_info *info; - struct work_struct interrupt_handler_ws; - s64 last_timestamp; - int mo_det_use_count; - struct mutex lock; - int bpse; - /* Can these share a cacheline ? */ - u8 rx[2] ____cacheline_aligned; - u8 tx[6] ____cacheline_aligned; -}; - -/** - * struct sca3000_chip_info - model dependent parameters - * @scale: scale * 10^-6 - * @temp_output: some devices have temperature sensors. - * @measurement_mode_freq: normal mode sampling frequency - * @option_mode_1: first optional mode. Not all models have one - * @option_mode_1_freq: option mode 1 sampling frequency - * @option_mode_2: second optional mode. Not all chips have one - * @option_mode_2_freq: option mode 2 sampling frequency - * - * This structure is used to hold information about the functionality of a given - * sca3000 variant. - **/ -struct sca3000_chip_info { - unsigned int scale; - bool temp_output; - int measurement_mode_freq; - int option_mode_1; - int option_mode_1_freq; - int option_mode_2; - int option_mode_2_freq; - int mot_det_mult_xz[6]; - int mot_det_mult_y[7]; -}; - -int sca3000_read_data_short(struct sca3000_state *st, - u8 reg_address_high, - int len); - -/** - * sca3000_write_reg() write a single register - * @address: address of register on chip - * @val: value to be written to register - * - * The main lock must be held. - **/ -int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val); - -#ifdef CONFIG_IIO_BUFFER -/** - * sca3000_register_ring_funcs() setup the ring state change functions - **/ -void sca3000_register_ring_funcs(struct iio_dev *indio_dev); - -/** - * sca3000_configure_ring() - allocate and configure ring buffer - * @indio_dev: iio-core device whose ring is to be configured - * - * The hardware ring buffer needs far fewer ring buffer functions than - * a software one as a lot of things are handled automatically. - * This function also tells the iio core that our device supports a - * hardware ring buffer mode. - **/ -int sca3000_configure_ring(struct iio_dev *indio_dev); - -/** - * sca3000_unconfigure_ring() - deallocate the ring buffer - * @indio_dev: iio-core device whose ring we are freeing - **/ -void sca3000_unconfigure_ring(struct iio_dev *indio_dev); - -/** - * sca3000_ring_int_process() handles ring related event pushing and escalation - * @val: the event code - **/ -void sca3000_ring_int_process(u8 val, struct iio_buffer *ring); - -#else -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) -{ -} - -#endif -#endif /* _SCA3000 */ diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c deleted file mode 100644 index 564b36d4f648..000000000000 --- a/drivers/staging/iio/accel/sca3000_core.c +++ /dev/null @@ -1,1210 +0,0 @@ -/* - * sca3000_core.c -- support VTI sca3000 series accelerometers via SPI - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * Copyright (c) 2009 Jonathan Cameron - * - * See industrialio/accels/sca3000.h for comments. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sca3000.h" - -enum sca3000_variant { - d01, - e02, - e04, - e05, -}; - -/* - * Note where option modes are not defined, the chip simply does not - * support any. - * Other chips in the sca3000 series use i2c and are not included here. - * - * Some of these devices are only listed in the family data sheet and - * do not actually appear to be available. - */ -static const struct sca3000_chip_info sca3000_spi_chip_info_tbl[] = { - [d01] = { - .scale = 7357, - .temp_output = true, - .measurement_mode_freq = 250, - .option_mode_1 = SCA3000_OP_MODE_BYPASS, - .option_mode_1_freq = 250, - .mot_det_mult_xz = {50, 100, 200, 350, 650, 1300}, - .mot_det_mult_y = {50, 100, 150, 250, 450, 850, 1750}, - }, - [e02] = { - .scale = 9810, - .measurement_mode_freq = 125, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 63, - .mot_det_mult_xz = {100, 150, 300, 550, 1050, 2050}, - .mot_det_mult_y = {50, 100, 200, 350, 700, 1350, 2700}, - }, - [e04] = { - .scale = 19620, - .measurement_mode_freq = 100, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 50, - .option_mode_2 = SCA3000_OP_MODE_WIDE, - .option_mode_2_freq = 400, - .mot_det_mult_xz = {200, 300, 600, 1100, 2100, 4100}, - .mot_det_mult_y = {100, 200, 400, 7000, 1400, 2700, 54000}, - }, - [e05] = { - .scale = 61313, - .measurement_mode_freq = 200, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 50, - .option_mode_2 = SCA3000_OP_MODE_WIDE, - .option_mode_2_freq = 400, - .mot_det_mult_xz = {600, 900, 1700, 3200, 6100, 11900}, - .mot_det_mult_y = {300, 600, 1200, 2000, 4100, 7800, 15600}, - }, -}; - -int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val) -{ - st->tx[0] = SCA3000_WRITE_REG(address); - st->tx[1] = val; - return spi_write(st->us, st->tx, 2); -} - -int sca3000_read_data_short(struct sca3000_state *st, - u8 reg_address_high, - int len) -{ - struct spi_transfer xfer[2] = { - { - .len = 1, - .tx_buf = st->tx, - }, { - .len = len, - .rx_buf = st->rx, - } - }; - st->tx[0] = SCA3000_READ_REG(reg_address_high); - - return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); -} - -/** - * sca3000_reg_lock_on() test if the ctrl register lock is on - * - * Lock must be held. - **/ -static int sca3000_reg_lock_on(struct sca3000_state *st) -{ - int ret; - - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_STATUS, 1); - if (ret < 0) - return ret; - - return !(st->rx[0] & SCA3000_LOCKED); -} - -/** - * __sca3000_unlock_reg_lock() unlock the control registers - * - * Note the device does not appear to support doing this in a single transfer. - * This should only ever be used as part of ctrl reg read. - * Lock must be held before calling this - **/ -static int __sca3000_unlock_reg_lock(struct sca3000_state *st) -{ - struct spi_transfer xfer[3] = { - { - .len = 2, - .cs_change = 1, - .tx_buf = st->tx, - }, { - .len = 2, - .cs_change = 1, - .tx_buf = st->tx + 2, - }, { - .len = 2, - .tx_buf = st->tx + 4, - }, - }; - st->tx[0] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); - st->tx[1] = 0x00; - st->tx[2] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); - st->tx[3] = 0x50; - st->tx[4] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); - st->tx[5] = 0xA0; - - return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); -} - -/** - * sca3000_write_ctrl_reg() write to a lock protect ctrl register - * @sel: selects which registers we wish to write to - * @val: the value to be written - * - * Certain control registers are protected against overwriting by the lock - * register and use a shared write address. This function allows writing of - * these registers. - * Lock must be held. - **/ -static int sca3000_write_ctrl_reg(struct sca3000_state *st, - u8 sel, - uint8_t val) -{ - int ret; - - ret = sca3000_reg_lock_on(st); - if (ret < 0) - goto error_ret; - if (ret) { - ret = __sca3000_unlock_reg_lock(st); - if (ret) - goto error_ret; - } - - /* Set the control select register */ - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_SEL, sel); - if (ret) - goto error_ret; - - /* Write the actual value into the register */ - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_DATA, val); - -error_ret: - return ret; -} - -/** - * sca3000_read_ctrl_reg() read from lock protected control register. - * - * Lock must be held. - **/ -static int sca3000_read_ctrl_reg(struct sca3000_state *st, - u8 ctrl_reg) -{ - int ret; - - ret = sca3000_reg_lock_on(st); - if (ret < 0) - goto error_ret; - if (ret) { - ret = __sca3000_unlock_reg_lock(st); - if (ret) - goto error_ret; - } - /* Set the control select register */ - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_SEL, ctrl_reg); - if (ret) - goto error_ret; - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_CTRL_DATA, 1); - if (ret) - goto error_ret; - return st->rx[0]; -error_ret: - return ret; -} - -/** - * sca3000_show_rev() - sysfs interface to read the chip revision number - **/ -static ssize_t sca3000_show_rev(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int len = 0, ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_REVID, 1); - if (ret < 0) - goto error_ret; - len += sprintf(buf + len, - "major=%d, minor=%d\n", - st->rx[0] & SCA3000_REVID_MAJOR_MASK, - st->rx[0] & SCA3000_REVID_MINOR_MASK); -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -/** - * sca3000_show_available_measurement_modes() display available modes - * - * This is all read from chip specific data in the driver. Not all - * of the sca3000 series support modes other than normal. - **/ -static ssize_t -sca3000_show_available_measurement_modes(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int len = 0; - - len += sprintf(buf + len, "0 - normal mode"); - switch (st->info->option_mode_1) { - case SCA3000_OP_MODE_NARROW: - len += sprintf(buf + len, ", 1 - narrow mode"); - break; - 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"); - break; - } - /* always supported */ - len += sprintf(buf + len, " 3 - motion detection\n"); - - return len; -} - -/** - * sca3000_show_measurement_mode() sysfs read of current mode - **/ -static ssize_t -sca3000_show_measurement_mode(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int len = 0, ret; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - /* mask bottom 2 bits - only ones that are relevant */ - st->rx[0] &= 0x03; - switch (st->rx[0]) { - case SCA3000_MEAS_MODE_NORMAL: - len += sprintf(buf + len, "0 - normal mode\n"); - break; - case SCA3000_MEAS_MODE_MOT_DET: - len += sprintf(buf + len, "3 - motion detection\n"); - break; - case SCA3000_MEAS_MODE_OP_1: - switch (st->info->option_mode_1) { - case SCA3000_OP_MODE_NARROW: - len += sprintf(buf + len, "1 - narrow mode\n"); - break; - 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) { - case SCA3000_OP_MODE_WIDE: - len += sprintf(buf + len, "2 - wide mode\n"); - break; - } - break; - } - -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -/** - * sca3000_store_measurement_mode() set the current mode - **/ -static ssize_t -sca3000_store_measurement_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - u8 mask = 0x03; - u8 val; - - mutex_lock(&st->lock); - ret = kstrtou8(buf, 10, &val); - if (ret) - goto error_ret; - if (val > 3) { - ret = -EINVAL; - goto error_ret; - } - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - st->rx[0] &= ~mask; - st->rx[0] |= (val & mask); - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, st->rx[0]); - if (ret) - goto error_ret; - mutex_unlock(&st->lock); - - return len; - -error_ret: - mutex_unlock(&st->lock); - - return ret; -} - -/* - * Not even vaguely standard attributes so defined here rather than - * in the relevant IIO core headers - */ -static IIO_DEVICE_ATTR(measurement_mode_available, S_IRUGO, - sca3000_show_available_measurement_modes, - NULL, 0); - -static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR, - sca3000_show_measurement_mode, - sca3000_store_measurement_mode, - 0); - -/* More standard attributes */ - -static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0); - -static const struct iio_event_spec sca3000_event = { - .type = IIO_EV_TYPE_MAG, - .dir = IIO_EV_DIR_RISING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), -}; - -#define SCA3000_CHAN(index, mod) \ - { \ - .type = IIO_ACCEL, \ - .modified = 1, \ - .channel2 = mod, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ - .address = index, \ - .scan_index = index, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 11, \ - .storagebits = 16, \ - .shift = 5, \ - }, \ - .event_spec = &sca3000_event, \ - .num_event_specs = 1, \ - } - -static const struct iio_chan_spec sca3000_channels[] = { - SCA3000_CHAN(0, IIO_MOD_X), - SCA3000_CHAN(1, IIO_MOD_Y), - SCA3000_CHAN(2, IIO_MOD_Z), -}; - -static const struct iio_chan_spec sca3000_channels_with_temp[] = { - SCA3000_CHAN(0, IIO_MOD_X), - SCA3000_CHAN(1, IIO_MOD_Y), - SCA3000_CHAN(2, IIO_MOD_Z), - { - .type = IIO_TEMP, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_OFFSET), - /* No buffer support */ - .scan_index = -1, - }, -}; - -static u8 sca3000_addresses[3][3] = { - [0] = {SCA3000_REG_ADDR_X_MSB, SCA3000_REG_CTRL_SEL_MD_X_TH, - SCA3000_MD_CTRL_OR_X}, - [1] = {SCA3000_REG_ADDR_Y_MSB, SCA3000_REG_CTRL_SEL_MD_Y_TH, - SCA3000_MD_CTRL_OR_Y}, - [2] = {SCA3000_REG_ADDR_Z_MSB, SCA3000_REG_CTRL_SEL_MD_Z_TH, - SCA3000_MD_CTRL_OR_Z}, -}; - -/** - * __sca3000_get_base_freq() obtain mode specific base frequency - * - * lock must be held - **/ -static inline int __sca3000_get_base_freq(struct sca3000_state *st, - const struct sca3000_chip_info *info, - int *base_freq) -{ - int ret; - - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - switch (0x03 & st->rx[0]) { - case SCA3000_MEAS_MODE_NORMAL: - *base_freq = info->measurement_mode_freq; - break; - case SCA3000_MEAS_MODE_OP_1: - *base_freq = info->option_mode_1_freq; - break; - case SCA3000_MEAS_MODE_OP_2: - *base_freq = info->option_mode_2_freq; - break; - default: - ret = -EINVAL; - } -error_ret: - return ret; -} - -/** - * read_raw handler for IIO_CHAN_INFO_SAMP_FREQ - * - * lock must be held - **/ -static int read_raw_samp_freq(struct sca3000_state *st, int *val) -{ - int ret; - - ret = __sca3000_get_base_freq(st, st->info, val); - if (ret) - return ret; - - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); - if (ret < 0) - return ret; - - if (*val > 0) { - ret &= SCA3000_OUT_CTRL_BUF_DIV_MASK; - switch (ret) { - case SCA3000_OUT_CTRL_BUF_DIV_2: - *val /= 2; - break; - case SCA3000_OUT_CTRL_BUF_DIV_4: - *val /= 4; - break; - } - } - - return 0; -} - -/** - * write_raw handler for IIO_CHAN_INFO_SAMP_FREQ - * - * lock must be held - **/ -static int write_raw_samp_freq(struct sca3000_state *st, int val) -{ - int ret, base_freq, ctrlval; - - ret = __sca3000_get_base_freq(st, st->info, &base_freq); - if (ret) - return ret; - - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); - if (ret < 0) - return ret; - - ctrlval = ret & ~SCA3000_OUT_CTRL_BUF_DIV_MASK; - - if (val == base_freq / 2) - ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_2; - if (val == base_freq / 4) - ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_4; - else if (val != base_freq) - return -EINVAL; - - return sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, - ctrlval); -} - -static int sca3000_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - u8 address; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&st->lock); - if (chan->type == IIO_ACCEL) { - if (st->mo_det_use_count) { - mutex_unlock(&st->lock); - return -EBUSY; - } - address = sca3000_addresses[chan->address][0]; - ret = sca3000_read_data_short(st, address, 2); - if (ret < 0) { - mutex_unlock(&st->lock); - return ret; - } - *val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF; - *val = ((*val) << (sizeof(*val) * 8 - 13)) >> - (sizeof(*val) * 8 - 13); - } else { - /* get the temperature when available */ - ret = sca3000_read_data_short(st, - SCA3000_REG_ADDR_TEMP_MSB, - 2); - if (ret < 0) { - mutex_unlock(&st->lock); - return ret; - } - *val = ((st->rx[0] & 0x3F) << 3) | - ((st->rx[1] & 0xE0) >> 5); - } - mutex_unlock(&st->lock); - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - *val = 0; - if (chan->type == IIO_ACCEL) - *val2 = st->info->scale; - else /* temperature */ - *val2 = 555556; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_CHAN_INFO_OFFSET: - *val = -214; - *val2 = 600000; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(&st->lock); - ret = read_raw_samp_freq(st, val); - mutex_unlock(&st->lock); - return ret ? ret : IIO_VAL_INT; - default: - return -EINVAL; - } -} - -static int sca3000_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - - switch (mask) { - case IIO_CHAN_INFO_SAMP_FREQ: - if (val2) - return -EINVAL; - mutex_lock(&st->lock); - ret = write_raw_samp_freq(st, val); - mutex_unlock(&st->lock); - return ret; - default: - return -EINVAL; - } - - return ret; -} - -/** - * sca3000_read_av_freq() sysfs function to get available frequencies - * - * The later modes are only relevant to the ring buffer - and depend on current - * mode. Note that data sheet gives rather wide tolerances for these so integer - * division will give good enough answer and not all chips have them specified - * at all. - **/ -static ssize_t sca3000_read_av_freq(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int len = 0, ret, val; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret) - goto error_ret; - - switch (val & 0x03) { - case SCA3000_MEAS_MODE_NORMAL: - len += sprintf(buf + len, "%d %d %d\n", - st->info->measurement_mode_freq, - st->info->measurement_mode_freq / 2, - st->info->measurement_mode_freq / 4); - break; - case SCA3000_MEAS_MODE_OP_1: - len += sprintf(buf + len, "%d %d %d\n", - st->info->option_mode_1_freq, - st->info->option_mode_1_freq / 2, - st->info->option_mode_1_freq / 4); - break; - case SCA3000_MEAS_MODE_OP_2: - len += sprintf(buf + len, "%d %d %d\n", - st->info->option_mode_2_freq, - st->info->option_mode_2_freq / 2, - st->info->option_mode_2_freq / 4); - break; - } - return len; -error_ret: - return ret; -} - -/* - * Should only really be registered if ring buffer support is compiled in. - * Does no harm however and doing it right would add a fair bit of complexity - */ -static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sca3000_read_av_freq); - -/** - * sca3000_read_thresh() - query of a threshold - **/ -static int sca3000_read_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int *val, int *val2) -{ - int ret, i; - struct sca3000_state *st = iio_priv(indio_dev); - int num = chan->channel2; - - mutex_lock(&st->lock); - ret = sca3000_read_ctrl_reg(st, sca3000_addresses[num][1]); - mutex_unlock(&st->lock); - if (ret < 0) - return ret; - *val = 0; - if (num == 1) - for_each_set_bit(i, (unsigned long *)&ret, - ARRAY_SIZE(st->info->mot_det_mult_y)) - *val += st->info->mot_det_mult_y[i]; - else - for_each_set_bit(i, (unsigned long *)&ret, - ARRAY_SIZE(st->info->mot_det_mult_xz)) - *val += st->info->mot_det_mult_xz[i]; - - return IIO_VAL_INT; -} - -/** - * sca3000_write_thresh() control of threshold - **/ -static int sca3000_write_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int val, int val2) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int num = chan->channel2; - int ret; - int i; - u8 nonlinear = 0; - - if (num == 1) { - i = ARRAY_SIZE(st->info->mot_det_mult_y); - while (i > 0) - if (val >= st->info->mot_det_mult_y[--i]) { - nonlinear |= (1 << i); - val -= st->info->mot_det_mult_y[i]; - } - } else { - i = ARRAY_SIZE(st->info->mot_det_mult_xz); - while (i > 0) - if (val >= st->info->mot_det_mult_xz[--i]) { - nonlinear |= (1 << i); - val -= st->info->mot_det_mult_xz[i]; - } - } - - mutex_lock(&st->lock); - ret = sca3000_write_ctrl_reg(st, sca3000_addresses[num][1], nonlinear); - mutex_unlock(&st->lock); - - return ret; -} - -static struct attribute *sca3000_attributes[] = { - &iio_dev_attr_revision.dev_attr.attr, - &iio_dev_attr_measurement_mode_available.dev_attr.attr, - &iio_dev_attr_measurement_mode.dev_attr.attr, - &iio_dev_attr_sampling_frequency_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group sca3000_attribute_group = { - .attrs = sca3000_attributes, -}; - -/** - * sca3000_event_handler() - handling ring and non ring events - * - * Ring related interrupt handler. Depending on event, push to - * the ring buffer event chrdev or the event one. - * - * This function is complicated by the fact that the devices can signify ring - * and non ring events via the same interrupt line and they can only - * be distinguished via a read of the relevant status register. - **/ -static irqreturn_t sca3000_event_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct sca3000_state *st = iio_priv(indio_dev); - int ret, val; - s64 last_timestamp = iio_get_time_ns(indio_dev); - - /* - * Could lead if badly timed to an extra read of status reg, - * but ensures no interrupt is missed. - */ - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_STATUS, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret) - goto done; - - sca3000_ring_int_process(val, indio_dev->buffer); - - if (val & SCA3000_INT_STATUS_FREE_FALL) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_X_AND_Y_AND_Z, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_FALLING), - last_timestamp); - - if (val & SCA3000_INT_STATUS_Y_TRIGGER) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Y, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_RISING), - last_timestamp); - - if (val & SCA3000_INT_STATUS_X_TRIGGER) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_X, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_RISING), - last_timestamp); - - if (val & SCA3000_INT_STATUS_Z_TRIGGER) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Z, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_RISING), - last_timestamp); - -done: - return IRQ_HANDLED; -} - -/** - * sca3000_read_event_config() what events are enabled - **/ -static int sca3000_read_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - u8 protect_mask = 0x03; - int num = chan->channel2; - - /* read current value of mode register */ - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - - if ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET) { - ret = 0; - } else { - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); - if (ret < 0) - goto error_ret; - /* only supporting logical or's for now */ - ret = !!(ret & sca3000_addresses[num][2]); - } -error_ret: - mutex_unlock(&st->lock); - - return ret; -} - -/** - * sca3000_query_free_fall_mode() is free fall mode enabled - **/ -static ssize_t sca3000_query_free_fall_mode(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int val; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret < 0) - return ret; - return sprintf(buf, "%d\n", !!(val & SCA3000_FREE_FALL_DETECT)); -} - -/** - * sca3000_set_free_fall_mode() simple on off control for free fall int - * - * In these chips the free fall detector should send an interrupt if - * the device falls more than 25cm. This has not been tested due - * to fragile wiring. - **/ -static ssize_t sca3000_set_free_fall_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - u8 val; - int ret; - u8 protect_mask = SCA3000_FREE_FALL_DETECT; - - mutex_lock(&st->lock); - ret = kstrtou8(buf, 10, &val); - if (ret) - goto error_ret; - - /* read current value of mode register */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - - /* if off and should be on */ - if (val && !(st->rx[0] & protect_mask)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] | SCA3000_FREE_FALL_DETECT)); - /* if on and should be off */ - else if (!val && (st->rx[0] & protect_mask)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~protect_mask)); -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -/** - * sca3000_write_event_config() simple on off control for motion detector - * - * This is a per axis control, but enabling any will result in the - * motion detector unit being enabled. - * N.B. enabling motion detector stops normal data acquisition. - * There is a complexity in knowing which mode to return to when - * this mode is disabled. Currently normal mode is assumed. - **/ -static int sca3000_write_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - int state) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret, ctrlval; - u8 protect_mask = 0x03; - int num = chan->channel2; - - mutex_lock(&st->lock); - /* - * First read the motion detector config to find out if - * this axis is on - */ - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); - if (ret < 0) - goto exit_point; - ctrlval = ret; - /* if off and should be on */ - if (state && !(ctrlval & sca3000_addresses[num][2])) { - ret = sca3000_write_ctrl_reg(st, - SCA3000_REG_CTRL_SEL_MD_CTRL, - ctrlval | - sca3000_addresses[num][2]); - if (ret) - goto exit_point; - st->mo_det_use_count++; - } else if (!state && (ctrlval & sca3000_addresses[num][2])) { - ret = sca3000_write_ctrl_reg(st, - SCA3000_REG_CTRL_SEL_MD_CTRL, - ctrlval & - ~(sca3000_addresses[num][2])); - if (ret) - goto exit_point; - st->mo_det_use_count--; - } - - /* read current value of mode register */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto exit_point; - /* if off and should be on */ - if ((st->mo_det_use_count) && - ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~protect_mask) - | SCA3000_MEAS_MODE_MOT_DET); - /* if on and should be off */ - else if (!(st->mo_det_use_count) && - ((st->rx[0] & protect_mask) == SCA3000_MEAS_MODE_MOT_DET)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~protect_mask)); -exit_point: - mutex_unlock(&st->lock); - - return ret; -} - -/* Free fall detector related event attribute */ -static IIO_DEVICE_ATTR_NAMED(accel_xayaz_mag_falling_en, - in_accel_x & y & z_mag_falling_en, - S_IRUGO | S_IWUSR, - sca3000_query_free_fall_mode, - sca3000_set_free_fall_mode, - 0); - -static IIO_CONST_ATTR_NAMED(accel_xayaz_mag_falling_period, - in_accel_x & y & z_mag_falling_period, - "0.226"); - -static struct attribute *sca3000_event_attributes[] = { - &iio_dev_attr_accel_xayaz_mag_falling_en.dev_attr.attr, - &iio_const_attr_accel_xayaz_mag_falling_period.dev_attr.attr, - NULL, -}; - -static struct attribute_group sca3000_event_attribute_group = { - .attrs = sca3000_event_attributes, - .name = "events", -}; - -/** - * sca3000_clean_setup() get the device into a predictable state - * - * Devices use flash memory to store many of the register values - * and hence can come up in somewhat unpredictable states. - * Hence reset everything on driver load. - **/ -static int sca3000_clean_setup(struct sca3000_state *st) -{ - int ret; - - mutex_lock(&st->lock); - /* Ensure all interrupts have been acknowledged */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_STATUS, 1); - if (ret) - goto error_ret; - - /* Turn off all motion detection channels */ - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); - if (ret < 0) - goto error_ret; - ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL, - ret & SCA3000_MD_CTRL_PROT_MASK); - if (ret) - goto error_ret; - - /* Disable ring buffer */ - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); - if (ret < 0) - goto error_ret; - ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, - (ret & SCA3000_OUT_CTRL_PROT_MASK) - | SCA3000_OUT_CTRL_BUF_X_EN - | SCA3000_OUT_CTRL_BUF_Y_EN - | SCA3000_OUT_CTRL_BUF_Z_EN - | SCA3000_OUT_CTRL_BUF_DIV_4); - if (ret) - goto error_ret; - /* Enable interrupts, relevant to mode and set up as active low */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); - if (ret) - goto error_ret; - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_INT_MASK, - (ret & SCA3000_INT_MASK_PROT_MASK) - | SCA3000_INT_MASK_ACTIVE_LOW); - if (ret) - goto error_ret; - /* - * Select normal measurement mode, free fall off, ring off - * Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5 - * as that occurs in one of the example on the datasheet - */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & SCA3000_MODE_PROT_MASK)); - st->bpse = 11; - -error_ret: - mutex_unlock(&st->lock); - return ret; -} - -static const struct iio_info sca3000_info = { - .attrs = &sca3000_attribute_group, - .read_raw = &sca3000_read_raw, - .write_raw = &sca3000_write_raw, - .event_attrs = &sca3000_event_attribute_group, - .read_event_value = &sca3000_read_thresh, - .write_event_value = &sca3000_write_thresh, - .read_event_config = &sca3000_read_event_config, - .write_event_config = &sca3000_write_event_config, - .driver_module = THIS_MODULE, -}; - -static int sca3000_probe(struct spi_device *spi) -{ - int ret; - struct sca3000_state *st; - struct iio_dev *indio_dev; - - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - - st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); - st->us = spi; - mutex_init(&st->lock); - st->info = &sca3000_spi_chip_info_tbl[spi_get_device_id(spi) - ->driver_data]; - - indio_dev->dev.parent = &spi->dev; - indio_dev->name = spi_get_device_id(spi)->name; - indio_dev->info = &sca3000_info; - if (st->info->temp_output) { - indio_dev->channels = sca3000_channels_with_temp; - indio_dev->num_channels = - ARRAY_SIZE(sca3000_channels_with_temp); - } else { - indio_dev->channels = sca3000_channels; - indio_dev->num_channels = ARRAY_SIZE(sca3000_channels); - } - indio_dev->modes = INDIO_DIRECT_MODE; - - sca3000_configure_ring(indio_dev); - ret = iio_device_register(indio_dev); - if (ret < 0) - return ret; - - if (spi->irq) { - ret = request_threaded_irq(spi->irq, - NULL, - &sca3000_event_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "sca3000", - indio_dev); - if (ret) - goto error_unregister_dev; - } - sca3000_register_ring_funcs(indio_dev); - ret = sca3000_clean_setup(st); - if (ret) - goto error_free_irq; - return 0; - -error_free_irq: - if (spi->irq) - free_irq(spi->irq, indio_dev); -error_unregister_dev: - iio_device_unregister(indio_dev); - return ret; -} - -static int sca3000_stop_all_interrupts(struct sca3000_state *st) -{ - int ret; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); - if (ret) - goto error_ret; - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_INT_MASK, - (st->rx[0] & - ~(SCA3000_INT_MASK_RING_THREE_QUARTER | - SCA3000_INT_MASK_RING_HALF | - SCA3000_INT_MASK_ALL_INTS))); -error_ret: - mutex_unlock(&st->lock); - return ret; -} - -static int sca3000_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct sca3000_state *st = iio_priv(indio_dev); - - /* Must ensure no interrupts can be generated after this! */ - sca3000_stop_all_interrupts(st); - if (spi->irq) - free_irq(spi->irq, indio_dev); - iio_device_unregister(indio_dev); - sca3000_unconfigure_ring(indio_dev); - - return 0; -} - -static const struct spi_device_id sca3000_id[] = { - {"sca3000_d01", d01}, - {"sca3000_e02", e02}, - {"sca3000_e04", e04}, - {"sca3000_e05", e05}, - {} -}; -MODULE_DEVICE_TABLE(spi, sca3000_id); - -static struct spi_driver sca3000_driver = { - .driver = { - .name = "sca3000", - }, - .probe = sca3000_probe, - .remove = sca3000_remove, - .id_table = sca3000_id, -}; -module_spi_driver(sca3000_driver); - -MODULE_AUTHOR("Jonathan Cameron "); -MODULE_DESCRIPTION("VTI SCA3000 Series Accelerometers SPI driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c deleted file mode 100644 index e5de52d05a5c..000000000000 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * sca3000_ring.c -- support VTI sca3000 series accelerometers via SPI - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * Copyright (c) 2009 Jonathan Cameron - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "../ring_hw.h" -#include "sca3000.h" - -/* RFC / future work - * - * The internal ring buffer doesn't actually change what it holds depending - * on which signals are enabled etc, merely whether you can read them. - * As such the scan mode selection is somewhat different than for a software - * ring buffer and changing it actually covers any data already in the buffer. - * Currently scan elements aren't configured so it doesn't matter. - */ - -static int sca3000_read_data(struct sca3000_state *st, - u8 reg_address_high, - u8 **rx_p, - int len) -{ - int ret; - struct spi_transfer xfer[2] = { - { - .len = 1, - .tx_buf = st->tx, - }, { - .len = len, - } - }; - *rx_p = kmalloc(len, GFP_KERNEL); - if (!*rx_p) { - ret = -ENOMEM; - goto error_ret; - } - xfer[1].rx_buf = *rx_p; - st->tx[0] = SCA3000_READ_REG(reg_address_high); - ret = spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); - if (ret) { - dev_err(get_device(&st->us->dev), "problem reading register"); - goto error_free_rx; - } - - return 0; -error_free_rx: - kfree(*rx_p); -error_ret: - return ret; -} - -/** - * sca3000_read_first_n_hw_rb() - main ring access, pulls data from ring - * @r: the ring - * @count: number of samples to try and pull - * @data: output the actual samples pulled from the hw ring - * - * Currently does not provide timestamps. As the hardware doesn't add them they - * can only be inferred approximately from ring buffer events such as 50% full - * and knowledge of when buffer was last emptied. This is left to userspace. - **/ -static int sca3000_read_first_n_hw_rb(struct iio_buffer *r, - size_t count, char __user *buf) -{ - struct iio_hw_buffer *hw_ring = iio_to_hw_buf(r); - struct iio_dev *indio_dev = hw_ring->private; - struct sca3000_state *st = iio_priv(indio_dev); - u8 *rx; - int ret, i, num_available, num_read = 0; - int bytes_per_sample = 1; - - if (st->bpse == 11) - bytes_per_sample = 2; - - mutex_lock(&st->lock); - if (count % bytes_per_sample) { - ret = -EINVAL; - goto error_ret; - } - - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_BUF_COUNT, 1); - if (ret) - goto error_ret; - num_available = st->rx[0]; - /* - * num_available is the total number of samples available - * i.e. number of time points * number of channels. - */ - if (count > num_available * bytes_per_sample) - num_read = num_available * bytes_per_sample; - else - num_read = count; - - ret = sca3000_read_data(st, - SCA3000_REG_ADDR_RING_OUT, - &rx, num_read); - if (ret) - goto error_ret; - - for (i = 0; i < num_read / sizeof(u16); i++) - *(((u16 *)rx) + i) = be16_to_cpup((__be16 *)rx + i); - - if (copy_to_user(buf, rx, num_read)) - ret = -EFAULT; - kfree(rx); - r->stufftoread = 0; -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : num_read; -} - -static size_t sca3000_ring_buf_data_available(struct iio_buffer *r) -{ - return r->stufftoread ? r->watermark : 0; -} - -/** - * sca3000_query_ring_int() is the hardware ring status interrupt enabled - **/ -static ssize_t sca3000_query_ring_int(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int ret, val; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret) - return ret; - - return sprintf(buf, "%d\n", !!(val & this_attr->address)); -} - -/** - * sca3000_set_ring_int() set state of ring status interrupt - **/ -static ssize_t sca3000_set_ring_int(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - u8 val; - int ret; - - mutex_lock(&st->lock); - ret = kstrtou8(buf, 10, &val); - if (ret) - goto error_ret; - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); - if (ret) - goto error_ret; - if (val) - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_INT_MASK, - st->rx[0] | this_attr->address); - else - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_INT_MASK, - st->rx[0] & ~this_attr->address); -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -static IIO_DEVICE_ATTR(50_percent, S_IRUGO | S_IWUSR, - sca3000_query_ring_int, - sca3000_set_ring_int, - SCA3000_INT_MASK_RING_HALF); - -static IIO_DEVICE_ATTR(75_percent, S_IRUGO | S_IWUSR, - sca3000_query_ring_int, - sca3000_set_ring_int, - SCA3000_INT_MASK_RING_THREE_QUARTER); - -static ssize_t sca3000_show_buffer_scale(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - - return sprintf(buf, "0.%06d\n", 4 * st->info->scale); -} - -static IIO_DEVICE_ATTR(in_accel_scale, - S_IRUGO, - sca3000_show_buffer_scale, - NULL, - 0); - -/* - * Ring buffer attributes - * This device is a bit unusual in that the sampling frequency and bpse - * only apply to the ring buffer. At all times full rate and accuracy - * is available via direct reading from registers. - */ -static const struct attribute *sca3000_ring_attributes[] = { - &iio_dev_attr_50_percent.dev_attr.attr, - &iio_dev_attr_75_percent.dev_attr.attr, - &iio_dev_attr_in_accel_scale.dev_attr.attr, - NULL, -}; - -static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev) -{ - struct iio_buffer *buf; - struct iio_hw_buffer *ring; - - ring = kzalloc(sizeof(*ring), GFP_KERNEL); - if (!ring) - return NULL; - - ring->private = indio_dev; - buf = &ring->buf; - buf->stufftoread = 0; - buf->length = 64; - buf->attrs = sca3000_ring_attributes; - iio_buffer_init(buf); - - return buf; -} - -static void sca3000_ring_release(struct iio_buffer *r) -{ - kfree(iio_to_hw_buf(r)); -} - -static const struct iio_buffer_access_funcs sca3000_ring_access_funcs = { - .read_first_n = &sca3000_read_first_n_hw_rb, - .data_available = sca3000_ring_buf_data_available, - .release = sca3000_ring_release, - - .modes = INDIO_BUFFER_HARDWARE, -}; - -int sca3000_configure_ring(struct iio_dev *indio_dev) -{ - struct iio_buffer *buffer; - - buffer = sca3000_rb_allocate(indio_dev); - if (!buffer) - return -ENOMEM; - indio_dev->modes |= INDIO_BUFFER_HARDWARE; - - - buffer->access = &sca3000_ring_access_funcs; - iio_device_attach_buffer(indio_dev, buffer); - - return 0; -} - -void sca3000_unconfigure_ring(struct iio_dev *indio_dev) -{ - iio_buffer_put(indio_dev->buffer); -} - -static inline -int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - if (state) { - dev_info(&indio_dev->dev, "supposedly enabling ring buffer\n"); - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_MODE, - (st->rx[0] | SCA3000_RING_BUF_ENABLE)); - } else - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~SCA3000_RING_BUF_ENABLE)); -error_ret: - mutex_unlock(&st->lock); - - return ret; -} - -/** - * sca3000_hw_ring_preenable() hw ring buffer preenable function - * - * Very simple enable function as the chip will allows normal reads - * during ring buffer operation so as long as it is indeed running - * before we notify the core, the precise ordering does not matter. - **/ -static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) -{ - return __sca3000_hw_ring_state_set(indio_dev, 1); -} - -static int sca3000_hw_ring_postdisable(struct iio_dev *indio_dev) -{ - return __sca3000_hw_ring_state_set(indio_dev, 0); -} - -static const struct iio_buffer_setup_ops sca3000_ring_setup_ops = { - .preenable = &sca3000_hw_ring_preenable, - .postdisable = &sca3000_hw_ring_postdisable, -}; - -void sca3000_register_ring_funcs(struct iio_dev *indio_dev) -{ - indio_dev->setup_ops = &sca3000_ring_setup_ops; -} - -/** - * sca3000_ring_int_process() ring specific interrupt handling. - * - * This is only split from the main interrupt handler so as to - * reduce the amount of code if the ring buffer is not enabled. - **/ -void sca3000_ring_int_process(u8 val, struct iio_buffer *ring) -{ - if (val & (SCA3000_INT_STATUS_THREE_QUARTERS | - SCA3000_INT_STATUS_HALF)) { - ring->stufftoread = true; - wake_up_interruptible(&ring->pollq); - } -} -- cgit v1.2.3 From d1bf1a865fe6b391208efab532b1e6fc912e5bed Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:03 +0100 Subject: staging:iio:accel:sca3000 drop sca3000_register_ring_funcs This was needed when the buffer support was optional. Pointless wrapper now so drop it. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index 62ab1aef2528..36a52d02ee0e 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -1504,11 +1504,6 @@ static const struct iio_buffer_setup_ops sca3000_ring_setup_ops = { .postdisable = &sca3000_hw_ring_postdisable, }; -static void sca3000_register_ring_funcs(struct iio_dev *indio_dev) -{ - indio_dev->setup_ops = &sca3000_ring_setup_ops; -} - /** * sca3000_clean_setup() get the device into a predictable state * @@ -1631,7 +1626,7 @@ static int sca3000_probe(struct spi_device *spi) if (ret) goto error_unregister_dev; } - sca3000_register_ring_funcs(indio_dev); + indio_dev->setup_ops = &sca3000_ring_setup_ops; ret = sca3000_clean_setup(st); if (ret) goto error_free_irq; -- cgit v1.2.3 From 271a25f6480d51225abc2616df6c96e5979a7ffa Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:04 +0100 Subject: staging:iio:accel:sca3000 Fix clearing of flag + setting of size of scan. Not clearing the stuff_to_read flag can lead to a false flag being set on restarting the buffer if the data was not all read the previous time. The size of the scan is needed to ensure the function iio_buffer_read_first_n_outer actually tries to read the data. This stuff has been broken for some time so not stable material. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index 36a52d02ee0e..8af7d83e658d 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -1491,6 +1491,19 @@ error_ret: **/ static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) { + /* + * Set stuff to read to indicate no data present. + * Need for cases where the interrupt had fired at the + * end of a cycle, but the data was never read. + */ + indio_dev->buffer->stufftoread = 0; + /* + * Needed to ensure the core will actually read data + * from the device rather than assuming no channels + * are enabled. + */ + indio_dev->buffer->bytes_per_datum = 6; + return __sca3000_hw_ring_state_set(indio_dev, 1); } -- cgit v1.2.3 From c19a02582b9b9b60cbeddfda2d3958ca36f9afc9 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:05 +0100 Subject: staging:iio:accel:sca3000 Drop custom ABI for watersheds. For now we support only the 50% watershed interrupt and start and stop it as part of the buffer bring up. The 75% case may come back in future. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 111 +++++++++++++----------------------- 1 file changed, 41 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index 8af7d83e658d..173e9a69d44f 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -1309,73 +1309,6 @@ static size_t sca3000_ring_buf_data_available(struct iio_buffer *r) return r->stufftoread ? r->watermark : 0; } -/** - * sca3000_query_ring_int() is the hardware ring status interrupt enabled - **/ -static ssize_t sca3000_query_ring_int(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int ret, val; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret) - return ret; - - return sprintf(buf, "%d\n", !!(val & this_attr->address)); -} - -/** - * sca3000_set_ring_int() set state of ring status interrupt - **/ -static ssize_t sca3000_set_ring_int(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - u8 val; - int ret; - - mutex_lock(&st->lock); - ret = kstrtou8(buf, 10, &val); - if (ret) - goto error_ret; - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); - if (ret) - goto error_ret; - if (val) - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_INT_MASK, - st->rx[0] | this_attr->address); - else - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_INT_MASK, - st->rx[0] & ~this_attr->address); -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -static IIO_DEVICE_ATTR(50_percent, S_IRUGO | S_IWUSR, - sca3000_query_ring_int, - sca3000_set_ring_int, - SCA3000_INT_MASK_RING_HALF); - -static IIO_DEVICE_ATTR(75_percent, S_IRUGO | S_IWUSR, - sca3000_query_ring_int, - sca3000_set_ring_int, - SCA3000_INT_MASK_RING_THREE_QUARTER); - static ssize_t sca3000_show_buffer_scale(struct device *dev, struct device_attribute *attr, char *buf) @@ -1399,8 +1332,6 @@ static IIO_DEVICE_ATTR(in_accel_scale, * is available via direct reading from registers. */ static const struct attribute *sca3000_ring_attributes[] = { - &iio_dev_attr_50_percent.dev_attr.attr, - &iio_dev_attr_75_percent.dev_attr.attr, &iio_dev_attr_in_accel_scale.dev_attr.attr, NULL, }; @@ -1491,6 +1422,9 @@ error_ret: **/ static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) { + int ret; + struct sca3000_state *st = iio_priv(indio_dev); + /* * Set stuff to read to indicate no data present. * Need for cases where the interrupt had fired at the @@ -1504,12 +1438,49 @@ static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) */ indio_dev->buffer->bytes_per_datum = 6; + mutex_lock(&st->lock); + + /* Enable the 50% full interrupt */ + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); + if (ret) + goto error_unlock; + ret = sca3000_write_reg(st, + SCA3000_REG_ADDR_INT_MASK, + st->rx[0] | SCA3000_INT_MASK_RING_HALF); + if (ret) + goto error_unlock; + + mutex_unlock(&st->lock); + return __sca3000_hw_ring_state_set(indio_dev, 1); + +error_unlock: + mutex_unlock(&st->lock); + + return ret; } static int sca3000_hw_ring_postdisable(struct iio_dev *indio_dev) { - return __sca3000_hw_ring_state_set(indio_dev, 0); + int ret; + struct sca3000_state *st = iio_priv(indio_dev); + + ret = __sca3000_hw_ring_state_set(indio_dev, 0); + if (ret) + return ret; + + /* Disable the 50% full interrupt */ + mutex_lock(&st->lock); + + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); + if (ret) + goto unlock; + ret = sca3000_write_reg(st, + SCA3000_REG_ADDR_INT_MASK, + st->rx[0] & ~SCA3000_INT_MASK_RING_HALF); +unlock: + mutex_unlock(&st->lock); + return ret; } static const struct iio_buffer_setup_ops sca3000_ring_setup_ops = { -- cgit v1.2.3 From 152a6a884ae13400bd7c48f011acf81ef5225238 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:06 +0100 Subject: staging:iio:accel:sca3000 move to hybrid hard / soft buffer design. In a similar fashion to other newer drivers (e.g. ti_am335x), instead of using the hardware buffer support in IIO to directly access the hardware fifo, insert a software fifo and feed that from the hardware one when interrupts occur. This gives a simpler structure to the data flows and allows more flexibility over how often data is shipped to userspace etc. This was also the only direct user of the simplistic generalization found in ring_hw.h so that header is removed. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/Kconfig | 3 +- drivers/staging/iio/accel/sca3000.c | 256 ++++++++++-------------------------- drivers/staging/iio/ring_hw.h | 27 ---- 3 files changed, 72 insertions(+), 214 deletions(-) delete mode 100644 drivers/staging/iio/ring_hw.h (limited to 'drivers') diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index 1c994b57c7d2..53389bfdd100 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -52,7 +52,8 @@ config ADIS16240 called adis16240. config SCA3000 - depends on IIO_BUFFER + select IIO_BUFFER + select IIO_KFIFO_BUF depends on SPI tristate "VTI SCA3000 series accelerometers" help diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index 173e9a69d44f..f9ab7b3f8e87 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -23,7 +23,7 @@ #include #include #include -#include "../ring_hw.h" +#include #define SCA3000_WRITE_REG(a) (((a) << 2) | 0x02) #define SCA3000_READ_REG(a) ((a) << 2) @@ -173,7 +173,7 @@ struct sca3000_state { struct mutex lock; int bpse; /* Can these share a cacheline ? */ - u8 rx[2] ____cacheline_aligned; + u8 rx[384] ____cacheline_aligned; u8 tx[6] ____cacheline_aligned; }; @@ -572,6 +572,10 @@ static const struct iio_event_spec sca3000_event = { .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), }; +/* + * Note the hack in the number of bits to pretend we have 2 more than + * we do in the fifo. + */ #define SCA3000_CHAN(index, mod) \ { \ .type = IIO_ACCEL, \ @@ -584,9 +588,10 @@ static const struct iio_event_spec sca3000_event = { .scan_index = index, \ .scan_type = { \ .sign = 's', \ - .realbits = 11, \ + .realbits = 13, \ .storagebits = 16, \ - .shift = 5, \ + .shift = 3, \ + .endianness = IIO_BE, \ }, \ .event_spec = &sca3000_event, \ .num_event_specs = 1, \ @@ -935,19 +940,71 @@ static const struct attribute_group sca3000_attribute_group = { .attrs = sca3000_attributes, }; +static int sca3000_read_data(struct sca3000_state *st, + u8 reg_address_high, + u8 *rx, + int len) +{ + int ret; + struct spi_transfer xfer[2] = { + { + .len = 1, + .tx_buf = st->tx, + }, { + .len = len, + .rx_buf = rx, + } + }; + + st->tx[0] = SCA3000_READ_REG(reg_address_high); + ret = spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); + if (ret) { + dev_err(get_device(&st->us->dev), "problem reading register"); + return ret; + } + + return 0; +} + /** * sca3000_ring_int_process() ring specific interrupt handling. * * This is only split from the main interrupt handler so as to * reduce the amount of code if the ring buffer is not enabled. **/ -static void sca3000_ring_int_process(u8 val, struct iio_buffer *ring) +static void sca3000_ring_int_process(u8 val, struct iio_dev *indio_dev) { - if (val & (SCA3000_INT_STATUS_THREE_QUARTERS | - SCA3000_INT_STATUS_HALF)) { - ring->stufftoread = true; - wake_up_interruptible(&ring->pollq); + struct sca3000_state *st = iio_priv(indio_dev); + int ret, i, num_available; + + mutex_lock(&st->lock); + if (val & SCA3000_INT_STATUS_HALF) { + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_BUF_COUNT, + 1); + if (ret) + goto error_ret; + num_available = st->rx[0]; + /* + * num_available is the total number of samples available + * i.e. number of time points * number of channels. + */ + ret = sca3000_read_data(st, SCA3000_REG_ADDR_RING_OUT, st->rx, + num_available * 2); + if (ret) + goto error_ret; + for (i = 0; i < num_available / 3; i++) { + /* + * Dirty hack to cover for 11 bit in fifo, 13 bit + * direct reading. + * + * In theory the bottom two bits are undefined. + * In reality they appear to always be 0. + */ + iio_push_to_buffers(indio_dev, st->rx + i * 3 * 2); + } } +error_ret: + mutex_unlock(&st->lock); } /** @@ -978,7 +1035,7 @@ static irqreturn_t sca3000_event_handler(int irq, void *private) if (ret) goto done; - sca3000_ring_int_process(val, indio_dev->buffer); + sca3000_ring_int_process(val, indio_dev); if (val & SCA3000_INT_STATUS_FREE_FALL) iio_push_event(indio_dev, @@ -1209,183 +1266,23 @@ static struct attribute_group sca3000_event_attribute_group = { .name = "events", }; -static int sca3000_read_data(struct sca3000_state *st, - u8 reg_address_high, - u8 **rx_p, - int len) -{ - int ret; - struct spi_transfer xfer[2] = { - { - .len = 1, - .tx_buf = st->tx, - }, { - .len = len, - } - }; - *rx_p = kmalloc(len, GFP_KERNEL); - if (!*rx_p) { - ret = -ENOMEM; - goto error_ret; - } - xfer[1].rx_buf = *rx_p; - st->tx[0] = SCA3000_READ_REG(reg_address_high); - ret = spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); - if (ret) { - dev_err(get_device(&st->us->dev), "problem reading register"); - goto error_free_rx; - } - - return 0; -error_free_rx: - kfree(*rx_p); -error_ret: - return ret; -} - -/** - * sca3000_read_first_n_hw_rb() - main ring access, pulls data from ring - * @r: the ring - * @count: number of samples to try and pull - * @data: output the actual samples pulled from the hw ring - * - * Currently does not provide timestamps. As the hardware doesn't add them they - * can only be inferred approximately from ring buffer events such as 50% full - * and knowledge of when buffer was last emptied. This is left to userspace. - **/ -static int sca3000_read_first_n_hw_rb(struct iio_buffer *r, - size_t count, char __user *buf) -{ - struct iio_hw_buffer *hw_ring = iio_to_hw_buf(r); - struct iio_dev *indio_dev = hw_ring->private; - struct sca3000_state *st = iio_priv(indio_dev); - u8 *rx; - int ret, i, num_available, num_read = 0; - int bytes_per_sample = 1; - - if (st->bpse == 11) - bytes_per_sample = 2; - - mutex_lock(&st->lock); - if (count % bytes_per_sample) { - ret = -EINVAL; - goto error_ret; - } - - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_BUF_COUNT, 1); - if (ret) - goto error_ret; - num_available = st->rx[0]; - /* - * num_available is the total number of samples available - * i.e. number of time points * number of channels. - */ - if (count > num_available * bytes_per_sample) - num_read = num_available * bytes_per_sample; - else - num_read = count; - - ret = sca3000_read_data(st, - SCA3000_REG_ADDR_RING_OUT, - &rx, num_read); - if (ret) - goto error_ret; - - for (i = 0; i < num_read / sizeof(u16); i++) - *(((u16 *)rx) + i) = be16_to_cpup((__be16 *)rx + i); - - if (copy_to_user(buf, rx, num_read)) - ret = -EFAULT; - kfree(rx); - r->stufftoread = 0; -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : num_read; -} - -static size_t sca3000_ring_buf_data_available(struct iio_buffer *r) -{ - return r->stufftoread ? r->watermark : 0; -} - -static ssize_t sca3000_show_buffer_scale(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - - return sprintf(buf, "0.%06d\n", 4 * st->info->scale); -} - -static IIO_DEVICE_ATTR(in_accel_scale, - S_IRUGO, - sca3000_show_buffer_scale, - NULL, - 0); - -/* - * Ring buffer attributes - * This device is a bit unusual in that the sampling frequency and bpse - * only apply to the ring buffer. At all times full rate and accuracy - * is available via direct reading from registers. - */ -static const struct attribute *sca3000_ring_attributes[] = { - &iio_dev_attr_in_accel_scale.dev_attr.attr, - NULL, -}; - -static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev) -{ - struct iio_buffer *buf; - struct iio_hw_buffer *ring; - - ring = kzalloc(sizeof(*ring), GFP_KERNEL); - if (!ring) - return NULL; - - ring->private = indio_dev; - buf = &ring->buf; - buf->stufftoread = 0; - buf->length = 64; - buf->attrs = sca3000_ring_attributes; - iio_buffer_init(buf); - - return buf; -} - -static void sca3000_ring_release(struct iio_buffer *r) -{ - kfree(iio_to_hw_buf(r)); -} - -static const struct iio_buffer_access_funcs sca3000_ring_access_funcs = { - .read_first_n = &sca3000_read_first_n_hw_rb, - .data_available = sca3000_ring_buf_data_available, - .release = sca3000_ring_release, - - .modes = INDIO_BUFFER_HARDWARE, -}; - static int sca3000_configure_ring(struct iio_dev *indio_dev) { struct iio_buffer *buffer; - buffer = sca3000_rb_allocate(indio_dev); + buffer = iio_kfifo_allocate(); if (!buffer) return -ENOMEM; - indio_dev->modes |= INDIO_BUFFER_HARDWARE; - buffer->access = &sca3000_ring_access_funcs; iio_device_attach_buffer(indio_dev, buffer); + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; return 0; } static void sca3000_unconfigure_ring(struct iio_dev *indio_dev) { - iio_buffer_put(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); } static inline @@ -1425,19 +1322,6 @@ static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) int ret; struct sca3000_state *st = iio_priv(indio_dev); - /* - * Set stuff to read to indicate no data present. - * Need for cases where the interrupt had fired at the - * end of a cycle, but the data was never read. - */ - indio_dev->buffer->stufftoread = 0; - /* - * Needed to ensure the core will actually read data - * from the device rather than assuming no channels - * are enabled. - */ - indio_dev->buffer->bytes_per_datum = 6; - mutex_lock(&st->lock); /* Enable the 50% full interrupt */ diff --git a/drivers/staging/iio/ring_hw.h b/drivers/staging/iio/ring_hw.h deleted file mode 100644 index 75bf47bfee78..000000000000 --- a/drivers/staging/iio/ring_hw.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * ring_hw.h - common functionality for iio hardware ring buffers - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * Copyright (c) 2009 Jonathan Cameron - * - */ - -#ifndef _RING_HW_H_ -#define _RING_HW_H_ - -/** - * struct iio_hw_ring_buffer- hardware ring buffer - * @buf: generic ring buffer elements - * @private: device specific data - */ -struct iio_hw_buffer { - struct iio_buffer buf; - void *private; -}; - -#define iio_to_hw_buf(r) container_of(r, struct iio_hw_buffer, buf) - -#endif /* _RING_HW_H_ */ -- cgit v1.2.3 From 2600e12b8ba677f78da745adbe601f411ba43d4a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:07 +0100 Subject: staging:iio:accel:sca3000 drop some unused variables. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index f9ab7b3f8e87..21428a4a3ec4 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -155,23 +155,19 @@ * struct sca3000_state - device instance state information * @us: the associated spi device * @info: chip variant information - * @interrupt_handler_ws: event interrupt handler for all events * @last_timestamp: the timestamp of the last event * @mo_det_use_count: reference counter for the motion detection unit * @lock: lock used to protect elements of sca3000_state * and the underlying device state. - * @bpse: number of bits per scan element * @tx: dma-able transmit buffer * @rx: dma-able receive buffer **/ struct sca3000_state { struct spi_device *us; const struct sca3000_chip_info *info; - struct work_struct interrupt_handler_ws; s64 last_timestamp; int mo_det_use_count; struct mutex lock; - int bpse; /* Can these share a cacheline ? */ u8 rx[384] ____cacheline_aligned; u8 tx[6] ____cacheline_aligned; @@ -1430,7 +1426,6 @@ static int sca3000_clean_setup(struct sca3000_state *st) goto error_ret; ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, (st->rx[0] & SCA3000_MODE_PROT_MASK)); - st->bpse = 11; error_ret: mutex_unlock(&st->lock); -- cgit v1.2.3 From 45ae5561acf52e82c838ba997dca5afc53ff1b61 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:08 +0100 Subject: staging:iio:accel:sca3000 use a 'fake' channel to handle freefall event registration. This is an approach used in some newer drivers as it exposes the compound channel events to the core rather than hiding their control in sysfs attributes entirely via the driver. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 303 ++++++++++++++++++------------------ 1 file changed, 155 insertions(+), 148 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index 21428a4a3ec4..ec8d6f56d14a 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -60,6 +60,7 @@ #define SCA3000_MEAS_MODE_NORMAL 0x00 #define SCA3000_MEAS_MODE_OP_1 0x01 #define SCA3000_MEAS_MODE_OP_2 0x02 +#define SCA3000_MODE_MASK 0x03 /* * In motion detection mode the accelerations are band pass filtered @@ -593,10 +594,25 @@ static const struct iio_event_spec sca3000_event = { .num_event_specs = 1, \ } +static const struct iio_event_spec sca3000_freefall_event_spec = { + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_PERIOD), +}; + static const struct iio_chan_spec sca3000_channels[] = { SCA3000_CHAN(0, IIO_MOD_X), SCA3000_CHAN(1, IIO_MOD_Y), SCA3000_CHAN(2, IIO_MOD_Z), + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X_AND_Y_AND_Z, + .scan_index = -1, /* Fake channel */ + .event_spec = &sca3000_freefall_event_spec, + .num_event_specs = 1, + }, }; static const struct iio_chan_spec sca3000_channels_with_temp[] = { @@ -611,6 +627,14 @@ static const struct iio_chan_spec sca3000_channels_with_temp[] = { /* No buffer support */ .scan_index = -1, }, + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X_AND_Y_AND_Z, + .scan_index = -1, /* Fake channel */ + .event_spec = &sca3000_freefall_event_spec, + .num_event_specs = 1, + }, }; static u8 sca3000_addresses[3][3] = { @@ -854,46 +878,54 @@ error_ret: static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sca3000_read_av_freq); /** - * sca3000_read_thresh() - query of a threshold + * sca3000_read_event_value() - query of a threshold or period **/ -static int sca3000_read_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int *val, int *val2) +static int sca3000_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { int ret, i; struct sca3000_state *st = iio_priv(indio_dev); int num = chan->channel2; + switch (info) { + case IIO_EV_INFO_VALUE: + mutex_lock(&st->lock); + ret = sca3000_read_ctrl_reg(st, sca3000_addresses[num][1]); + mutex_unlock(&st->lock); + if (ret < 0) + return ret; + *val = 0; + if (num == 1) + for_each_set_bit(i, (unsigned long *)&ret, + ARRAY_SIZE(st->info->mot_det_mult_y)) + *val += st->info->mot_det_mult_y[i]; + else + for_each_set_bit(i, (unsigned long *)&ret, + ARRAY_SIZE(st->info->mot_det_mult_xz)) + *val += st->info->mot_det_mult_xz[i]; - mutex_lock(&st->lock); - ret = sca3000_read_ctrl_reg(st, sca3000_addresses[num][1]); - mutex_unlock(&st->lock); - if (ret < 0) - return ret; - *val = 0; - if (num == 1) - for_each_set_bit(i, (unsigned long *)&ret, - ARRAY_SIZE(st->info->mot_det_mult_y)) - *val += st->info->mot_det_mult_y[i]; - else - for_each_set_bit(i, (unsigned long *)&ret, - ARRAY_SIZE(st->info->mot_det_mult_xz)) - *val += st->info->mot_det_mult_xz[i]; - - return IIO_VAL_INT; + return IIO_VAL_INT; + case IIO_EV_INFO_PERIOD: + *val = 0; + *val2 = 226000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } } /** - * sca3000_write_thresh() control of threshold + * sca3000_write_value() control of threshold and period **/ -static int sca3000_write_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int val, int val2) +static int sca3000_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { struct sca3000_state *st = iio_priv(indio_dev); int num = chan->channel2; @@ -901,7 +933,7 @@ static int sca3000_write_thresh(struct iio_dev *indio_dev, int i; u8 nonlinear = 0; - if (num == 1) { + if (num == IIO_MOD_Y) { i = ARRAY_SIZE(st->info->mot_det_mult_y); while (i > 0) if (val >= st->info->mot_det_mult_y[--i]) { @@ -1088,180 +1120,156 @@ static int sca3000_read_event_config(struct iio_dev *indio_dev, /* read current value of mode register */ mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); if (ret) goto error_ret; - if ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET) { - ret = 0; - } else { - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); - if (ret < 0) - goto error_ret; - /* only supporting logical or's for now */ - ret = !!(ret & sca3000_addresses[num][2]); + switch (chan->channel2) { + case IIO_MOD_X_AND_Y_AND_Z: + ret = !!(st->rx[0] & SCA3000_FREE_FALL_DETECT); + break; + case IIO_MOD_X: + case IIO_MOD_Y: + case IIO_MOD_Z: + /* + * Motion detection mode cannot run at the same time as + * acceleration data being read. + */ + if ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET) { + ret = 0; + } else { + ret = sca3000_read_ctrl_reg(st, + SCA3000_REG_CTRL_SEL_MD_CTRL); + if (ret < 0) + goto error_ret; + /* only supporting logical or's for now */ + ret = !!(ret & sca3000_addresses[num][2]); + } + break; + default: + ret = -EINVAL; } + error_ret: mutex_unlock(&st->lock); return ret; } -/** - * sca3000_query_free_fall_mode() is free fall mode enabled - **/ -static ssize_t sca3000_query_free_fall_mode(struct device *dev, - struct device_attribute *attr, - char *buf) +static int sca3000_freefall_set_state(struct iio_dev *indio_dev, int state) { - int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); - int val; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret < 0) - return ret; - return sprintf(buf, "%d\n", !!(val & SCA3000_FREE_FALL_DETECT)); -} - -/** - * sca3000_set_free_fall_mode() simple on off control for free fall int - * - * In these chips the free fall detector should send an interrupt if - * the device falls more than 25cm. This has not been tested due - * to fragile wiring. - **/ -static ssize_t sca3000_set_free_fall_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - u8 val; int ret; - u8 protect_mask = SCA3000_FREE_FALL_DETECT; - - mutex_lock(&st->lock); - ret = kstrtou8(buf, 10, &val); - if (ret) - goto error_ret; /* read current value of mode register */ ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); if (ret) - goto error_ret; + return ret; /* if off and should be on */ - if (val && !(st->rx[0] & protect_mask)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] | SCA3000_FREE_FALL_DETECT)); + if (state && !(st->rx[0] & SCA3000_FREE_FALL_DETECT)) + return sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + st->rx[0] | SCA3000_FREE_FALL_DETECT); /* if on and should be off */ - else if (!val && (st->rx[0] & protect_mask)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~protect_mask)); -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; + else if (!state && (st->rx[0] & SCA3000_FREE_FALL_DETECT)) + return sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + st->rx[0] & ~SCA3000_FREE_FALL_DETECT); + else + return 0; } -/** - * sca3000_write_event_config() simple on off control for motion detector - * - * This is a per axis control, but enabling any will result in the - * motion detector unit being enabled. - * N.B. enabling motion detector stops normal data acquisition. - * There is a complexity in knowing which mode to return to when - * this mode is disabled. Currently normal mode is assumed. - **/ -static int sca3000_write_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - int state) +static int sca3000_motion_detect_set_state(struct iio_dev *indio_dev, int axis, + int state) { struct sca3000_state *st = iio_priv(indio_dev); int ret, ctrlval; - u8 protect_mask = 0x03; - int num = chan->channel2; - mutex_lock(&st->lock); /* * First read the motion detector config to find out if * this axis is on */ ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); if (ret < 0) - goto exit_point; + return ret; ctrlval = ret; /* if off and should be on */ - if (state && !(ctrlval & sca3000_addresses[num][2])) { + if (state && !(ctrlval & sca3000_addresses[axis][2])) { ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL, ctrlval | - sca3000_addresses[num][2]); + sca3000_addresses[axis][2]); if (ret) - goto exit_point; + return ret; st->mo_det_use_count++; - } else if (!state && (ctrlval & sca3000_addresses[num][2])) { + } else if (!state && (ctrlval & sca3000_addresses[axis][2])) { ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL, ctrlval & - ~(sca3000_addresses[num][2])); + ~(sca3000_addresses[axis][2])); if (ret) - goto exit_point; + return ret; st->mo_det_use_count--; } /* read current value of mode register */ ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); if (ret) - goto exit_point; + return ret; /* if off and should be on */ if ((st->mo_det_use_count) && - ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~protect_mask) + ((st->rx[0] & SCA3000_MODE_MASK) != SCA3000_MEAS_MODE_MOT_DET)) + return sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + (st->rx[0] & ~SCA3000_MODE_MASK) | SCA3000_MEAS_MODE_MOT_DET); /* if on and should be off */ else if (!(st->mo_det_use_count) && - ((st->rx[0] & protect_mask) == SCA3000_MEAS_MODE_MOT_DET)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~protect_mask)); -exit_point: + ((st->rx[0] & SCA3000_MODE_MASK) == SCA3000_MEAS_MODE_MOT_DET)) + return sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + st->rx[0] & SCA3000_MODE_MASK); + else + return 0; +} + +/** + * sca3000_write_event_config() simple on off control for motion detector + * + * This is a per axis control, but enabling any will result in the + * motion detector unit being enabled. + * N.B. enabling motion detector stops normal data acquisition. + * There is a complexity in knowing which mode to return to when + * this mode is disabled. Currently normal mode is assumed. + **/ +static int sca3000_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + switch (chan->channel2) { + case IIO_MOD_X_AND_Y_AND_Z: + ret = sca3000_freefall_set_state(indio_dev, state); + break; + + case IIO_MOD_X: + case IIO_MOD_Y: + case IIO_MOD_Z: + ret = sca3000_motion_detect_set_state(indio_dev, chan->channel2, + state); + break; + default: + ret = -EINVAL; + break; + } mutex_unlock(&st->lock); return ret; } -/* Free fall detector related event attribute */ -static IIO_DEVICE_ATTR_NAMED(accel_xayaz_mag_falling_en, - in_accel_x & y & z_mag_falling_en, - S_IRUGO | S_IWUSR, - sca3000_query_free_fall_mode, - sca3000_set_free_fall_mode, - 0); - -static IIO_CONST_ATTR_NAMED(accel_xayaz_mag_falling_period, - in_accel_x & y & z_mag_falling_period, - "0.226"); - -static struct attribute *sca3000_event_attributes[] = { - &iio_dev_attr_accel_xayaz_mag_falling_en.dev_attr.attr, - &iio_const_attr_accel_xayaz_mag_falling_period.dev_attr.attr, - NULL, -}; - -static struct attribute_group sca3000_event_attribute_group = { - .attrs = sca3000_event_attributes, - .name = "events", -}; - static int sca3000_configure_ring(struct iio_dev *indio_dev) { struct iio_buffer *buffer; @@ -1436,9 +1444,8 @@ static const struct iio_info sca3000_info = { .attrs = &sca3000_attribute_group, .read_raw = &sca3000_read_raw, .write_raw = &sca3000_write_raw, - .event_attrs = &sca3000_event_attribute_group, - .read_event_value = &sca3000_read_thresh, - .write_event_value = &sca3000_write_thresh, + .read_event_value = &sca3000_read_event_value, + .write_event_value = &sca3000_write_event_value, .read_event_config = &sca3000_read_event_config, .write_event_config = &sca3000_write_event_config, .driver_module = THIS_MODULE, -- cgit v1.2.3 From 9bc11d32b3a47e09904f954a3a17a514779afaec Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:09 +0100 Subject: staging:iio:accel:sca3000 Clean up register defines. Introduce some more masks and generally drive towards consistent naming. Note the small indents used to indicate parts of registers + parts of multiplexed registers. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 328 ++++++++++++++++++------------------ 1 file changed, 165 insertions(+), 163 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index ec8d6f56d14a..86b0f104b592 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -28,111 +28,111 @@ #define SCA3000_WRITE_REG(a) (((a) << 2) | 0x02) #define SCA3000_READ_REG(a) ((a) << 2) -#define SCA3000_REG_ADDR_REVID 0x00 -#define SCA3000_REVID_MAJOR_MASK 0xf0 -#define SCA3000_REVID_MINOR_MASK 0x0f - -#define SCA3000_REG_ADDR_STATUS 0x02 -#define SCA3000_LOCKED 0x20 -#define SCA3000_EEPROM_CS_ERROR 0x02 -#define SCA3000_SPI_FRAME_ERROR 0x01 - +#define SCA3000_REG_REVID_ADDR 0x00 +#define SCA3000_REG_REVID_MAJOR_MASK GENMASK(8, 4) +#define SCA3000_REG_REVID_MINOR_MASK GENMASK(3, 0) + +#define SCA3000_REG_STATUS_ADDR 0x02 +#define SCA3000_LOCKED BIT(5) +#define SCA3000_EEPROM_CS_ERROR BIT(1) +#define SCA3000_SPI_FRAME_ERROR BIT(0) + /* All reads done using register decrement so no need to directly access LSBs */ -#define SCA3000_REG_ADDR_X_MSB 0x05 -#define SCA3000_REG_ADDR_Y_MSB 0x07 -#define SCA3000_REG_ADDR_Z_MSB 0x09 +#define SCA3000_REG_X_MSB_ADDR 0x05 +#define SCA3000_REG_Y_MSB_ADDR 0x07 +#define SCA3000_REG_Z_MSB_ADDR 0x09 -#define SCA3000_REG_ADDR_RING_OUT 0x0f +#define SCA3000_REG_RING_OUT_ADDR 0x0f /* Temp read untested - the e05 doesn't have the sensor */ -#define SCA3000_REG_ADDR_TEMP_MSB 0x13 +#define SCA3000_REG_TEMP_MSB_ADDR 0x13 -#define SCA3000_REG_ADDR_MODE 0x14 -#define SCA3000_MODE_PROT_MASK 0x28 +#define SCA3000_REG_MODE_ADDR 0x14 +#define SCA3000_MODE_PROT_MASK 0x28 +#define SCA3000_REG_MODE_RING_BUF_ENABLE BIT(7) +#define SCA3000_REG_MODE_RING_BUF_8BIT BIT(6) -#define SCA3000_RING_BUF_ENABLE 0x80 -#define SCA3000_RING_BUF_8BIT 0x40 /* * Free fall detection triggers an interrupt if the acceleration * is below a threshold for equivalent of 25cm drop */ -#define SCA3000_FREE_FALL_DETECT 0x10 -#define SCA3000_MEAS_MODE_NORMAL 0x00 -#define SCA3000_MEAS_MODE_OP_1 0x01 -#define SCA3000_MEAS_MODE_OP_2 0x02 -#define SCA3000_MODE_MASK 0x03 +#define SCA3000_REG_MODE_FREE_FALL_DETECT BIT(4) +#define SCA3000_REG_MODE_MEAS_MODE_NORMAL 0x00 +#define SCA3000_REG_MODE_MEAS_MODE_OP_1 0x01 +#define SCA3000_REG_MODE_MEAS_MODE_OP_2 0x02 /* * In motion detection mode the accelerations are band pass filtered * (approx 1 - 25Hz) and then a programmable threshold used to trigger * and interrupt. */ -#define SCA3000_MEAS_MODE_MOT_DET 0x03 - -#define SCA3000_REG_ADDR_BUF_COUNT 0x15 +#define SCA3000_REG_MODE_MEAS_MODE_MOT_DET 0x03 +#define SCA3000_REG_MODE_MODE_MASK 0x03 -#define SCA3000_REG_ADDR_INT_STATUS 0x16 +#define SCA3000_REG_BUF_COUNT_ADDR 0x15 -#define SCA3000_INT_STATUS_THREE_QUARTERS 0x80 -#define SCA3000_INT_STATUS_HALF 0x40 - -#define SCA3000_INT_STATUS_FREE_FALL 0x08 -#define SCA3000_INT_STATUS_Y_TRIGGER 0x04 -#define SCA3000_INT_STATUS_X_TRIGGER 0x02 -#define SCA3000_INT_STATUS_Z_TRIGGER 0x01 +#define SCA3000_REG_INT_STATUS_ADDR 0x16 +#define SCA3000_REG_INT_STATUS_THREE_QUARTERS BIT(7) +#define SCA3000_REG_INT_STATUS_HALF BIT(6) + +#define SCA3000_INT_STATUS_FREE_FALL BIT(3) +#define SCA3000_INT_STATUS_Y_TRIGGER BIT(2) +#define SCA3000_INT_STATUS_X_TRIGGER BIT(1) +#define SCA3000_INT_STATUS_Z_TRIGGER BIT(0) /* Used to allow access to multiplexed registers */ -#define SCA3000_REG_ADDR_CTRL_SEL 0x18 +#define SCA3000_REG_CTRL_SEL_ADDR 0x18 /* Only available for SCA3000-D03 and SCA3000-D01 */ -#define SCA3000_REG_CTRL_SEL_I2C_DISABLE 0x01 -#define SCA3000_REG_CTRL_SEL_MD_CTRL 0x02 -#define SCA3000_REG_CTRL_SEL_MD_Y_TH 0x03 -#define SCA3000_REG_CTRL_SEL_MD_X_TH 0x04 -#define SCA3000_REG_CTRL_SEL_MD_Z_TH 0x05 +#define SCA3000_REG_CTRL_SEL_I2C_DISABLE 0x01 +#define SCA3000_REG_CTRL_SEL_MD_CTRL 0x02 +#define SCA3000_REG_CTRL_SEL_MD_Y_TH 0x03 +#define SCA3000_REG_CTRL_SEL_MD_X_TH 0x04 +#define SCA3000_REG_CTRL_SEL_MD_Z_TH 0x05 /* * BE VERY CAREFUL WITH THIS, IF 3 BITS ARE NOT SET the device * will not function */ -#define SCA3000_REG_CTRL_SEL_OUT_CTRL 0x0B -#define SCA3000_OUT_CTRL_PROT_MASK 0xE0 -#define SCA3000_OUT_CTRL_BUF_X_EN 0x10 -#define SCA3000_OUT_CTRL_BUF_Y_EN 0x08 -#define SCA3000_OUT_CTRL_BUF_Z_EN 0x04 -#define SCA3000_OUT_CTRL_BUF_DIV_MASK 0x03 -#define SCA3000_OUT_CTRL_BUF_DIV_4 0x02 -#define SCA3000_OUT_CTRL_BUF_DIV_2 0x01 +#define SCA3000_REG_CTRL_SEL_OUT_CTRL 0x0B + +#define SCA3000_REG_OUT_CTRL_PROT_MASK 0xE0 +#define SCA3000_REG_OUT_CTRL_BUF_X_EN 0x10 +#define SCA3000_REG_OUT_CTRL_BUF_Y_EN 0x08 +#define SCA3000_REG_OUT_CTRL_BUF_Z_EN 0x04 +#define SCA3000_REG_OUT_CTRL_BUF_DIV_MASK 0x03 +#define SCA3000_REG_OUT_CTRL_BUF_DIV_4 0x02 +#define SCA3000_REG_OUT_CTRL_BUF_DIV_2 0x01 + /* * Control which motion detector interrupts are on. * For now only OR combinations are supported. */ -#define SCA3000_MD_CTRL_PROT_MASK 0xC0 -#define SCA3000_MD_CTRL_OR_Y 0x01 -#define SCA3000_MD_CTRL_OR_X 0x02 -#define SCA3000_MD_CTRL_OR_Z 0x04 +#define SCA3000_MD_CTRL_PROT_MASK 0xC0 +#define SCA3000_MD_CTRL_OR_Y BIT(0) +#define SCA3000_MD_CTRL_OR_X BIT(1) +#define SCA3000_MD_CTRL_OR_Z BIT(2) /* Currently unsupported */ -#define SCA3000_MD_CTRL_AND_Y 0x08 -#define SCA3000_MD_CTRL_AND_X 0x10 -#define SAC3000_MD_CTRL_AND_Z 0x20 +#define SCA3000_MD_CTRL_AND_Y BIT(3) +#define SCA3000_MD_CTRL_AND_X BIT(4) +#define SAC3000_MD_CTRL_AND_Z BIT(5) /* * Some control registers of complex access methods requiring this register to * be used to remove a lock. */ -#define SCA3000_REG_ADDR_UNLOCK 0x1e - -#define SCA3000_REG_ADDR_INT_MASK 0x21 -#define SCA3000_INT_MASK_PROT_MASK 0x1C +#define SCA3000_REG_UNLOCK_ADDR 0x1e -#define SCA3000_INT_MASK_RING_THREE_QUARTER 0x80 -#define SCA3000_INT_MASK_RING_HALF 0x40 - -#define SCA3000_INT_MASK_ALL_INTS 0x02 -#define SCA3000_INT_MASK_ACTIVE_HIGH 0x01 -#define SCA3000_INT_MASK_ACTIVE_LOW 0x00 +#define SCA3000_REG_INT_MASK_ADDR 0x21 +#define SCA3000_REG_INT_MASK_PROT_MASK 0x1C + +#define SCA3000_REG_INT_MASK_RING_THREE_QUARTER BIT(7) +#define SCA3000_REG_INT_MASK_RING_HALF BIT(6) +#define SCA3000_REG_INT_MASK_ALL_INTS 0x02 +#define SCA3000_REG_INT_MASK_ACTIVE_HIGH 0x01 +#define SCA3000_REG_INT_MASK_ACTIVE_LOW 0x00 /* Values of multiplexed registers (write to ctrl_data after select) */ -#define SCA3000_REG_ADDR_CTRL_DATA 0x22 +#define SCA3000_REG_CTRL_DATA_ADDR 0x22 /* * Measurement modes available on some sca3000 series chips. Code assumes others @@ -146,9 +146,9 @@ * * Wide - Widen low-pass filtering of signal channel to increase bandwidth */ -#define SCA3000_OP_MODE_BYPASS 0x01 -#define SCA3000_OP_MODE_NARROW 0x02 -#define SCA3000_OP_MODE_WIDE 0x04 +#define SCA3000_OP_MODE_BYPASS 0x01 +#define SCA3000_OP_MODE_NARROW 0x02 +#define SCA3000_OP_MODE_WIDE 0x04 #define SCA3000_MAX_TX 6 #define SCA3000_MAX_RX 2 @@ -288,7 +288,7 @@ static int sca3000_reg_lock_on(struct sca3000_state *st) { int ret; - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_STATUS, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_STATUS_ADDR, 1); if (ret < 0) return ret; @@ -318,11 +318,11 @@ static int __sca3000_unlock_reg_lock(struct sca3000_state *st) .tx_buf = st->tx + 4, }, }; - st->tx[0] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); + st->tx[0] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); st->tx[1] = 0x00; - st->tx[2] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); + st->tx[2] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); st->tx[3] = 0x50; - st->tx[4] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); + st->tx[4] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); st->tx[5] = 0xA0; return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); @@ -354,12 +354,12 @@ static int sca3000_write_ctrl_reg(struct sca3000_state *st, } /* Set the control select register */ - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_SEL, sel); + ret = sca3000_write_reg(st, SCA3000_REG_CTRL_SEL_ADDR, sel); if (ret) goto error_ret; /* Write the actual value into the register */ - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_DATA, val); + ret = sca3000_write_reg(st, SCA3000_REG_CTRL_DATA_ADDR, val); error_ret: return ret; @@ -384,10 +384,10 @@ static int sca3000_read_ctrl_reg(struct sca3000_state *st, goto error_ret; } /* Set the control select register */ - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_SEL, ctrl_reg); + ret = sca3000_write_reg(st, SCA3000_REG_CTRL_SEL_ADDR, ctrl_reg); if (ret) goto error_ret; - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_CTRL_DATA, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_CTRL_DATA_ADDR, 1); if (ret) goto error_ret; return st->rx[0]; @@ -407,13 +407,13 @@ static ssize_t sca3000_show_rev(struct device *dev, struct sca3000_state *st = iio_priv(indio_dev); mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_REVID, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_REVID_ADDR, 1); if (ret < 0) goto error_ret; len += sprintf(buf + len, - "major=%d, minor=%d\n", - st->rx[0] & SCA3000_REVID_MAJOR_MASK, - st->rx[0] & SCA3000_REVID_MINOR_MASK); + "major=%lu, minor=%lu\n", + st->rx[0] & SCA3000_REG_REVID_MAJOR_MASK, + st->rx[0] & SCA3000_REG_REVID_MINOR_MASK); error_ret: mutex_unlock(&st->lock); @@ -468,19 +468,19 @@ sca3000_show_measurement_mode(struct device *dev, int len = 0, ret; mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); if (ret) goto error_ret; /* mask bottom 2 bits - only ones that are relevant */ - st->rx[0] &= 0x03; + st->rx[0] &= SCA3000_REG_MODE_MODE_MASK; switch (st->rx[0]) { - case SCA3000_MEAS_MODE_NORMAL: + case SCA3000_REG_MODE_MEAS_MODE_NORMAL: len += sprintf(buf + len, "0 - normal mode\n"); break; - case SCA3000_MEAS_MODE_MOT_DET: + case SCA3000_REG_MODE_MEAS_MODE_MOT_DET: len += sprintf(buf + len, "3 - motion detection\n"); break; - case SCA3000_MEAS_MODE_OP_1: + case SCA3000_REG_MODE_MEAS_MODE_OP_1: switch (st->info->option_mode_1) { case SCA3000_OP_MODE_NARROW: len += sprintf(buf + len, "1 - narrow mode\n"); @@ -490,7 +490,7 @@ sca3000_show_measurement_mode(struct device *dev, break; } break; - case SCA3000_MEAS_MODE_OP_2: + case SCA3000_REG_MODE_MEAS_MODE_OP_2: switch (st->info->option_mode_2) { case SCA3000_OP_MODE_WIDE: len += sprintf(buf + len, "2 - wide mode\n"); @@ -517,7 +517,6 @@ sca3000_store_measurement_mode(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); int ret; - u8 mask = 0x03; u8 val; mutex_lock(&st->lock); @@ -528,12 +527,12 @@ sca3000_store_measurement_mode(struct device *dev, ret = -EINVAL; goto error_ret; } - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); if (ret) goto error_ret; - st->rx[0] &= ~mask; - st->rx[0] |= (val & mask); - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, st->rx[0]); + st->rx[0] &= ~SCA3000_REG_MODE_MODE_MASK; + st->rx[0] |= (val & SCA3000_REG_MODE_MODE_MASK); + ret = sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, st->rx[0]); if (ret) goto error_ret; mutex_unlock(&st->lock); @@ -638,11 +637,11 @@ static const struct iio_chan_spec sca3000_channels_with_temp[] = { }; static u8 sca3000_addresses[3][3] = { - [0] = {SCA3000_REG_ADDR_X_MSB, SCA3000_REG_CTRL_SEL_MD_X_TH, + [0] = {SCA3000_REG_X_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_X_TH, SCA3000_MD_CTRL_OR_X}, - [1] = {SCA3000_REG_ADDR_Y_MSB, SCA3000_REG_CTRL_SEL_MD_Y_TH, + [1] = {SCA3000_REG_Y_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_Y_TH, SCA3000_MD_CTRL_OR_Y}, - [2] = {SCA3000_REG_ADDR_Z_MSB, SCA3000_REG_CTRL_SEL_MD_Z_TH, + [2] = {SCA3000_REG_Z_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_Z_TH, SCA3000_MD_CTRL_OR_Z}, }; @@ -657,17 +656,17 @@ static inline int __sca3000_get_base_freq(struct sca3000_state *st, { int ret; - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); if (ret) goto error_ret; - switch (0x03 & st->rx[0]) { - case SCA3000_MEAS_MODE_NORMAL: + switch (SCA3000_REG_MODE_MODE_MASK & st->rx[0]) { + case SCA3000_REG_MODE_MEAS_MODE_NORMAL: *base_freq = info->measurement_mode_freq; break; - case SCA3000_MEAS_MODE_OP_1: + case SCA3000_REG_MODE_MEAS_MODE_OP_1: *base_freq = info->option_mode_1_freq; break; - case SCA3000_MEAS_MODE_OP_2: + case SCA3000_REG_MODE_MEAS_MODE_OP_2: *base_freq = info->option_mode_2_freq; break; default: @@ -695,12 +694,12 @@ static int read_raw_samp_freq(struct sca3000_state *st, int *val) return ret; if (*val > 0) { - ret &= SCA3000_OUT_CTRL_BUF_DIV_MASK; + ret &= SCA3000_REG_OUT_CTRL_BUF_DIV_MASK; switch (ret) { - case SCA3000_OUT_CTRL_BUF_DIV_2: + case SCA3000_REG_OUT_CTRL_BUF_DIV_2: *val /= 2; break; - case SCA3000_OUT_CTRL_BUF_DIV_4: + case SCA3000_REG_OUT_CTRL_BUF_DIV_4: *val /= 4; break; } @@ -726,12 +725,12 @@ static int write_raw_samp_freq(struct sca3000_state *st, int val) if (ret < 0) return ret; - ctrlval = ret & ~SCA3000_OUT_CTRL_BUF_DIV_MASK; + ctrlval = ret & ~SCA3000_REG_OUT_CTRL_BUF_DIV_MASK; if (val == base_freq / 2) - ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_2; + ctrlval |= SCA3000_REG_OUT_CTRL_BUF_DIV_2; if (val == base_freq / 4) - ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_4; + ctrlval |= SCA3000_REG_OUT_CTRL_BUF_DIV_4; else if (val != base_freq) return -EINVAL; @@ -769,7 +768,7 @@ static int sca3000_read_raw(struct iio_dev *indio_dev, } else { /* get the temperature when available */ ret = sca3000_read_data_short(st, - SCA3000_REG_ADDR_TEMP_MSB, + SCA3000_REG_TEMP_MSB_ADDR, 2); if (ret < 0) { mutex_unlock(&st->lock); @@ -840,26 +839,26 @@ static ssize_t sca3000_read_av_freq(struct device *dev, int len = 0, ret, val; mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); val = st->rx[0]; mutex_unlock(&st->lock); if (ret) goto error_ret; - switch (val & 0x03) { - case SCA3000_MEAS_MODE_NORMAL: + switch (val & SCA3000_REG_MODE_MODE_MASK) { + case SCA3000_REG_MODE_MEAS_MODE_NORMAL: len += sprintf(buf + len, "%d %d %d\n", st->info->measurement_mode_freq, st->info->measurement_mode_freq / 2, st->info->measurement_mode_freq / 4); break; - case SCA3000_MEAS_MODE_OP_1: + case SCA3000_REG_MODE_MEAS_MODE_OP_1: len += sprintf(buf + len, "%d %d %d\n", st->info->option_mode_1_freq, st->info->option_mode_1_freq / 2, st->info->option_mode_1_freq / 4); break; - case SCA3000_MEAS_MODE_OP_2: + case SCA3000_REG_MODE_MEAS_MODE_OP_2: len += sprintf(buf + len, "%d %d %d\n", st->info->option_mode_2_freq, st->info->option_mode_2_freq / 2, @@ -1006,8 +1005,9 @@ static void sca3000_ring_int_process(u8 val, struct iio_dev *indio_dev) int ret, i, num_available; mutex_lock(&st->lock); - if (val & SCA3000_INT_STATUS_HALF) { - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_BUF_COUNT, + + if (val & SCA3000_REG_INT_STATUS_HALF) { + ret = sca3000_read_data_short(st, SCA3000_REG_BUF_COUNT_ADDR, 1); if (ret) goto error_ret; @@ -1016,7 +1016,7 @@ static void sca3000_ring_int_process(u8 val, struct iio_dev *indio_dev) * num_available is the total number of samples available * i.e. number of time points * number of channels. */ - ret = sca3000_read_data(st, SCA3000_REG_ADDR_RING_OUT, st->rx, + ret = sca3000_read_data(st, SCA3000_REG_RING_OUT_ADDR, st->rx, num_available * 2); if (ret) goto error_ret; @@ -1057,7 +1057,7 @@ static irqreturn_t sca3000_event_handler(int irq, void *private) * but ensures no interrupt is missed. */ mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_STATUS, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_INT_STATUS_ADDR, 1); val = st->rx[0]; mutex_unlock(&st->lock); if (ret) @@ -1115,19 +1115,18 @@ static int sca3000_read_event_config(struct iio_dev *indio_dev, { struct sca3000_state *st = iio_priv(indio_dev); int ret; - u8 protect_mask = 0x03; int num = chan->channel2; /* read current value of mode register */ mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); if (ret) goto error_ret; switch (chan->channel2) { case IIO_MOD_X_AND_Y_AND_Z: - ret = !!(st->rx[0] & SCA3000_FREE_FALL_DETECT); + ret = !!(st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT); break; case IIO_MOD_X: case IIO_MOD_Y: @@ -1136,7 +1135,8 @@ static int sca3000_read_event_config(struct iio_dev *indio_dev, * Motion detection mode cannot run at the same time as * acceleration data being read. */ - if ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET) { + if ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) + != SCA3000_REG_MODE_MEAS_MODE_MOT_DET) { ret = 0; } else { ret = sca3000_read_ctrl_reg(st, @@ -1163,18 +1163,18 @@ static int sca3000_freefall_set_state(struct iio_dev *indio_dev, int state) int ret; /* read current value of mode register */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); if (ret) return ret; /* if off and should be on */ - if (state && !(st->rx[0] & SCA3000_FREE_FALL_DETECT)) - return sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - st->rx[0] | SCA3000_FREE_FALL_DETECT); + if (state && !(st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + st->rx[0] | SCA3000_REG_MODE_FREE_FALL_DETECT); /* if on and should be off */ - else if (!state && (st->rx[0] & SCA3000_FREE_FALL_DETECT)) - return sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - st->rx[0] & ~SCA3000_FREE_FALL_DETECT); + else if (!state && (st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + st->rx[0] & ~SCA3000_REG_MODE_FREE_FALL_DETECT); else return 0; } @@ -1213,20 +1213,22 @@ static int sca3000_motion_detect_set_state(struct iio_dev *indio_dev, int axis, } /* read current value of mode register */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); if (ret) return ret; /* if off and should be on */ if ((st->mo_det_use_count) && - ((st->rx[0] & SCA3000_MODE_MASK) != SCA3000_MEAS_MODE_MOT_DET)) - return sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~SCA3000_MODE_MASK) - | SCA3000_MEAS_MODE_MOT_DET); + ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) + != SCA3000_REG_MODE_MEAS_MODE_MOT_DET)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + (st->rx[0] & ~SCA3000_REG_MODE_MODE_MASK) + | SCA3000_REG_MODE_MEAS_MODE_MOT_DET); /* if on and should be off */ else if (!(st->mo_det_use_count) && - ((st->rx[0] & SCA3000_MODE_MASK) == SCA3000_MEAS_MODE_MOT_DET)) - return sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - st->rx[0] & SCA3000_MODE_MASK); + ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) + == SCA3000_REG_MODE_MEAS_MODE_MOT_DET)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + st->rx[0] & SCA3000_REG_MODE_MODE_MASK); else return 0; } @@ -1296,18 +1298,18 @@ int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state) int ret; mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); if (ret) goto error_ret; if (state) { dev_info(&indio_dev->dev, "supposedly enabling ring buffer\n"); ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_MODE, - (st->rx[0] | SCA3000_RING_BUF_ENABLE)); + SCA3000_REG_MODE_ADDR, + (st->rx[0] | SCA3000_REG_MODE_RING_BUF_ENABLE)); } else ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~SCA3000_RING_BUF_ENABLE)); + SCA3000_REG_MODE_ADDR, + (st->rx[0] & ~SCA3000_REG_MODE_RING_BUF_ENABLE)); error_ret: mutex_unlock(&st->lock); @@ -1329,12 +1331,12 @@ static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) mutex_lock(&st->lock); /* Enable the 50% full interrupt */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); if (ret) goto error_unlock; ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_INT_MASK, - st->rx[0] | SCA3000_INT_MASK_RING_HALF); + SCA3000_REG_INT_MASK_ADDR, + st->rx[0] | SCA3000_REG_INT_MASK_RING_HALF); if (ret) goto error_unlock; @@ -1360,12 +1362,12 @@ static int sca3000_hw_ring_postdisable(struct iio_dev *indio_dev) /* Disable the 50% full interrupt */ mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); if (ret) goto unlock; ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_INT_MASK, - st->rx[0] & ~SCA3000_INT_MASK_RING_HALF); + SCA3000_REG_INT_MASK_ADDR, + st->rx[0] & ~SCA3000_REG_INT_MASK_RING_HALF); unlock: mutex_unlock(&st->lock); return ret; @@ -1389,7 +1391,7 @@ static int sca3000_clean_setup(struct sca3000_state *st) mutex_lock(&st->lock); /* Ensure all interrupts have been acknowledged */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_STATUS, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_INT_STATUS_ADDR, 1); if (ret) goto error_ret; @@ -1407,21 +1409,21 @@ static int sca3000_clean_setup(struct sca3000_state *st) if (ret < 0) goto error_ret; ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, - (ret & SCA3000_OUT_CTRL_PROT_MASK) - | SCA3000_OUT_CTRL_BUF_X_EN - | SCA3000_OUT_CTRL_BUF_Y_EN - | SCA3000_OUT_CTRL_BUF_Z_EN - | SCA3000_OUT_CTRL_BUF_DIV_4); + (ret & SCA3000_REG_OUT_CTRL_PROT_MASK) + | SCA3000_REG_OUT_CTRL_BUF_X_EN + | SCA3000_REG_OUT_CTRL_BUF_Y_EN + | SCA3000_REG_OUT_CTRL_BUF_Z_EN + | SCA3000_REG_OUT_CTRL_BUF_DIV_4); if (ret) goto error_ret; /* Enable interrupts, relevant to mode and set up as active low */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); if (ret) goto error_ret; ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_INT_MASK, - (ret & SCA3000_INT_MASK_PROT_MASK) - | SCA3000_INT_MASK_ACTIVE_LOW); + SCA3000_REG_INT_MASK_ADDR, + (ret & SCA3000_REG_INT_MASK_PROT_MASK) + | SCA3000_REG_INT_MASK_ACTIVE_LOW); if (ret) goto error_ret; /* @@ -1429,10 +1431,10 @@ static int sca3000_clean_setup(struct sca3000_state *st) * Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5 * as that occurs in one of the example on the datasheet */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); if (ret) goto error_ret; - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + ret = sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, (st->rx[0] & SCA3000_MODE_PROT_MASK)); error_ret: @@ -1515,14 +1517,14 @@ static int sca3000_stop_all_interrupts(struct sca3000_state *st) int ret; mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); if (ret) goto error_ret; - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_INT_MASK, + ret = sca3000_write_reg(st, SCA3000_REG_INT_MASK_ADDR, (st->rx[0] & - ~(SCA3000_INT_MASK_RING_THREE_QUARTER | - SCA3000_INT_MASK_RING_HALF | - SCA3000_INT_MASK_ALL_INTS))); + ~(SCA3000_REG_INT_MASK_RING_THREE_QUARTER | + SCA3000_REG_INT_MASK_RING_HALF | + SCA3000_REG_INT_MASK_ALL_INTS))); error_ret: mutex_unlock(&st->lock); return ret; -- cgit v1.2.3 From 085fe1b2e3df91a085d15a0bdc3f03cef6a42dab Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:10 +0100 Subject: staging:iio:accel:sca3000 add readback of the 3db low pass filter frequency Driving towards getting rid of the non standard mode control interface. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 48 ++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index 86b0f104b592..8aa6980406f1 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -191,10 +191,13 @@ struct sca3000_chip_info { unsigned int scale; bool temp_output; int measurement_mode_freq; + int measurement_mode_3db_freq; int option_mode_1; int option_mode_1_freq; + int option_mode_1_3db_freq; int option_mode_2; int option_mode_2_freq; + int option_mode_2_3db_freq; int mot_det_mult_xz[6]; int mot_det_mult_y[7]; }; @@ -219,36 +222,46 @@ static const struct sca3000_chip_info sca3000_spi_chip_info_tbl[] = { .scale = 7357, .temp_output = true, .measurement_mode_freq = 250, + .measurement_mode_3db_freq = 45, .option_mode_1 = SCA3000_OP_MODE_BYPASS, .option_mode_1_freq = 250, + .option_mode_1_3db_freq = 70, .mot_det_mult_xz = {50, 100, 200, 350, 650, 1300}, .mot_det_mult_y = {50, 100, 150, 250, 450, 850, 1750}, }, [e02] = { .scale = 9810, .measurement_mode_freq = 125, + .measurement_mode_3db_freq = 40, .option_mode_1 = SCA3000_OP_MODE_NARROW, .option_mode_1_freq = 63, + .option_mode_1_3db_freq = 11, .mot_det_mult_xz = {100, 150, 300, 550, 1050, 2050}, .mot_det_mult_y = {50, 100, 200, 350, 700, 1350, 2700}, }, [e04] = { .scale = 19620, .measurement_mode_freq = 100, + .measurement_mode_3db_freq = 38, .option_mode_1 = SCA3000_OP_MODE_NARROW, .option_mode_1_freq = 50, + .option_mode_1_3db_freq = 9, .option_mode_2 = SCA3000_OP_MODE_WIDE, .option_mode_2_freq = 400, + .option_mode_2_3db_freq = 70, .mot_det_mult_xz = {200, 300, 600, 1100, 2100, 4100}, .mot_det_mult_y = {100, 200, 400, 7000, 1400, 2700, 54000}, }, [e05] = { .scale = 61313, .measurement_mode_freq = 200, + .measurement_mode_3db_freq = 60, .option_mode_1 = SCA3000_OP_MODE_NARROW, .option_mode_1_freq = 50, + .option_mode_1_3db_freq = 9, .option_mode_2 = SCA3000_OP_MODE_WIDE, .option_mode_2_freq = 400, + .option_mode_2_3db_freq = 75, .mot_det_mult_xz = {600, 900, 1700, 3200, 6100, 11900}, .mot_det_mult_y = {300, 600, 1200, 2000, 4100, 7800, 15600}, }, @@ -578,7 +591,8 @@ static const struct iio_event_spec sca3000_event = { .modified = 1, \ .channel2 = mod, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |\ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),\ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ .address = index, \ .scan_index = index, \ @@ -738,6 +752,33 @@ static int write_raw_samp_freq(struct sca3000_state *st, int val) ctrlval); } +static int sca3000_read_3db_freq(struct sca3000_state *st, int *val) +{ + int ret; + + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + return ret; + + /* mask bottom 2 bits - only ones that are relevant */ + st->rx[0] &= SCA3000_REG_MODE_MODE_MASK; + switch (st->rx[0]) { + case SCA3000_REG_MODE_MEAS_MODE_NORMAL: + *val = st->info->measurement_mode_3db_freq; + return IIO_VAL_INT; + case SCA3000_REG_MODE_MEAS_MODE_MOT_DET: + return -EBUSY; + case SCA3000_REG_MODE_MEAS_MODE_OP_1: + *val = st->info->option_mode_1_3db_freq; + return IIO_VAL_INT; + case SCA3000_REG_MODE_MEAS_MODE_OP_2: + *val = st->info->option_mode_2_3db_freq; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + static int sca3000_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, @@ -795,6 +836,11 @@ static int sca3000_read_raw(struct iio_dev *indio_dev, ret = read_raw_samp_freq(st, val); mutex_unlock(&st->lock); return ret ? ret : IIO_VAL_INT; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + mutex_lock(&st->lock); + ret = sca3000_read_3db_freq(st, val); + mutex_unlock(&st->lock); + return ret; default: return -EINVAL; } -- cgit v1.2.3 From 74bdc940757608876a77cc0cdc2877b66e5dd47d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:11 +0100 Subject: staging:iio:accel:sca3000: Fix off by one error in axis due to IIO_NO_MOD Given the introduction of IIO_NO_MOD was prior to the first submission prior to IIO entering staging this has been broken for a while. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index 8aa6980406f1..b5dc40523bb5 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -934,16 +934,17 @@ static int sca3000_read_event_value(struct iio_dev *indio_dev, { int ret, i; struct sca3000_state *st = iio_priv(indio_dev); - int num = chan->channel2; + switch (info) { case IIO_EV_INFO_VALUE: mutex_lock(&st->lock); - ret = sca3000_read_ctrl_reg(st, sca3000_addresses[num][1]); + ret = sca3000_read_ctrl_reg(st, + sca3000_addresses[chan->address][1]); mutex_unlock(&st->lock); if (ret < 0) return ret; *val = 0; - if (num == 1) + if (chan->channel2 == IIO_MOD_Y) for_each_set_bit(i, (unsigned long *)&ret, ARRAY_SIZE(st->info->mot_det_mult_y)) *val += st->info->mot_det_mult_y[i]; @@ -973,12 +974,11 @@ static int sca3000_write_event_value(struct iio_dev *indio_dev, int val, int val2) { struct sca3000_state *st = iio_priv(indio_dev); - int num = chan->channel2; int ret; int i; u8 nonlinear = 0; - if (num == IIO_MOD_Y) { + if (chan->channel2 == IIO_MOD_Y) { i = ARRAY_SIZE(st->info->mot_det_mult_y); while (i > 0) if (val >= st->info->mot_det_mult_y[--i]) { @@ -995,7 +995,9 @@ static int sca3000_write_event_value(struct iio_dev *indio_dev, } mutex_lock(&st->lock); - ret = sca3000_write_ctrl_reg(st, sca3000_addresses[num][1], nonlinear); + ret = sca3000_write_ctrl_reg(st, + sca3000_addresses[chan->address][1], + nonlinear); mutex_unlock(&st->lock); return ret; @@ -1161,8 +1163,6 @@ static int sca3000_read_event_config(struct iio_dev *indio_dev, { struct sca3000_state *st = iio_priv(indio_dev); int ret; - int num = chan->channel2; - /* read current value of mode register */ mutex_lock(&st->lock); @@ -1190,7 +1190,7 @@ static int sca3000_read_event_config(struct iio_dev *indio_dev, if (ret < 0) goto error_ret; /* only supporting logical or's for now */ - ret = !!(ret & sca3000_addresses[num][2]); + ret = !!(ret & sca3000_addresses[chan->address][2]); } break; default: @@ -1306,7 +1306,8 @@ static int sca3000_write_event_config(struct iio_dev *indio_dev, case IIO_MOD_X: case IIO_MOD_Y: case IIO_MOD_Z: - ret = sca3000_motion_detect_set_state(indio_dev, chan->channel2, + ret = sca3000_motion_detect_set_state(indio_dev, + chan->address, state); break; default: -- cgit v1.2.3 From 626f971b5b07298e24359999970d0f758253af1e Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:12 +0100 Subject: staging:iio:accel:sca3000 Add write support to the low pass filter control Also includes an available attribute. The ordering of values appears a bit random, but as the ABI doesn't specify this and we already have both rising and falling lists I think this is fine. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index b5dc40523bb5..f5ced157ead9 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -433,6 +433,26 @@ error_ret: return ret ? ret : len; } +static ssize_t +sca3000_show_available_3db_freqs(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + int len; + + len = sprintf(buf, "%d", st->info->measurement_mode_3db_freq); + if (st->info->option_mode_1) + len += sprintf(buf + len, " %d", + st->info->option_mode_1_3db_freq); + if (st->info->option_mode_2) + len += sprintf(buf + len, " %d", + st->info->option_mode_2_3db_freq); + len += sprintf(buf + len, "\n"); + + return len; +} /** * sca3000_show_available_measurement_modes() display available modes * @@ -571,6 +591,9 @@ static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR, sca3000_store_measurement_mode, 0); +static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, + S_IRUGO, sca3000_show_available_3db_freqs, + NULL, 0); /* More standard attributes */ static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0); @@ -779,6 +802,31 @@ static int sca3000_read_3db_freq(struct sca3000_state *st, int *val) } } +static int sca3000_write_3db_freq(struct sca3000_state *st, int val) +{ + int ret; + int mode; + + if (val == st->info->measurement_mode_3db_freq) + mode = SCA3000_REG_MODE_MEAS_MODE_NORMAL; + else if (st->info->option_mode_1 && + (val == st->info->option_mode_1_3db_freq)) + mode = SCA3000_REG_MODE_MEAS_MODE_OP_1; + else if (st->info->option_mode_2 && + (val == st->info->option_mode_2_3db_freq)) + mode = SCA3000_REG_MODE_MEAS_MODE_OP_2; + else + return -EINVAL; + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + return ret; + + st->rx[0] &= ~SCA3000_REG_MODE_MODE_MASK; + st->rx[0] |= (mode & SCA3000_REG_MODE_MODE_MASK); + + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, st->rx[0]); +} + static int sca3000_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, @@ -861,6 +909,12 @@ static int sca3000_write_raw(struct iio_dev *indio_dev, ret = write_raw_samp_freq(st, val); mutex_unlock(&st->lock); return ret; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + if (val2) + return -EINVAL; + mutex_lock(&st->lock); + ret = sca3000_write_3db_freq(st, val); + mutex_unlock(&st->lock); default: return -EINVAL; } @@ -1007,6 +1061,7 @@ static struct attribute *sca3000_attributes[] = { &iio_dev_attr_revision.dev_attr.attr, &iio_dev_attr_measurement_mode_available.dev_attr.attr, &iio_dev_attr_measurement_mode.dev_attr.attr, + &iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr, &iio_dev_attr_sampling_frequency_available.dev_attr.attr, NULL, }; -- cgit v1.2.3 From 6831c17236a4ad005fb37be94bc7a18305e99bda Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:13 +0100 Subject: staging:iio:accel:sca3000 Drop custom measurement mode attributes This is now represented by the standard 3db filter frequency controls. Things get complex wrt to the sampling frequency as these modes change but that is fine under the IIO ABI where any value is allowed to effect any other. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 139 ------------------------------------ 1 file changed, 139 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index f5ced157ead9..211e1fd6c6e6 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -453,143 +453,6 @@ sca3000_show_available_3db_freqs(struct device *dev, return len; } -/** - * sca3000_show_available_measurement_modes() display available modes - * - * This is all read from chip specific data in the driver. Not all - * of the sca3000 series support modes other than normal. - **/ -static ssize_t -sca3000_show_available_measurement_modes(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int len = 0; - - len += sprintf(buf + len, "0 - normal mode"); - switch (st->info->option_mode_1) { - case SCA3000_OP_MODE_NARROW: - len += sprintf(buf + len, ", 1 - narrow mode"); - break; - 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"); - break; - } - /* always supported */ - len += sprintf(buf + len, " 3 - motion detection\n"); - - return len; -} - -/** - * sca3000_show_measurement_mode() sysfs read of current mode - **/ -static ssize_t -sca3000_show_measurement_mode(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int len = 0, ret; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); - if (ret) - goto error_ret; - /* mask bottom 2 bits - only ones that are relevant */ - st->rx[0] &= SCA3000_REG_MODE_MODE_MASK; - switch (st->rx[0]) { - case SCA3000_REG_MODE_MEAS_MODE_NORMAL: - len += sprintf(buf + len, "0 - normal mode\n"); - break; - case SCA3000_REG_MODE_MEAS_MODE_MOT_DET: - len += sprintf(buf + len, "3 - motion detection\n"); - break; - case SCA3000_REG_MODE_MEAS_MODE_OP_1: - switch (st->info->option_mode_1) { - case SCA3000_OP_MODE_NARROW: - len += sprintf(buf + len, "1 - narrow mode\n"); - break; - case SCA3000_OP_MODE_BYPASS: - len += sprintf(buf + len, "1 - bypass mode\n"); - break; - } - break; - case SCA3000_REG_MODE_MEAS_MODE_OP_2: - switch (st->info->option_mode_2) { - case SCA3000_OP_MODE_WIDE: - len += sprintf(buf + len, "2 - wide mode\n"); - break; - } - break; - } - -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -/** - * sca3000_store_measurement_mode() set the current mode - **/ -static ssize_t -sca3000_store_measurement_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - u8 val; - - mutex_lock(&st->lock); - ret = kstrtou8(buf, 10, &val); - if (ret) - goto error_ret; - if (val > 3) { - ret = -EINVAL; - goto error_ret; - } - ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); - if (ret) - goto error_ret; - st->rx[0] &= ~SCA3000_REG_MODE_MODE_MASK; - st->rx[0] |= (val & SCA3000_REG_MODE_MODE_MASK); - ret = sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, st->rx[0]); - if (ret) - goto error_ret; - mutex_unlock(&st->lock); - - return len; - -error_ret: - mutex_unlock(&st->lock); - - return ret; -} - -/* - * Not even vaguely standard attributes so defined here rather than - * in the relevant IIO core headers - */ -static IIO_DEVICE_ATTR(measurement_mode_available, S_IRUGO, - sca3000_show_available_measurement_modes, - NULL, 0); - -static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR, - sca3000_show_measurement_mode, - sca3000_store_measurement_mode, - 0); static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, S_IRUGO, sca3000_show_available_3db_freqs, @@ -1059,8 +922,6 @@ static int sca3000_write_event_value(struct iio_dev *indio_dev, static struct attribute *sca3000_attributes[] = { &iio_dev_attr_revision.dev_attr.attr, - &iio_dev_attr_measurement_mode_available.dev_attr.attr, - &iio_dev_attr_measurement_mode.dev_attr.attr, &iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr, &iio_dev_attr_sampling_frequency_available.dev_attr.attr, NULL, -- cgit v1.2.3 From 7ab9fa0052878c331670ef5a2a1ef09ec3111dea Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:14 +0100 Subject: staging:iio:accel:sca3000 replace non standard revision attr with dev_info on probe There seems little point in being able to query the part revision number via sysfs. Hence just put it in the kernel logs during probe incase anyone ever wants to know. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index 211e1fd6c6e6..586c120dbf41 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -411,26 +411,23 @@ error_ret: /** * sca3000_show_rev() - sysfs interface to read the chip revision number **/ -static ssize_t sca3000_show_rev(struct device *dev, - struct device_attribute *attr, - char *buf) +static int sca3000_print_rev(struct iio_dev *indio_dev) { - int len = 0, ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); + int ret; struct sca3000_state *st = iio_priv(indio_dev); mutex_lock(&st->lock); ret = sca3000_read_data_short(st, SCA3000_REG_REVID_ADDR, 1); if (ret < 0) goto error_ret; - len += sprintf(buf + len, - "major=%lu, minor=%lu\n", - st->rx[0] & SCA3000_REG_REVID_MAJOR_MASK, - st->rx[0] & SCA3000_REG_REVID_MINOR_MASK); + dev_info(&indio_dev->dev, + "sca3000 revision major=%lu, minor=%lu\n", + st->rx[0] & SCA3000_REG_REVID_MAJOR_MASK, + st->rx[0] & SCA3000_REG_REVID_MINOR_MASK); error_ret: mutex_unlock(&st->lock); - return ret ? ret : len; + return ret; } static ssize_t @@ -457,9 +454,6 @@ sca3000_show_available_3db_freqs(struct device *dev, static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, S_IRUGO, sca3000_show_available_3db_freqs, NULL, 0); -/* More standard attributes */ - -static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0); static const struct iio_event_spec sca3000_event = { .type = IIO_EV_TYPE_MAG, @@ -921,7 +915,6 @@ static int sca3000_write_event_value(struct iio_dev *indio_dev, } static struct attribute *sca3000_attributes[] = { - &iio_dev_attr_revision.dev_attr.attr, &iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr, &iio_dev_attr_sampling_frequency_available.dev_attr.attr, NULL, @@ -1465,6 +1458,11 @@ static int sca3000_probe(struct spi_device *spi) ret = sca3000_clean_setup(st); if (ret) goto error_free_irq; + + ret = sca3000_print_rev(indio_dev); + if (ret) + goto error_free_irq; + return 0; error_free_irq: -- cgit v1.2.3 From 9a4936dc89a34e002946a6c08b330918ec6afab8 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:15 +0100 Subject: staging:iio:accel:sca3000 Tidy up probe order to avoid a race. Previously the device was exposed to userspace and in kernel consumers before the interrupts had been configured. As nothing stopped them being enabled in the interval this could cause unhandled interrupts. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index 586c120dbf41..6ffd608a2b36 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -1440,9 +1440,6 @@ static int sca3000_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; sca3000_configure_ring(indio_dev); - ret = iio_device_register(indio_dev); - if (ret < 0) - return ret; if (spi->irq) { ret = request_threaded_irq(spi->irq, @@ -1452,7 +1449,7 @@ static int sca3000_probe(struct spi_device *spi) "sca3000", indio_dev); if (ret) - goto error_unregister_dev; + return ret; } indio_dev->setup_ops = &sca3000_ring_setup_ops; ret = sca3000_clean_setup(st); @@ -1463,13 +1460,12 @@ static int sca3000_probe(struct spi_device *spi) if (ret) goto error_free_irq; - return 0; + return iio_device_register(indio_dev); error_free_irq: if (spi->irq) free_irq(spi->irq, indio_dev); -error_unregister_dev: - iio_device_unregister(indio_dev); + return ret; } @@ -1496,11 +1492,13 @@ static int sca3000_remove(struct spi_device *spi) struct iio_dev *indio_dev = spi_get_drvdata(spi); struct sca3000_state *st = iio_priv(indio_dev); + iio_device_unregister(indio_dev); + /* Must ensure no interrupts can be generated after this! */ sca3000_stop_all_interrupts(st); if (spi->irq) free_irq(spi->irq, indio_dev); - iio_device_unregister(indio_dev); + sca3000_unconfigure_ring(indio_dev); return 0; -- cgit v1.2.3 From 389c583fd8cf48a80d9352a43d50619d7bbe124c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:16 +0100 Subject: staging:iio:accel:sca3000 small checkpatch fixes (alignment etc) Tidied up where checkpatch warning suppressions doesn't effect the readability of the code. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index 6ffd608a2b36..c0542f3d18dd 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -275,8 +275,8 @@ static int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val) } static int sca3000_read_data_short(struct sca3000_state *st, - u8 reg_address_high, - int len) + u8 reg_address_high, + int len) { struct spi_transfer xfer[2] = { { -- cgit v1.2.3 From 2ccf61442ff142d2dde7c47471c2798a4d78b0ad Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:17 +0100 Subject: staging:iio:accel:sca3000 kernel docify comments that were nearly kernel doc. Basic tidy up of comments to bring them into a standard style. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/staging/iio/accel/sca3000.c | 106 ++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c index c0542f3d18dd..cb1d83fa19a0 100644 --- a/drivers/staging/iio/accel/sca3000.c +++ b/drivers/staging/iio/accel/sca3000.c @@ -179,10 +179,20 @@ struct sca3000_state { * @scale: scale * 10^-6 * @temp_output: some devices have temperature sensors. * @measurement_mode_freq: normal mode sampling frequency + * @measurement_mode_3db_freq: 3db cutoff frequency of the low pass filter for + * the normal measurement mode. * @option_mode_1: first optional mode. Not all models have one * @option_mode_1_freq: option mode 1 sampling frequency + * @option_mode_1_3db_freq: 3db cutoff frequency of the low pass filter for + * the first option mode. * @option_mode_2: second optional mode. Not all chips have one * @option_mode_2_freq: option mode 2 sampling frequency + * @option_mode_2_3db_freq: 3db cutoff frequency of the low pass filter for + * the second option mode. + * @mod_det_mult_xz: Bit wise multipliers to calculate the threshold + * for motion detection in the x and z axis. + * @mod_det_mult_y: Bit wise multipliers to calculate the threshold + * for motion detection in the y axis. * * This structure is used to hold information about the functionality of a given * sca3000 variant. @@ -293,7 +303,8 @@ static int sca3000_read_data_short(struct sca3000_state *st, } /** - * sca3000_reg_lock_on() test if the ctrl register lock is on + * sca3000_reg_lock_on() - test if the ctrl register lock is on + * @st: Driver specific device instance data. * * Lock must be held. **/ @@ -309,12 +320,13 @@ static int sca3000_reg_lock_on(struct sca3000_state *st) } /** - * __sca3000_unlock_reg_lock() unlock the control registers + * __sca3000_unlock_reg_lock() - unlock the control registers + * @st: Driver specific device instance data. * * Note the device does not appear to support doing this in a single transfer. * This should only ever be used as part of ctrl reg read. * Lock must be held before calling this - **/ + */ static int __sca3000_unlock_reg_lock(struct sca3000_state *st) { struct spi_transfer xfer[3] = { @@ -343,6 +355,7 @@ static int __sca3000_unlock_reg_lock(struct sca3000_state *st) /** * sca3000_write_ctrl_reg() write to a lock protect ctrl register + * @st: Driver specific device instance data. * @sel: selects which registers we wish to write to * @val: the value to be written * @@ -350,7 +363,7 @@ static int __sca3000_unlock_reg_lock(struct sca3000_state *st) * register and use a shared write address. This function allows writing of * these registers. * Lock must be held. - **/ + */ static int sca3000_write_ctrl_reg(struct sca3000_state *st, u8 sel, uint8_t val) @@ -380,9 +393,11 @@ error_ret: /** * sca3000_read_ctrl_reg() read from lock protected control register. + * @st: Driver specific device instance data. + * @ctrl_reg: Which ctrl register do we want to read. * * Lock must be held. - **/ + */ static int sca3000_read_ctrl_reg(struct sca3000_state *st, u8 ctrl_reg) { @@ -410,7 +425,10 @@ error_ret: /** * sca3000_show_rev() - sysfs interface to read the chip revision number - **/ + * @indio_dev: Device instance specific generic IIO data. + * Driver specific device instance data can be obtained via + * via iio_priv(indio_dev) + */ static int sca3000_print_rev(struct iio_dev *indio_dev) { int ret; @@ -540,10 +558,13 @@ static u8 sca3000_addresses[3][3] = { }; /** - * __sca3000_get_base_freq() obtain mode specific base frequency + * __sca3000_get_base_freq() - obtain mode specific base frequency + * @st: Private driver specific device instance specific state. + * @info: chip type specific information. + * @base_freq: Base frequency for the current measurement mode. * * lock must be held - **/ + */ static inline int __sca3000_get_base_freq(struct sca3000_state *st, const struct sca3000_chip_info *info, int *base_freq) @@ -571,11 +592,13 @@ error_ret: } /** - * read_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * sca3000_read_raw_samp_freq() - read_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * @st: Private driver specific device instance specific state. + * @val: The frequency read back. * * lock must be held **/ -static int read_raw_samp_freq(struct sca3000_state *st, int *val) +static int sca3000_read_raw_samp_freq(struct sca3000_state *st, int *val) { int ret; @@ -603,11 +626,13 @@ static int read_raw_samp_freq(struct sca3000_state *st, int *val) } /** - * write_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * sca3000_write_raw_samp_freq() - write_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * @st: Private driver specific device instance specific state. + * @val: The frequency desired. * * lock must be held - **/ -static int write_raw_samp_freq(struct sca3000_state *st, int val) + */ +static int sca3000_write_raw_samp_freq(struct sca3000_state *st, int val) { int ret, base_freq, ctrlval; @@ -738,7 +763,7 @@ static int sca3000_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: mutex_lock(&st->lock); - ret = read_raw_samp_freq(st, val); + ret = sca3000_read_raw_samp_freq(st, val); mutex_unlock(&st->lock); return ret ? ret : IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: @@ -763,7 +788,7 @@ static int sca3000_write_raw(struct iio_dev *indio_dev, if (val2) return -EINVAL; mutex_lock(&st->lock); - ret = write_raw_samp_freq(st, val); + ret = sca3000_write_raw_samp_freq(st, val); mutex_unlock(&st->lock); return ret; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: @@ -780,7 +805,10 @@ static int sca3000_write_raw(struct iio_dev *indio_dev, } /** - * sca3000_read_av_freq() sysfs function to get available frequencies + * sca3000_read_av_freq() - sysfs function to get available frequencies + * @dev: Device structure for this device. + * @attr: Description of the attribute. + * @buf: Incoming string * * The later modes are only relevant to the ring buffer - and depend on current * mode. Note that data sheet gives rather wide tolerances for these so integer @@ -875,8 +903,18 @@ static int sca3000_read_event_value(struct iio_dev *indio_dev, } /** - * sca3000_write_value() control of threshold and period - **/ + * sca3000_write_value() - control of threshold and period + * @indio_dev: Device instance specific IIO information. + * @chan: Description of the channel for which the event is being + * configured. + * @type: The type of event being configured, here magnitude rising + * as everything else is read only. + * @dir: Direction of the event (here rising) + * @info: What information about the event are we configuring. + * Here the threshold only. + * @val: Integer part of the value being written.. + * @val2: Non integer part of the value being written. Here always 0. + */ static int sca3000_write_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, @@ -951,11 +989,10 @@ static int sca3000_read_data(struct sca3000_state *st, } /** - * sca3000_ring_int_process() ring specific interrupt handling. - * - * This is only split from the main interrupt handler so as to - * reduce the amount of code if the ring buffer is not enabled. - **/ + * sca3000_ring_int_process() - ring specific interrupt handling. + * @val: Value of the interrupt status register. + * @indio_dev: Device instance specific IIO device structure. + */ static void sca3000_ring_int_process(u8 val, struct iio_dev *indio_dev) { struct sca3000_state *st = iio_priv(indio_dev); @@ -994,6 +1031,8 @@ error_ret: /** * sca3000_event_handler() - handling ring and non ring events + * @irq: The irq being handled. + * @private: struct iio_device pointer for the device. * * Ring related interrupt handler. Depending on event, push to * the ring buffer event chrdev or the event one. @@ -1001,7 +1040,7 @@ error_ret: * This function is complicated by the fact that the devices can signify ring * and non ring events via the same interrupt line and they can only * be distinguished via a read of the relevant status register. - **/ + */ static irqreturn_t sca3000_event_handler(int irq, void *private) { struct iio_dev *indio_dev = private; @@ -1189,7 +1228,13 @@ static int sca3000_motion_detect_set_state(struct iio_dev *indio_dev, int axis, } /** - * sca3000_write_event_config() simple on off control for motion detector + * sca3000_write_event_config() - simple on off control for motion detector + * @indio_dev: IIO device instance specific structure. Data specific to this + * particular driver may be accessed via iio_priv(indio_dev). + * @chan: Description of the channel whose event we are configuring. + * @type: The type of event. + * @dir: The direction of the event. + * @state: Desired state of event being configured. * * This is a per axis control, but enabling any will result in the * motion detector unit being enabled. @@ -1273,12 +1318,14 @@ error_ret: } /** - * sca3000_hw_ring_preenable() hw ring buffer preenable function + * sca3000_hw_ring_preenable() - hw ring buffer preenable function + * @indio_dev: structure representing the IIO device. Device instance + * specific state can be accessed via iio_priv(indio_dev). * * Very simple enable function as the chip will allows normal reads * during ring buffer operation so as long as it is indeed running * before we notify the core, the precise ordering does not matter. - **/ + */ static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) { int ret; @@ -1335,12 +1382,13 @@ static const struct iio_buffer_setup_ops sca3000_ring_setup_ops = { }; /** - * sca3000_clean_setup() get the device into a predictable state + * sca3000_clean_setup() - get the device into a predictable state + * @st: Device instance specific private data structure * * Devices use flash memory to store many of the register values * and hence can come up in somewhat unpredictable states. * Hence reset everything on driver load. - **/ + */ static int sca3000_clean_setup(struct sca3000_state *st) { int ret; -- cgit v1.2.3 From d62e5fee88e26044a48d4b5632c4f89936041d92 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 8 Oct 2016 17:39:18 +0100 Subject: staging:iio:accel:sca3000 Move out of staging. Now the driver is in a reasonable state, lets get it (finally) out of staging. Signed-off-by: Jonathan Cameron Reviewed-by: Lars-Peter Clausen --- drivers/iio/accel/Kconfig | 12 + drivers/iio/accel/Makefile | 2 + drivers/iio/accel/sca3000.c | 1576 +++++++++++++++++++++++++++++++++++ drivers/staging/iio/accel/Kconfig | 11 - drivers/staging/iio/accel/Makefile | 2 - drivers/staging/iio/accel/sca3000.c | 1576 ----------------------------------- 6 files changed, 1590 insertions(+), 1589 deletions(-) create mode 100644 drivers/iio/accel/sca3000.c delete mode 100644 drivers/staging/iio/accel/sca3000.c (limited to 'drivers') diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 878e3c9449de..c6cc2c0909a1 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -303,6 +303,18 @@ config MXC6255 To compile this driver as a module, choose M here: the module will be called mxc6255. +config SCA3000 + select IIO_BUFFER + select IIO_KFIFO_BUF + depends on SPI + tristate "VTI SCA3000 series accelerometers" + help + Say Y here to build support for the VTI SCA3000 series of SPI + accelerometers. These devices use a hardware ring buffer. + + To compile this driver as a module, say M here: the module will be + called sca3000. + config STK8312 tristate "Sensortek STK8312 3-Axis Accelerometer Driver" depends on I2C diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 0aa574957047..69fe8edc57a2 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -35,6 +35,8 @@ obj-$(CONFIG_MMA9553) += mma9553.o obj-$(CONFIG_MXC4005) += mxc4005.o obj-$(CONFIG_MXC6255) += mxc6255.o +obj-$(CONFIG_SCA3000) += sca3000.o + obj-$(CONFIG_STK8312) += stk8312.o obj-$(CONFIG_STK8BA50) += stk8ba50.o diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c new file mode 100644 index 000000000000..cb1d83fa19a0 --- /dev/null +++ b/drivers/iio/accel/sca3000.c @@ -0,0 +1,1576 @@ +/* + * sca3000_core.c -- support VTI sca3000 series accelerometers via SPI + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * Copyright (c) 2009 Jonathan Cameron + * + * See industrialio/accels/sca3000.h for comments. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SCA3000_WRITE_REG(a) (((a) << 2) | 0x02) +#define SCA3000_READ_REG(a) ((a) << 2) + +#define SCA3000_REG_REVID_ADDR 0x00 +#define SCA3000_REG_REVID_MAJOR_MASK GENMASK(8, 4) +#define SCA3000_REG_REVID_MINOR_MASK GENMASK(3, 0) + +#define SCA3000_REG_STATUS_ADDR 0x02 +#define SCA3000_LOCKED BIT(5) +#define SCA3000_EEPROM_CS_ERROR BIT(1) +#define SCA3000_SPI_FRAME_ERROR BIT(0) + +/* All reads done using register decrement so no need to directly access LSBs */ +#define SCA3000_REG_X_MSB_ADDR 0x05 +#define SCA3000_REG_Y_MSB_ADDR 0x07 +#define SCA3000_REG_Z_MSB_ADDR 0x09 + +#define SCA3000_REG_RING_OUT_ADDR 0x0f + +/* Temp read untested - the e05 doesn't have the sensor */ +#define SCA3000_REG_TEMP_MSB_ADDR 0x13 + +#define SCA3000_REG_MODE_ADDR 0x14 +#define SCA3000_MODE_PROT_MASK 0x28 +#define SCA3000_REG_MODE_RING_BUF_ENABLE BIT(7) +#define SCA3000_REG_MODE_RING_BUF_8BIT BIT(6) + +/* + * Free fall detection triggers an interrupt if the acceleration + * is below a threshold for equivalent of 25cm drop + */ +#define SCA3000_REG_MODE_FREE_FALL_DETECT BIT(4) +#define SCA3000_REG_MODE_MEAS_MODE_NORMAL 0x00 +#define SCA3000_REG_MODE_MEAS_MODE_OP_1 0x01 +#define SCA3000_REG_MODE_MEAS_MODE_OP_2 0x02 + +/* + * In motion detection mode the accelerations are band pass filtered + * (approx 1 - 25Hz) and then a programmable threshold used to trigger + * and interrupt. + */ +#define SCA3000_REG_MODE_MEAS_MODE_MOT_DET 0x03 +#define SCA3000_REG_MODE_MODE_MASK 0x03 + +#define SCA3000_REG_BUF_COUNT_ADDR 0x15 + +#define SCA3000_REG_INT_STATUS_ADDR 0x16 +#define SCA3000_REG_INT_STATUS_THREE_QUARTERS BIT(7) +#define SCA3000_REG_INT_STATUS_HALF BIT(6) + +#define SCA3000_INT_STATUS_FREE_FALL BIT(3) +#define SCA3000_INT_STATUS_Y_TRIGGER BIT(2) +#define SCA3000_INT_STATUS_X_TRIGGER BIT(1) +#define SCA3000_INT_STATUS_Z_TRIGGER BIT(0) + +/* Used to allow access to multiplexed registers */ +#define SCA3000_REG_CTRL_SEL_ADDR 0x18 +/* Only available for SCA3000-D03 and SCA3000-D01 */ +#define SCA3000_REG_CTRL_SEL_I2C_DISABLE 0x01 +#define SCA3000_REG_CTRL_SEL_MD_CTRL 0x02 +#define SCA3000_REG_CTRL_SEL_MD_Y_TH 0x03 +#define SCA3000_REG_CTRL_SEL_MD_X_TH 0x04 +#define SCA3000_REG_CTRL_SEL_MD_Z_TH 0x05 +/* + * BE VERY CAREFUL WITH THIS, IF 3 BITS ARE NOT SET the device + * will not function + */ +#define SCA3000_REG_CTRL_SEL_OUT_CTRL 0x0B + +#define SCA3000_REG_OUT_CTRL_PROT_MASK 0xE0 +#define SCA3000_REG_OUT_CTRL_BUF_X_EN 0x10 +#define SCA3000_REG_OUT_CTRL_BUF_Y_EN 0x08 +#define SCA3000_REG_OUT_CTRL_BUF_Z_EN 0x04 +#define SCA3000_REG_OUT_CTRL_BUF_DIV_MASK 0x03 +#define SCA3000_REG_OUT_CTRL_BUF_DIV_4 0x02 +#define SCA3000_REG_OUT_CTRL_BUF_DIV_2 0x01 + + +/* + * Control which motion detector interrupts are on. + * For now only OR combinations are supported. + */ +#define SCA3000_MD_CTRL_PROT_MASK 0xC0 +#define SCA3000_MD_CTRL_OR_Y BIT(0) +#define SCA3000_MD_CTRL_OR_X BIT(1) +#define SCA3000_MD_CTRL_OR_Z BIT(2) +/* Currently unsupported */ +#define SCA3000_MD_CTRL_AND_Y BIT(3) +#define SCA3000_MD_CTRL_AND_X BIT(4) +#define SAC3000_MD_CTRL_AND_Z BIT(5) + +/* + * Some control registers of complex access methods requiring this register to + * be used to remove a lock. + */ +#define SCA3000_REG_UNLOCK_ADDR 0x1e + +#define SCA3000_REG_INT_MASK_ADDR 0x21 +#define SCA3000_REG_INT_MASK_PROT_MASK 0x1C + +#define SCA3000_REG_INT_MASK_RING_THREE_QUARTER BIT(7) +#define SCA3000_REG_INT_MASK_RING_HALF BIT(6) + +#define SCA3000_REG_INT_MASK_ALL_INTS 0x02 +#define SCA3000_REG_INT_MASK_ACTIVE_HIGH 0x01 +#define SCA3000_REG_INT_MASK_ACTIVE_LOW 0x00 +/* Values of multiplexed registers (write to ctrl_data after select) */ +#define SCA3000_REG_CTRL_DATA_ADDR 0x22 + +/* + * Measurement modes available on some sca3000 series chips. Code assumes others + * may become available in the future. + * + * Bypass - Bypass the low-pass filter in the signal channel so as to increase + * signal bandwidth. + * + * Narrow - Narrow low-pass filtering of the signal channel and half output + * data rate by decimation. + * + * Wide - Widen low-pass filtering of signal channel to increase bandwidth + */ +#define SCA3000_OP_MODE_BYPASS 0x01 +#define SCA3000_OP_MODE_NARROW 0x02 +#define SCA3000_OP_MODE_WIDE 0x04 +#define SCA3000_MAX_TX 6 +#define SCA3000_MAX_RX 2 + +/** + * struct sca3000_state - device instance state information + * @us: the associated spi device + * @info: chip variant information + * @last_timestamp: the timestamp of the last event + * @mo_det_use_count: reference counter for the motion detection unit + * @lock: lock used to protect elements of sca3000_state + * and the underlying device state. + * @tx: dma-able transmit buffer + * @rx: dma-able receive buffer + **/ +struct sca3000_state { + struct spi_device *us; + const struct sca3000_chip_info *info; + s64 last_timestamp; + int mo_det_use_count; + struct mutex lock; + /* Can these share a cacheline ? */ + u8 rx[384] ____cacheline_aligned; + u8 tx[6] ____cacheline_aligned; +}; + +/** + * struct sca3000_chip_info - model dependent parameters + * @scale: scale * 10^-6 + * @temp_output: some devices have temperature sensors. + * @measurement_mode_freq: normal mode sampling frequency + * @measurement_mode_3db_freq: 3db cutoff frequency of the low pass filter for + * the normal measurement mode. + * @option_mode_1: first optional mode. Not all models have one + * @option_mode_1_freq: option mode 1 sampling frequency + * @option_mode_1_3db_freq: 3db cutoff frequency of the low pass filter for + * the first option mode. + * @option_mode_2: second optional mode. Not all chips have one + * @option_mode_2_freq: option mode 2 sampling frequency + * @option_mode_2_3db_freq: 3db cutoff frequency of the low pass filter for + * the second option mode. + * @mod_det_mult_xz: Bit wise multipliers to calculate the threshold + * for motion detection in the x and z axis. + * @mod_det_mult_y: Bit wise multipliers to calculate the threshold + * for motion detection in the y axis. + * + * This structure is used to hold information about the functionality of a given + * sca3000 variant. + **/ +struct sca3000_chip_info { + unsigned int scale; + bool temp_output; + int measurement_mode_freq; + int measurement_mode_3db_freq; + int option_mode_1; + int option_mode_1_freq; + int option_mode_1_3db_freq; + int option_mode_2; + int option_mode_2_freq; + int option_mode_2_3db_freq; + int mot_det_mult_xz[6]; + int mot_det_mult_y[7]; +}; + +enum sca3000_variant { + d01, + e02, + e04, + e05, +}; + +/* + * Note where option modes are not defined, the chip simply does not + * support any. + * Other chips in the sca3000 series use i2c and are not included here. + * + * Some of these devices are only listed in the family data sheet and + * do not actually appear to be available. + */ +static const struct sca3000_chip_info sca3000_spi_chip_info_tbl[] = { + [d01] = { + .scale = 7357, + .temp_output = true, + .measurement_mode_freq = 250, + .measurement_mode_3db_freq = 45, + .option_mode_1 = SCA3000_OP_MODE_BYPASS, + .option_mode_1_freq = 250, + .option_mode_1_3db_freq = 70, + .mot_det_mult_xz = {50, 100, 200, 350, 650, 1300}, + .mot_det_mult_y = {50, 100, 150, 250, 450, 850, 1750}, + }, + [e02] = { + .scale = 9810, + .measurement_mode_freq = 125, + .measurement_mode_3db_freq = 40, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 63, + .option_mode_1_3db_freq = 11, + .mot_det_mult_xz = {100, 150, 300, 550, 1050, 2050}, + .mot_det_mult_y = {50, 100, 200, 350, 700, 1350, 2700}, + }, + [e04] = { + .scale = 19620, + .measurement_mode_freq = 100, + .measurement_mode_3db_freq = 38, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 50, + .option_mode_1_3db_freq = 9, + .option_mode_2 = SCA3000_OP_MODE_WIDE, + .option_mode_2_freq = 400, + .option_mode_2_3db_freq = 70, + .mot_det_mult_xz = {200, 300, 600, 1100, 2100, 4100}, + .mot_det_mult_y = {100, 200, 400, 7000, 1400, 2700, 54000}, + }, + [e05] = { + .scale = 61313, + .measurement_mode_freq = 200, + .measurement_mode_3db_freq = 60, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 50, + .option_mode_1_3db_freq = 9, + .option_mode_2 = SCA3000_OP_MODE_WIDE, + .option_mode_2_freq = 400, + .option_mode_2_3db_freq = 75, + .mot_det_mult_xz = {600, 900, 1700, 3200, 6100, 11900}, + .mot_det_mult_y = {300, 600, 1200, 2000, 4100, 7800, 15600}, + }, +}; + +static int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val) +{ + st->tx[0] = SCA3000_WRITE_REG(address); + st->tx[1] = val; + return spi_write(st->us, st->tx, 2); +} + +static int sca3000_read_data_short(struct sca3000_state *st, + u8 reg_address_high, + int len) +{ + struct spi_transfer xfer[2] = { + { + .len = 1, + .tx_buf = st->tx, + }, { + .len = len, + .rx_buf = st->rx, + } + }; + st->tx[0] = SCA3000_READ_REG(reg_address_high); + + return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); +} + +/** + * sca3000_reg_lock_on() - test if the ctrl register lock is on + * @st: Driver specific device instance data. + * + * Lock must be held. + **/ +static int sca3000_reg_lock_on(struct sca3000_state *st) +{ + int ret; + + ret = sca3000_read_data_short(st, SCA3000_REG_STATUS_ADDR, 1); + if (ret < 0) + return ret; + + return !(st->rx[0] & SCA3000_LOCKED); +} + +/** + * __sca3000_unlock_reg_lock() - unlock the control registers + * @st: Driver specific device instance data. + * + * Note the device does not appear to support doing this in a single transfer. + * This should only ever be used as part of ctrl reg read. + * Lock must be held before calling this + */ +static int __sca3000_unlock_reg_lock(struct sca3000_state *st) +{ + struct spi_transfer xfer[3] = { + { + .len = 2, + .cs_change = 1, + .tx_buf = st->tx, + }, { + .len = 2, + .cs_change = 1, + .tx_buf = st->tx + 2, + }, { + .len = 2, + .tx_buf = st->tx + 4, + }, + }; + st->tx[0] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); + st->tx[1] = 0x00; + st->tx[2] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); + st->tx[3] = 0x50; + st->tx[4] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); + st->tx[5] = 0xA0; + + return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); +} + +/** + * sca3000_write_ctrl_reg() write to a lock protect ctrl register + * @st: Driver specific device instance data. + * @sel: selects which registers we wish to write to + * @val: the value to be written + * + * Certain control registers are protected against overwriting by the lock + * register and use a shared write address. This function allows writing of + * these registers. + * Lock must be held. + */ +static int sca3000_write_ctrl_reg(struct sca3000_state *st, + u8 sel, + uint8_t val) +{ + int ret; + + ret = sca3000_reg_lock_on(st); + if (ret < 0) + goto error_ret; + if (ret) { + ret = __sca3000_unlock_reg_lock(st); + if (ret) + goto error_ret; + } + + /* Set the control select register */ + ret = sca3000_write_reg(st, SCA3000_REG_CTRL_SEL_ADDR, sel); + if (ret) + goto error_ret; + + /* Write the actual value into the register */ + ret = sca3000_write_reg(st, SCA3000_REG_CTRL_DATA_ADDR, val); + +error_ret: + return ret; +} + +/** + * sca3000_read_ctrl_reg() read from lock protected control register. + * @st: Driver specific device instance data. + * @ctrl_reg: Which ctrl register do we want to read. + * + * Lock must be held. + */ +static int sca3000_read_ctrl_reg(struct sca3000_state *st, + u8 ctrl_reg) +{ + int ret; + + ret = sca3000_reg_lock_on(st); + if (ret < 0) + goto error_ret; + if (ret) { + ret = __sca3000_unlock_reg_lock(st); + if (ret) + goto error_ret; + } + /* Set the control select register */ + ret = sca3000_write_reg(st, SCA3000_REG_CTRL_SEL_ADDR, ctrl_reg); + if (ret) + goto error_ret; + ret = sca3000_read_data_short(st, SCA3000_REG_CTRL_DATA_ADDR, 1); + if (ret) + goto error_ret; + return st->rx[0]; +error_ret: + return ret; +} + +/** + * sca3000_show_rev() - sysfs interface to read the chip revision number + * @indio_dev: Device instance specific generic IIO data. + * Driver specific device instance data can be obtained via + * via iio_priv(indio_dev) + */ +static int sca3000_print_rev(struct iio_dev *indio_dev) +{ + int ret; + struct sca3000_state *st = iio_priv(indio_dev); + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_REVID_ADDR, 1); + if (ret < 0) + goto error_ret; + dev_info(&indio_dev->dev, + "sca3000 revision major=%lu, minor=%lu\n", + st->rx[0] & SCA3000_REG_REVID_MAJOR_MASK, + st->rx[0] & SCA3000_REG_REVID_MINOR_MASK); +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + +static ssize_t +sca3000_show_available_3db_freqs(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + int len; + + len = sprintf(buf, "%d", st->info->measurement_mode_3db_freq); + if (st->info->option_mode_1) + len += sprintf(buf + len, " %d", + st->info->option_mode_1_3db_freq); + if (st->info->option_mode_2) + len += sprintf(buf + len, " %d", + st->info->option_mode_2_3db_freq); + len += sprintf(buf + len, "\n"); + + return len; +} + +static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, + S_IRUGO, sca3000_show_available_3db_freqs, + NULL, 0); + +static const struct iio_event_spec sca3000_event = { + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), +}; + +/* + * Note the hack in the number of bits to pretend we have 2 more than + * we do in the fifo. + */ +#define SCA3000_CHAN(index, mod) \ + { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = mod, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |\ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),\ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + .address = index, \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 13, \ + .storagebits = 16, \ + .shift = 3, \ + .endianness = IIO_BE, \ + }, \ + .event_spec = &sca3000_event, \ + .num_event_specs = 1, \ + } + +static const struct iio_event_spec sca3000_freefall_event_spec = { + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_PERIOD), +}; + +static const struct iio_chan_spec sca3000_channels[] = { + SCA3000_CHAN(0, IIO_MOD_X), + SCA3000_CHAN(1, IIO_MOD_Y), + SCA3000_CHAN(2, IIO_MOD_Z), + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X_AND_Y_AND_Z, + .scan_index = -1, /* Fake channel */ + .event_spec = &sca3000_freefall_event_spec, + .num_event_specs = 1, + }, +}; + +static const struct iio_chan_spec sca3000_channels_with_temp[] = { + SCA3000_CHAN(0, IIO_MOD_X), + SCA3000_CHAN(1, IIO_MOD_Y), + SCA3000_CHAN(2, IIO_MOD_Z), + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + /* No buffer support */ + .scan_index = -1, + }, + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X_AND_Y_AND_Z, + .scan_index = -1, /* Fake channel */ + .event_spec = &sca3000_freefall_event_spec, + .num_event_specs = 1, + }, +}; + +static u8 sca3000_addresses[3][3] = { + [0] = {SCA3000_REG_X_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_X_TH, + SCA3000_MD_CTRL_OR_X}, + [1] = {SCA3000_REG_Y_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_Y_TH, + SCA3000_MD_CTRL_OR_Y}, + [2] = {SCA3000_REG_Z_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_Z_TH, + SCA3000_MD_CTRL_OR_Z}, +}; + +/** + * __sca3000_get_base_freq() - obtain mode specific base frequency + * @st: Private driver specific device instance specific state. + * @info: chip type specific information. + * @base_freq: Base frequency for the current measurement mode. + * + * lock must be held + */ +static inline int __sca3000_get_base_freq(struct sca3000_state *st, + const struct sca3000_chip_info *info, + int *base_freq) +{ + int ret; + + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + goto error_ret; + switch (SCA3000_REG_MODE_MODE_MASK & st->rx[0]) { + case SCA3000_REG_MODE_MEAS_MODE_NORMAL: + *base_freq = info->measurement_mode_freq; + break; + case SCA3000_REG_MODE_MEAS_MODE_OP_1: + *base_freq = info->option_mode_1_freq; + break; + case SCA3000_REG_MODE_MEAS_MODE_OP_2: + *base_freq = info->option_mode_2_freq; + break; + default: + ret = -EINVAL; + } +error_ret: + return ret; +} + +/** + * sca3000_read_raw_samp_freq() - read_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * @st: Private driver specific device instance specific state. + * @val: The frequency read back. + * + * lock must be held + **/ +static int sca3000_read_raw_samp_freq(struct sca3000_state *st, int *val) +{ + int ret; + + ret = __sca3000_get_base_freq(st, st->info, val); + if (ret) + return ret; + + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); + if (ret < 0) + return ret; + + if (*val > 0) { + ret &= SCA3000_REG_OUT_CTRL_BUF_DIV_MASK; + switch (ret) { + case SCA3000_REG_OUT_CTRL_BUF_DIV_2: + *val /= 2; + break; + case SCA3000_REG_OUT_CTRL_BUF_DIV_4: + *val /= 4; + break; + } + } + + return 0; +} + +/** + * sca3000_write_raw_samp_freq() - write_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * @st: Private driver specific device instance specific state. + * @val: The frequency desired. + * + * lock must be held + */ +static int sca3000_write_raw_samp_freq(struct sca3000_state *st, int val) +{ + int ret, base_freq, ctrlval; + + ret = __sca3000_get_base_freq(st, st->info, &base_freq); + if (ret) + return ret; + + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); + if (ret < 0) + return ret; + + ctrlval = ret & ~SCA3000_REG_OUT_CTRL_BUF_DIV_MASK; + + if (val == base_freq / 2) + ctrlval |= SCA3000_REG_OUT_CTRL_BUF_DIV_2; + if (val == base_freq / 4) + ctrlval |= SCA3000_REG_OUT_CTRL_BUF_DIV_4; + else if (val != base_freq) + return -EINVAL; + + return sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, + ctrlval); +} + +static int sca3000_read_3db_freq(struct sca3000_state *st, int *val) +{ + int ret; + + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + return ret; + + /* mask bottom 2 bits - only ones that are relevant */ + st->rx[0] &= SCA3000_REG_MODE_MODE_MASK; + switch (st->rx[0]) { + case SCA3000_REG_MODE_MEAS_MODE_NORMAL: + *val = st->info->measurement_mode_3db_freq; + return IIO_VAL_INT; + case SCA3000_REG_MODE_MEAS_MODE_MOT_DET: + return -EBUSY; + case SCA3000_REG_MODE_MEAS_MODE_OP_1: + *val = st->info->option_mode_1_3db_freq; + return IIO_VAL_INT; + case SCA3000_REG_MODE_MEAS_MODE_OP_2: + *val = st->info->option_mode_2_3db_freq; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int sca3000_write_3db_freq(struct sca3000_state *st, int val) +{ + int ret; + int mode; + + if (val == st->info->measurement_mode_3db_freq) + mode = SCA3000_REG_MODE_MEAS_MODE_NORMAL; + else if (st->info->option_mode_1 && + (val == st->info->option_mode_1_3db_freq)) + mode = SCA3000_REG_MODE_MEAS_MODE_OP_1; + else if (st->info->option_mode_2 && + (val == st->info->option_mode_2_3db_freq)) + mode = SCA3000_REG_MODE_MEAS_MODE_OP_2; + else + return -EINVAL; + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + return ret; + + st->rx[0] &= ~SCA3000_REG_MODE_MODE_MASK; + st->rx[0] |= (mode & SCA3000_REG_MODE_MODE_MASK); + + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, st->rx[0]); +} + +static int sca3000_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + u8 address; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&st->lock); + if (chan->type == IIO_ACCEL) { + if (st->mo_det_use_count) { + mutex_unlock(&st->lock); + return -EBUSY; + } + address = sca3000_addresses[chan->address][0]; + ret = sca3000_read_data_short(st, address, 2); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } + *val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF; + *val = ((*val) << (sizeof(*val) * 8 - 13)) >> + (sizeof(*val) * 8 - 13); + } else { + /* get the temperature when available */ + ret = sca3000_read_data_short(st, + SCA3000_REG_TEMP_MSB_ADDR, + 2); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } + *val = ((st->rx[0] & 0x3F) << 3) | + ((st->rx[1] & 0xE0) >> 5); + } + mutex_unlock(&st->lock); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + if (chan->type == IIO_ACCEL) + *val2 = st->info->scale; + else /* temperature */ + *val2 = 555556; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = -214; + *val2 = 600000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&st->lock); + ret = sca3000_read_raw_samp_freq(st, val); + mutex_unlock(&st->lock); + return ret ? ret : IIO_VAL_INT; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + mutex_lock(&st->lock); + ret = sca3000_read_3db_freq(st, val); + mutex_unlock(&st->lock); + return ret; + default: + return -EINVAL; + } +} + +static int sca3000_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) + return -EINVAL; + mutex_lock(&st->lock); + ret = sca3000_write_raw_samp_freq(st, val); + mutex_unlock(&st->lock); + return ret; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + if (val2) + return -EINVAL; + mutex_lock(&st->lock); + ret = sca3000_write_3db_freq(st, val); + mutex_unlock(&st->lock); + default: + return -EINVAL; + } + + return ret; +} + +/** + * sca3000_read_av_freq() - sysfs function to get available frequencies + * @dev: Device structure for this device. + * @attr: Description of the attribute. + * @buf: Incoming string + * + * The later modes are only relevant to the ring buffer - and depend on current + * mode. Note that data sheet gives rather wide tolerances for these so integer + * division will give good enough answer and not all chips have them specified + * at all. + **/ +static ssize_t sca3000_read_av_freq(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + int len = 0, ret, val; + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + val = st->rx[0]; + mutex_unlock(&st->lock); + if (ret) + goto error_ret; + + switch (val & SCA3000_REG_MODE_MODE_MASK) { + case SCA3000_REG_MODE_MEAS_MODE_NORMAL: + len += sprintf(buf + len, "%d %d %d\n", + st->info->measurement_mode_freq, + st->info->measurement_mode_freq / 2, + st->info->measurement_mode_freq / 4); + break; + case SCA3000_REG_MODE_MEAS_MODE_OP_1: + len += sprintf(buf + len, "%d %d %d\n", + st->info->option_mode_1_freq, + st->info->option_mode_1_freq / 2, + st->info->option_mode_1_freq / 4); + break; + case SCA3000_REG_MODE_MEAS_MODE_OP_2: + len += sprintf(buf + len, "%d %d %d\n", + st->info->option_mode_2_freq, + st->info->option_mode_2_freq / 2, + st->info->option_mode_2_freq / 4); + break; + } + return len; +error_ret: + return ret; +} + +/* + * Should only really be registered if ring buffer support is compiled in. + * Does no harm however and doing it right would add a fair bit of complexity + */ +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sca3000_read_av_freq); + +/** + * sca3000_read_event_value() - query of a threshold or period + **/ +static int sca3000_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + int ret, i; + struct sca3000_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_EV_INFO_VALUE: + mutex_lock(&st->lock); + ret = sca3000_read_ctrl_reg(st, + sca3000_addresses[chan->address][1]); + mutex_unlock(&st->lock); + if (ret < 0) + return ret; + *val = 0; + if (chan->channel2 == IIO_MOD_Y) + for_each_set_bit(i, (unsigned long *)&ret, + ARRAY_SIZE(st->info->mot_det_mult_y)) + *val += st->info->mot_det_mult_y[i]; + else + for_each_set_bit(i, (unsigned long *)&ret, + ARRAY_SIZE(st->info->mot_det_mult_xz)) + *val += st->info->mot_det_mult_xz[i]; + + return IIO_VAL_INT; + case IIO_EV_INFO_PERIOD: + *val = 0; + *val2 = 226000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +/** + * sca3000_write_value() - control of threshold and period + * @indio_dev: Device instance specific IIO information. + * @chan: Description of the channel for which the event is being + * configured. + * @type: The type of event being configured, here magnitude rising + * as everything else is read only. + * @dir: Direction of the event (here rising) + * @info: What information about the event are we configuring. + * Here the threshold only. + * @val: Integer part of the value being written.. + * @val2: Non integer part of the value being written. Here always 0. + */ +static int sca3000_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + int i; + u8 nonlinear = 0; + + if (chan->channel2 == IIO_MOD_Y) { + i = ARRAY_SIZE(st->info->mot_det_mult_y); + while (i > 0) + if (val >= st->info->mot_det_mult_y[--i]) { + nonlinear |= (1 << i); + val -= st->info->mot_det_mult_y[i]; + } + } else { + i = ARRAY_SIZE(st->info->mot_det_mult_xz); + while (i > 0) + if (val >= st->info->mot_det_mult_xz[--i]) { + nonlinear |= (1 << i); + val -= st->info->mot_det_mult_xz[i]; + } + } + + mutex_lock(&st->lock); + ret = sca3000_write_ctrl_reg(st, + sca3000_addresses[chan->address][1], + nonlinear); + mutex_unlock(&st->lock); + + return ret; +} + +static struct attribute *sca3000_attributes[] = { + &iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr, + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group sca3000_attribute_group = { + .attrs = sca3000_attributes, +}; + +static int sca3000_read_data(struct sca3000_state *st, + u8 reg_address_high, + u8 *rx, + int len) +{ + int ret; + struct spi_transfer xfer[2] = { + { + .len = 1, + .tx_buf = st->tx, + }, { + .len = len, + .rx_buf = rx, + } + }; + + st->tx[0] = SCA3000_READ_REG(reg_address_high); + ret = spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); + if (ret) { + dev_err(get_device(&st->us->dev), "problem reading register"); + return ret; + } + + return 0; +} + +/** + * sca3000_ring_int_process() - ring specific interrupt handling. + * @val: Value of the interrupt status register. + * @indio_dev: Device instance specific IIO device structure. + */ +static void sca3000_ring_int_process(u8 val, struct iio_dev *indio_dev) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret, i, num_available; + + mutex_lock(&st->lock); + + if (val & SCA3000_REG_INT_STATUS_HALF) { + ret = sca3000_read_data_short(st, SCA3000_REG_BUF_COUNT_ADDR, + 1); + if (ret) + goto error_ret; + num_available = st->rx[0]; + /* + * num_available is the total number of samples available + * i.e. number of time points * number of channels. + */ + ret = sca3000_read_data(st, SCA3000_REG_RING_OUT_ADDR, st->rx, + num_available * 2); + if (ret) + goto error_ret; + for (i = 0; i < num_available / 3; i++) { + /* + * Dirty hack to cover for 11 bit in fifo, 13 bit + * direct reading. + * + * In theory the bottom two bits are undefined. + * In reality they appear to always be 0. + */ + iio_push_to_buffers(indio_dev, st->rx + i * 3 * 2); + } + } +error_ret: + mutex_unlock(&st->lock); +} + +/** + * sca3000_event_handler() - handling ring and non ring events + * @irq: The irq being handled. + * @private: struct iio_device pointer for the device. + * + * Ring related interrupt handler. Depending on event, push to + * the ring buffer event chrdev or the event one. + * + * This function is complicated by the fact that the devices can signify ring + * and non ring events via the same interrupt line and they can only + * be distinguished via a read of the relevant status register. + */ +static irqreturn_t sca3000_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct sca3000_state *st = iio_priv(indio_dev); + int ret, val; + s64 last_timestamp = iio_get_time_ns(indio_dev); + + /* + * Could lead if badly timed to an extra read of status reg, + * but ensures no interrupt is missed. + */ + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_INT_STATUS_ADDR, 1); + val = st->rx[0]; + mutex_unlock(&st->lock); + if (ret) + goto done; + + sca3000_ring_int_process(val, indio_dev); + + if (val & SCA3000_INT_STATUS_FREE_FALL) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_FALLING), + last_timestamp); + + if (val & SCA3000_INT_STATUS_Y_TRIGGER) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Y, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + last_timestamp); + + if (val & SCA3000_INT_STATUS_X_TRIGGER) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + last_timestamp); + + if (val & SCA3000_INT_STATUS_Z_TRIGGER) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + last_timestamp); + +done: + return IRQ_HANDLED; +} + +/** + * sca3000_read_event_config() what events are enabled + **/ +static int sca3000_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + /* read current value of mode register */ + mutex_lock(&st->lock); + + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + goto error_ret; + + switch (chan->channel2) { + case IIO_MOD_X_AND_Y_AND_Z: + ret = !!(st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT); + break; + case IIO_MOD_X: + case IIO_MOD_Y: + case IIO_MOD_Z: + /* + * Motion detection mode cannot run at the same time as + * acceleration data being read. + */ + if ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) + != SCA3000_REG_MODE_MEAS_MODE_MOT_DET) { + ret = 0; + } else { + ret = sca3000_read_ctrl_reg(st, + SCA3000_REG_CTRL_SEL_MD_CTRL); + if (ret < 0) + goto error_ret; + /* only supporting logical or's for now */ + ret = !!(ret & sca3000_addresses[chan->address][2]); + } + break; + default: + ret = -EINVAL; + } + +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + +static int sca3000_freefall_set_state(struct iio_dev *indio_dev, int state) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + + /* read current value of mode register */ + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + return ret; + + /* if off and should be on */ + if (state && !(st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + st->rx[0] | SCA3000_REG_MODE_FREE_FALL_DETECT); + /* if on and should be off */ + else if (!state && (st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + st->rx[0] & ~SCA3000_REG_MODE_FREE_FALL_DETECT); + else + return 0; +} + +static int sca3000_motion_detect_set_state(struct iio_dev *indio_dev, int axis, + int state) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret, ctrlval; + + /* + * First read the motion detector config to find out if + * this axis is on + */ + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); + if (ret < 0) + return ret; + ctrlval = ret; + /* if off and should be on */ + if (state && !(ctrlval & sca3000_addresses[axis][2])) { + ret = sca3000_write_ctrl_reg(st, + SCA3000_REG_CTRL_SEL_MD_CTRL, + ctrlval | + sca3000_addresses[axis][2]); + if (ret) + return ret; + st->mo_det_use_count++; + } else if (!state && (ctrlval & sca3000_addresses[axis][2])) { + ret = sca3000_write_ctrl_reg(st, + SCA3000_REG_CTRL_SEL_MD_CTRL, + ctrlval & + ~(sca3000_addresses[axis][2])); + if (ret) + return ret; + st->mo_det_use_count--; + } + + /* read current value of mode register */ + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + return ret; + /* if off and should be on */ + if ((st->mo_det_use_count) && + ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) + != SCA3000_REG_MODE_MEAS_MODE_MOT_DET)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + (st->rx[0] & ~SCA3000_REG_MODE_MODE_MASK) + | SCA3000_REG_MODE_MEAS_MODE_MOT_DET); + /* if on and should be off */ + else if (!(st->mo_det_use_count) && + ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) + == SCA3000_REG_MODE_MEAS_MODE_MOT_DET)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + st->rx[0] & SCA3000_REG_MODE_MODE_MASK); + else + return 0; +} + +/** + * sca3000_write_event_config() - simple on off control for motion detector + * @indio_dev: IIO device instance specific structure. Data specific to this + * particular driver may be accessed via iio_priv(indio_dev). + * @chan: Description of the channel whose event we are configuring. + * @type: The type of event. + * @dir: The direction of the event. + * @state: Desired state of event being configured. + * + * This is a per axis control, but enabling any will result in the + * motion detector unit being enabled. + * N.B. enabling motion detector stops normal data acquisition. + * There is a complexity in knowing which mode to return to when + * this mode is disabled. Currently normal mode is assumed. + **/ +static int sca3000_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + switch (chan->channel2) { + case IIO_MOD_X_AND_Y_AND_Z: + ret = sca3000_freefall_set_state(indio_dev, state); + break; + + case IIO_MOD_X: + case IIO_MOD_Y: + case IIO_MOD_Z: + ret = sca3000_motion_detect_set_state(indio_dev, + chan->address, + state); + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&st->lock); + + return ret; +} + +static int sca3000_configure_ring(struct iio_dev *indio_dev) +{ + struct iio_buffer *buffer; + + buffer = iio_kfifo_allocate(); + if (!buffer) + return -ENOMEM; + + iio_device_attach_buffer(indio_dev, buffer); + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; + + return 0; +} + +static void sca3000_unconfigure_ring(struct iio_dev *indio_dev) +{ + iio_kfifo_free(indio_dev->buffer); +} + +static inline +int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + goto error_ret; + if (state) { + dev_info(&indio_dev->dev, "supposedly enabling ring buffer\n"); + ret = sca3000_write_reg(st, + SCA3000_REG_MODE_ADDR, + (st->rx[0] | SCA3000_REG_MODE_RING_BUF_ENABLE)); + } else + ret = sca3000_write_reg(st, + SCA3000_REG_MODE_ADDR, + (st->rx[0] & ~SCA3000_REG_MODE_RING_BUF_ENABLE)); +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + +/** + * sca3000_hw_ring_preenable() - hw ring buffer preenable function + * @indio_dev: structure representing the IIO device. Device instance + * specific state can be accessed via iio_priv(indio_dev). + * + * Very simple enable function as the chip will allows normal reads + * during ring buffer operation so as long as it is indeed running + * before we notify the core, the precise ordering does not matter. + */ +static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) +{ + int ret; + struct sca3000_state *st = iio_priv(indio_dev); + + mutex_lock(&st->lock); + + /* Enable the 50% full interrupt */ + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); + if (ret) + goto error_unlock; + ret = sca3000_write_reg(st, + SCA3000_REG_INT_MASK_ADDR, + st->rx[0] | SCA3000_REG_INT_MASK_RING_HALF); + if (ret) + goto error_unlock; + + mutex_unlock(&st->lock); + + return __sca3000_hw_ring_state_set(indio_dev, 1); + +error_unlock: + mutex_unlock(&st->lock); + + return ret; +} + +static int sca3000_hw_ring_postdisable(struct iio_dev *indio_dev) +{ + int ret; + struct sca3000_state *st = iio_priv(indio_dev); + + ret = __sca3000_hw_ring_state_set(indio_dev, 0); + if (ret) + return ret; + + /* Disable the 50% full interrupt */ + mutex_lock(&st->lock); + + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); + if (ret) + goto unlock; + ret = sca3000_write_reg(st, + SCA3000_REG_INT_MASK_ADDR, + st->rx[0] & ~SCA3000_REG_INT_MASK_RING_HALF); +unlock: + mutex_unlock(&st->lock); + return ret; +} + +static const struct iio_buffer_setup_ops sca3000_ring_setup_ops = { + .preenable = &sca3000_hw_ring_preenable, + .postdisable = &sca3000_hw_ring_postdisable, +}; + +/** + * sca3000_clean_setup() - get the device into a predictable state + * @st: Device instance specific private data structure + * + * Devices use flash memory to store many of the register values + * and hence can come up in somewhat unpredictable states. + * Hence reset everything on driver load. + */ +static int sca3000_clean_setup(struct sca3000_state *st) +{ + int ret; + + mutex_lock(&st->lock); + /* Ensure all interrupts have been acknowledged */ + ret = sca3000_read_data_short(st, SCA3000_REG_INT_STATUS_ADDR, 1); + if (ret) + goto error_ret; + + /* Turn off all motion detection channels */ + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); + if (ret < 0) + goto error_ret; + ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL, + ret & SCA3000_MD_CTRL_PROT_MASK); + if (ret) + goto error_ret; + + /* Disable ring buffer */ + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); + if (ret < 0) + goto error_ret; + ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, + (ret & SCA3000_REG_OUT_CTRL_PROT_MASK) + | SCA3000_REG_OUT_CTRL_BUF_X_EN + | SCA3000_REG_OUT_CTRL_BUF_Y_EN + | SCA3000_REG_OUT_CTRL_BUF_Z_EN + | SCA3000_REG_OUT_CTRL_BUF_DIV_4); + if (ret) + goto error_ret; + /* Enable interrupts, relevant to mode and set up as active low */ + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); + if (ret) + goto error_ret; + ret = sca3000_write_reg(st, + SCA3000_REG_INT_MASK_ADDR, + (ret & SCA3000_REG_INT_MASK_PROT_MASK) + | SCA3000_REG_INT_MASK_ACTIVE_LOW); + if (ret) + goto error_ret; + /* + * Select normal measurement mode, free fall off, ring off + * Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5 + * as that occurs in one of the example on the datasheet + */ + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + goto error_ret; + ret = sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + (st->rx[0] & SCA3000_MODE_PROT_MASK)); + +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static const struct iio_info sca3000_info = { + .attrs = &sca3000_attribute_group, + .read_raw = &sca3000_read_raw, + .write_raw = &sca3000_write_raw, + .read_event_value = &sca3000_read_event_value, + .write_event_value = &sca3000_write_event_value, + .read_event_config = &sca3000_read_event_config, + .write_event_config = &sca3000_write_event_config, + .driver_module = THIS_MODULE, +}; + +static int sca3000_probe(struct spi_device *spi) +{ + int ret; + struct sca3000_state *st; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + spi_set_drvdata(spi, indio_dev); + st->us = spi; + mutex_init(&st->lock); + st->info = &sca3000_spi_chip_info_tbl[spi_get_device_id(spi) + ->driver_data]; + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->info = &sca3000_info; + if (st->info->temp_output) { + indio_dev->channels = sca3000_channels_with_temp; + indio_dev->num_channels = + ARRAY_SIZE(sca3000_channels_with_temp); + } else { + indio_dev->channels = sca3000_channels; + indio_dev->num_channels = ARRAY_SIZE(sca3000_channels); + } + indio_dev->modes = INDIO_DIRECT_MODE; + + sca3000_configure_ring(indio_dev); + + if (spi->irq) { + ret = request_threaded_irq(spi->irq, + NULL, + &sca3000_event_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "sca3000", + indio_dev); + if (ret) + return ret; + } + indio_dev->setup_ops = &sca3000_ring_setup_ops; + ret = sca3000_clean_setup(st); + if (ret) + goto error_free_irq; + + ret = sca3000_print_rev(indio_dev); + if (ret) + goto error_free_irq; + + return iio_device_register(indio_dev); + +error_free_irq: + if (spi->irq) + free_irq(spi->irq, indio_dev); + + return ret; +} + +static int sca3000_stop_all_interrupts(struct sca3000_state *st) +{ + int ret; + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); + if (ret) + goto error_ret; + ret = sca3000_write_reg(st, SCA3000_REG_INT_MASK_ADDR, + (st->rx[0] & + ~(SCA3000_REG_INT_MASK_RING_THREE_QUARTER | + SCA3000_REG_INT_MASK_RING_HALF | + SCA3000_REG_INT_MASK_ALL_INTS))); +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static int sca3000_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct sca3000_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + /* Must ensure no interrupts can be generated after this! */ + sca3000_stop_all_interrupts(st); + if (spi->irq) + free_irq(spi->irq, indio_dev); + + sca3000_unconfigure_ring(indio_dev); + + return 0; +} + +static const struct spi_device_id sca3000_id[] = { + {"sca3000_d01", d01}, + {"sca3000_e02", e02}, + {"sca3000_e04", e04}, + {"sca3000_e05", e05}, + {} +}; +MODULE_DEVICE_TABLE(spi, sca3000_id); + +static struct spi_driver sca3000_driver = { + .driver = { + .name = "sca3000", + }, + .probe = sca3000_probe, + .remove = sca3000_remove, + .id_table = sca3000_id, +}; +module_spi_driver(sca3000_driver); + +MODULE_AUTHOR("Jonathan Cameron "); +MODULE_DESCRIPTION("VTI SCA3000 Series Accelerometers SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index 53389bfdd100..c6b0f5eae7ab 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -51,15 +51,4 @@ config ADIS16240 To compile this driver as a module, say M here: the module will be called adis16240. -config SCA3000 - select IIO_BUFFER - select IIO_KFIFO_BUF - depends on SPI - tristate "VTI SCA3000 series accelerometers" - help - Say Y here to build support for the VTI SCA3000 series of SPI - accelerometers. These devices use a hardware ring buffer. - - To compile this driver as a module, say M here: the module will be - called sca3000. endmenu diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index 1d49b6ab87ab..febb137b60c4 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -13,5 +13,3 @@ obj-$(CONFIG_ADIS16209) += adis16209.o adis16240-y := adis16240_core.o obj-$(CONFIG_ADIS16240) += adis16240.o - -obj-$(CONFIG_SCA3000) += sca3000.o diff --git a/drivers/staging/iio/accel/sca3000.c b/drivers/staging/iio/accel/sca3000.c deleted file mode 100644 index cb1d83fa19a0..000000000000 --- a/drivers/staging/iio/accel/sca3000.c +++ /dev/null @@ -1,1576 +0,0 @@ -/* - * sca3000_core.c -- support VTI sca3000 series accelerometers via SPI - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * Copyright (c) 2009 Jonathan Cameron - * - * See industrialio/accels/sca3000.h for comments. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SCA3000_WRITE_REG(a) (((a) << 2) | 0x02) -#define SCA3000_READ_REG(a) ((a) << 2) - -#define SCA3000_REG_REVID_ADDR 0x00 -#define SCA3000_REG_REVID_MAJOR_MASK GENMASK(8, 4) -#define SCA3000_REG_REVID_MINOR_MASK GENMASK(3, 0) - -#define SCA3000_REG_STATUS_ADDR 0x02 -#define SCA3000_LOCKED BIT(5) -#define SCA3000_EEPROM_CS_ERROR BIT(1) -#define SCA3000_SPI_FRAME_ERROR BIT(0) - -/* All reads done using register decrement so no need to directly access LSBs */ -#define SCA3000_REG_X_MSB_ADDR 0x05 -#define SCA3000_REG_Y_MSB_ADDR 0x07 -#define SCA3000_REG_Z_MSB_ADDR 0x09 - -#define SCA3000_REG_RING_OUT_ADDR 0x0f - -/* Temp read untested - the e05 doesn't have the sensor */ -#define SCA3000_REG_TEMP_MSB_ADDR 0x13 - -#define SCA3000_REG_MODE_ADDR 0x14 -#define SCA3000_MODE_PROT_MASK 0x28 -#define SCA3000_REG_MODE_RING_BUF_ENABLE BIT(7) -#define SCA3000_REG_MODE_RING_BUF_8BIT BIT(6) - -/* - * Free fall detection triggers an interrupt if the acceleration - * is below a threshold for equivalent of 25cm drop - */ -#define SCA3000_REG_MODE_FREE_FALL_DETECT BIT(4) -#define SCA3000_REG_MODE_MEAS_MODE_NORMAL 0x00 -#define SCA3000_REG_MODE_MEAS_MODE_OP_1 0x01 -#define SCA3000_REG_MODE_MEAS_MODE_OP_2 0x02 - -/* - * In motion detection mode the accelerations are band pass filtered - * (approx 1 - 25Hz) and then a programmable threshold used to trigger - * and interrupt. - */ -#define SCA3000_REG_MODE_MEAS_MODE_MOT_DET 0x03 -#define SCA3000_REG_MODE_MODE_MASK 0x03 - -#define SCA3000_REG_BUF_COUNT_ADDR 0x15 - -#define SCA3000_REG_INT_STATUS_ADDR 0x16 -#define SCA3000_REG_INT_STATUS_THREE_QUARTERS BIT(7) -#define SCA3000_REG_INT_STATUS_HALF BIT(6) - -#define SCA3000_INT_STATUS_FREE_FALL BIT(3) -#define SCA3000_INT_STATUS_Y_TRIGGER BIT(2) -#define SCA3000_INT_STATUS_X_TRIGGER BIT(1) -#define SCA3000_INT_STATUS_Z_TRIGGER BIT(0) - -/* Used to allow access to multiplexed registers */ -#define SCA3000_REG_CTRL_SEL_ADDR 0x18 -/* Only available for SCA3000-D03 and SCA3000-D01 */ -#define SCA3000_REG_CTRL_SEL_I2C_DISABLE 0x01 -#define SCA3000_REG_CTRL_SEL_MD_CTRL 0x02 -#define SCA3000_REG_CTRL_SEL_MD_Y_TH 0x03 -#define SCA3000_REG_CTRL_SEL_MD_X_TH 0x04 -#define SCA3000_REG_CTRL_SEL_MD_Z_TH 0x05 -/* - * BE VERY CAREFUL WITH THIS, IF 3 BITS ARE NOT SET the device - * will not function - */ -#define SCA3000_REG_CTRL_SEL_OUT_CTRL 0x0B - -#define SCA3000_REG_OUT_CTRL_PROT_MASK 0xE0 -#define SCA3000_REG_OUT_CTRL_BUF_X_EN 0x10 -#define SCA3000_REG_OUT_CTRL_BUF_Y_EN 0x08 -#define SCA3000_REG_OUT_CTRL_BUF_Z_EN 0x04 -#define SCA3000_REG_OUT_CTRL_BUF_DIV_MASK 0x03 -#define SCA3000_REG_OUT_CTRL_BUF_DIV_4 0x02 -#define SCA3000_REG_OUT_CTRL_BUF_DIV_2 0x01 - - -/* - * Control which motion detector interrupts are on. - * For now only OR combinations are supported. - */ -#define SCA3000_MD_CTRL_PROT_MASK 0xC0 -#define SCA3000_MD_CTRL_OR_Y BIT(0) -#define SCA3000_MD_CTRL_OR_X BIT(1) -#define SCA3000_MD_CTRL_OR_Z BIT(2) -/* Currently unsupported */ -#define SCA3000_MD_CTRL_AND_Y BIT(3) -#define SCA3000_MD_CTRL_AND_X BIT(4) -#define SAC3000_MD_CTRL_AND_Z BIT(5) - -/* - * Some control registers of complex access methods requiring this register to - * be used to remove a lock. - */ -#define SCA3000_REG_UNLOCK_ADDR 0x1e - -#define SCA3000_REG_INT_MASK_ADDR 0x21 -#define SCA3000_REG_INT_MASK_PROT_MASK 0x1C - -#define SCA3000_REG_INT_MASK_RING_THREE_QUARTER BIT(7) -#define SCA3000_REG_INT_MASK_RING_HALF BIT(6) - -#define SCA3000_REG_INT_MASK_ALL_INTS 0x02 -#define SCA3000_REG_INT_MASK_ACTIVE_HIGH 0x01 -#define SCA3000_REG_INT_MASK_ACTIVE_LOW 0x00 -/* Values of multiplexed registers (write to ctrl_data after select) */ -#define SCA3000_REG_CTRL_DATA_ADDR 0x22 - -/* - * Measurement modes available on some sca3000 series chips. Code assumes others - * may become available in the future. - * - * Bypass - Bypass the low-pass filter in the signal channel so as to increase - * signal bandwidth. - * - * Narrow - Narrow low-pass filtering of the signal channel and half output - * data rate by decimation. - * - * Wide - Widen low-pass filtering of signal channel to increase bandwidth - */ -#define SCA3000_OP_MODE_BYPASS 0x01 -#define SCA3000_OP_MODE_NARROW 0x02 -#define SCA3000_OP_MODE_WIDE 0x04 -#define SCA3000_MAX_TX 6 -#define SCA3000_MAX_RX 2 - -/** - * struct sca3000_state - device instance state information - * @us: the associated spi device - * @info: chip variant information - * @last_timestamp: the timestamp of the last event - * @mo_det_use_count: reference counter for the motion detection unit - * @lock: lock used to protect elements of sca3000_state - * and the underlying device state. - * @tx: dma-able transmit buffer - * @rx: dma-able receive buffer - **/ -struct sca3000_state { - struct spi_device *us; - const struct sca3000_chip_info *info; - s64 last_timestamp; - int mo_det_use_count; - struct mutex lock; - /* Can these share a cacheline ? */ - u8 rx[384] ____cacheline_aligned; - u8 tx[6] ____cacheline_aligned; -}; - -/** - * struct sca3000_chip_info - model dependent parameters - * @scale: scale * 10^-6 - * @temp_output: some devices have temperature sensors. - * @measurement_mode_freq: normal mode sampling frequency - * @measurement_mode_3db_freq: 3db cutoff frequency of the low pass filter for - * the normal measurement mode. - * @option_mode_1: first optional mode. Not all models have one - * @option_mode_1_freq: option mode 1 sampling frequency - * @option_mode_1_3db_freq: 3db cutoff frequency of the low pass filter for - * the first option mode. - * @option_mode_2: second optional mode. Not all chips have one - * @option_mode_2_freq: option mode 2 sampling frequency - * @option_mode_2_3db_freq: 3db cutoff frequency of the low pass filter for - * the second option mode. - * @mod_det_mult_xz: Bit wise multipliers to calculate the threshold - * for motion detection in the x and z axis. - * @mod_det_mult_y: Bit wise multipliers to calculate the threshold - * for motion detection in the y axis. - * - * This structure is used to hold information about the functionality of a given - * sca3000 variant. - **/ -struct sca3000_chip_info { - unsigned int scale; - bool temp_output; - int measurement_mode_freq; - int measurement_mode_3db_freq; - int option_mode_1; - int option_mode_1_freq; - int option_mode_1_3db_freq; - int option_mode_2; - int option_mode_2_freq; - int option_mode_2_3db_freq; - int mot_det_mult_xz[6]; - int mot_det_mult_y[7]; -}; - -enum sca3000_variant { - d01, - e02, - e04, - e05, -}; - -/* - * Note where option modes are not defined, the chip simply does not - * support any. - * Other chips in the sca3000 series use i2c and are not included here. - * - * Some of these devices are only listed in the family data sheet and - * do not actually appear to be available. - */ -static const struct sca3000_chip_info sca3000_spi_chip_info_tbl[] = { - [d01] = { - .scale = 7357, - .temp_output = true, - .measurement_mode_freq = 250, - .measurement_mode_3db_freq = 45, - .option_mode_1 = SCA3000_OP_MODE_BYPASS, - .option_mode_1_freq = 250, - .option_mode_1_3db_freq = 70, - .mot_det_mult_xz = {50, 100, 200, 350, 650, 1300}, - .mot_det_mult_y = {50, 100, 150, 250, 450, 850, 1750}, - }, - [e02] = { - .scale = 9810, - .measurement_mode_freq = 125, - .measurement_mode_3db_freq = 40, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 63, - .option_mode_1_3db_freq = 11, - .mot_det_mult_xz = {100, 150, 300, 550, 1050, 2050}, - .mot_det_mult_y = {50, 100, 200, 350, 700, 1350, 2700}, - }, - [e04] = { - .scale = 19620, - .measurement_mode_freq = 100, - .measurement_mode_3db_freq = 38, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 50, - .option_mode_1_3db_freq = 9, - .option_mode_2 = SCA3000_OP_MODE_WIDE, - .option_mode_2_freq = 400, - .option_mode_2_3db_freq = 70, - .mot_det_mult_xz = {200, 300, 600, 1100, 2100, 4100}, - .mot_det_mult_y = {100, 200, 400, 7000, 1400, 2700, 54000}, - }, - [e05] = { - .scale = 61313, - .measurement_mode_freq = 200, - .measurement_mode_3db_freq = 60, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 50, - .option_mode_1_3db_freq = 9, - .option_mode_2 = SCA3000_OP_MODE_WIDE, - .option_mode_2_freq = 400, - .option_mode_2_3db_freq = 75, - .mot_det_mult_xz = {600, 900, 1700, 3200, 6100, 11900}, - .mot_det_mult_y = {300, 600, 1200, 2000, 4100, 7800, 15600}, - }, -}; - -static int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val) -{ - st->tx[0] = SCA3000_WRITE_REG(address); - st->tx[1] = val; - return spi_write(st->us, st->tx, 2); -} - -static int sca3000_read_data_short(struct sca3000_state *st, - u8 reg_address_high, - int len) -{ - struct spi_transfer xfer[2] = { - { - .len = 1, - .tx_buf = st->tx, - }, { - .len = len, - .rx_buf = st->rx, - } - }; - st->tx[0] = SCA3000_READ_REG(reg_address_high); - - return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); -} - -/** - * sca3000_reg_lock_on() - test if the ctrl register lock is on - * @st: Driver specific device instance data. - * - * Lock must be held. - **/ -static int sca3000_reg_lock_on(struct sca3000_state *st) -{ - int ret; - - ret = sca3000_read_data_short(st, SCA3000_REG_STATUS_ADDR, 1); - if (ret < 0) - return ret; - - return !(st->rx[0] & SCA3000_LOCKED); -} - -/** - * __sca3000_unlock_reg_lock() - unlock the control registers - * @st: Driver specific device instance data. - * - * Note the device does not appear to support doing this in a single transfer. - * This should only ever be used as part of ctrl reg read. - * Lock must be held before calling this - */ -static int __sca3000_unlock_reg_lock(struct sca3000_state *st) -{ - struct spi_transfer xfer[3] = { - { - .len = 2, - .cs_change = 1, - .tx_buf = st->tx, - }, { - .len = 2, - .cs_change = 1, - .tx_buf = st->tx + 2, - }, { - .len = 2, - .tx_buf = st->tx + 4, - }, - }; - st->tx[0] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); - st->tx[1] = 0x00; - st->tx[2] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); - st->tx[3] = 0x50; - st->tx[4] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); - st->tx[5] = 0xA0; - - return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); -} - -/** - * sca3000_write_ctrl_reg() write to a lock protect ctrl register - * @st: Driver specific device instance data. - * @sel: selects which registers we wish to write to - * @val: the value to be written - * - * Certain control registers are protected against overwriting by the lock - * register and use a shared write address. This function allows writing of - * these registers. - * Lock must be held. - */ -static int sca3000_write_ctrl_reg(struct sca3000_state *st, - u8 sel, - uint8_t val) -{ - int ret; - - ret = sca3000_reg_lock_on(st); - if (ret < 0) - goto error_ret; - if (ret) { - ret = __sca3000_unlock_reg_lock(st); - if (ret) - goto error_ret; - } - - /* Set the control select register */ - ret = sca3000_write_reg(st, SCA3000_REG_CTRL_SEL_ADDR, sel); - if (ret) - goto error_ret; - - /* Write the actual value into the register */ - ret = sca3000_write_reg(st, SCA3000_REG_CTRL_DATA_ADDR, val); - -error_ret: - return ret; -} - -/** - * sca3000_read_ctrl_reg() read from lock protected control register. - * @st: Driver specific device instance data. - * @ctrl_reg: Which ctrl register do we want to read. - * - * Lock must be held. - */ -static int sca3000_read_ctrl_reg(struct sca3000_state *st, - u8 ctrl_reg) -{ - int ret; - - ret = sca3000_reg_lock_on(st); - if (ret < 0) - goto error_ret; - if (ret) { - ret = __sca3000_unlock_reg_lock(st); - if (ret) - goto error_ret; - } - /* Set the control select register */ - ret = sca3000_write_reg(st, SCA3000_REG_CTRL_SEL_ADDR, ctrl_reg); - if (ret) - goto error_ret; - ret = sca3000_read_data_short(st, SCA3000_REG_CTRL_DATA_ADDR, 1); - if (ret) - goto error_ret; - return st->rx[0]; -error_ret: - return ret; -} - -/** - * sca3000_show_rev() - sysfs interface to read the chip revision number - * @indio_dev: Device instance specific generic IIO data. - * Driver specific device instance data can be obtained via - * via iio_priv(indio_dev) - */ -static int sca3000_print_rev(struct iio_dev *indio_dev) -{ - int ret; - struct sca3000_state *st = iio_priv(indio_dev); - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_REVID_ADDR, 1); - if (ret < 0) - goto error_ret; - dev_info(&indio_dev->dev, - "sca3000 revision major=%lu, minor=%lu\n", - st->rx[0] & SCA3000_REG_REVID_MAJOR_MASK, - st->rx[0] & SCA3000_REG_REVID_MINOR_MASK); -error_ret: - mutex_unlock(&st->lock); - - return ret; -} - -static ssize_t -sca3000_show_available_3db_freqs(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int len; - - len = sprintf(buf, "%d", st->info->measurement_mode_3db_freq); - if (st->info->option_mode_1) - len += sprintf(buf + len, " %d", - st->info->option_mode_1_3db_freq); - if (st->info->option_mode_2) - len += sprintf(buf + len, " %d", - st->info->option_mode_2_3db_freq); - len += sprintf(buf + len, "\n"); - - return len; -} - -static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, - S_IRUGO, sca3000_show_available_3db_freqs, - NULL, 0); - -static const struct iio_event_spec sca3000_event = { - .type = IIO_EV_TYPE_MAG, - .dir = IIO_EV_DIR_RISING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), -}; - -/* - * Note the hack in the number of bits to pretend we have 2 more than - * we do in the fifo. - */ -#define SCA3000_CHAN(index, mod) \ - { \ - .type = IIO_ACCEL, \ - .modified = 1, \ - .channel2 = mod, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |\ - BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),\ - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ - .address = index, \ - .scan_index = index, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 13, \ - .storagebits = 16, \ - .shift = 3, \ - .endianness = IIO_BE, \ - }, \ - .event_spec = &sca3000_event, \ - .num_event_specs = 1, \ - } - -static const struct iio_event_spec sca3000_freefall_event_spec = { - .type = IIO_EV_TYPE_MAG, - .dir = IIO_EV_DIR_FALLING, - .mask_separate = BIT(IIO_EV_INFO_ENABLE) | - BIT(IIO_EV_INFO_PERIOD), -}; - -static const struct iio_chan_spec sca3000_channels[] = { - SCA3000_CHAN(0, IIO_MOD_X), - SCA3000_CHAN(1, IIO_MOD_Y), - SCA3000_CHAN(2, IIO_MOD_Z), - { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_X_AND_Y_AND_Z, - .scan_index = -1, /* Fake channel */ - .event_spec = &sca3000_freefall_event_spec, - .num_event_specs = 1, - }, -}; - -static const struct iio_chan_spec sca3000_channels_with_temp[] = { - SCA3000_CHAN(0, IIO_MOD_X), - SCA3000_CHAN(1, IIO_MOD_Y), - SCA3000_CHAN(2, IIO_MOD_Z), - { - .type = IIO_TEMP, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_OFFSET), - /* No buffer support */ - .scan_index = -1, - }, - { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_X_AND_Y_AND_Z, - .scan_index = -1, /* Fake channel */ - .event_spec = &sca3000_freefall_event_spec, - .num_event_specs = 1, - }, -}; - -static u8 sca3000_addresses[3][3] = { - [0] = {SCA3000_REG_X_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_X_TH, - SCA3000_MD_CTRL_OR_X}, - [1] = {SCA3000_REG_Y_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_Y_TH, - SCA3000_MD_CTRL_OR_Y}, - [2] = {SCA3000_REG_Z_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_Z_TH, - SCA3000_MD_CTRL_OR_Z}, -}; - -/** - * __sca3000_get_base_freq() - obtain mode specific base frequency - * @st: Private driver specific device instance specific state. - * @info: chip type specific information. - * @base_freq: Base frequency for the current measurement mode. - * - * lock must be held - */ -static inline int __sca3000_get_base_freq(struct sca3000_state *st, - const struct sca3000_chip_info *info, - int *base_freq) -{ - int ret; - - ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); - if (ret) - goto error_ret; - switch (SCA3000_REG_MODE_MODE_MASK & st->rx[0]) { - case SCA3000_REG_MODE_MEAS_MODE_NORMAL: - *base_freq = info->measurement_mode_freq; - break; - case SCA3000_REG_MODE_MEAS_MODE_OP_1: - *base_freq = info->option_mode_1_freq; - break; - case SCA3000_REG_MODE_MEAS_MODE_OP_2: - *base_freq = info->option_mode_2_freq; - break; - default: - ret = -EINVAL; - } -error_ret: - return ret; -} - -/** - * sca3000_read_raw_samp_freq() - read_raw handler for IIO_CHAN_INFO_SAMP_FREQ - * @st: Private driver specific device instance specific state. - * @val: The frequency read back. - * - * lock must be held - **/ -static int sca3000_read_raw_samp_freq(struct sca3000_state *st, int *val) -{ - int ret; - - ret = __sca3000_get_base_freq(st, st->info, val); - if (ret) - return ret; - - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); - if (ret < 0) - return ret; - - if (*val > 0) { - ret &= SCA3000_REG_OUT_CTRL_BUF_DIV_MASK; - switch (ret) { - case SCA3000_REG_OUT_CTRL_BUF_DIV_2: - *val /= 2; - break; - case SCA3000_REG_OUT_CTRL_BUF_DIV_4: - *val /= 4; - break; - } - } - - return 0; -} - -/** - * sca3000_write_raw_samp_freq() - write_raw handler for IIO_CHAN_INFO_SAMP_FREQ - * @st: Private driver specific device instance specific state. - * @val: The frequency desired. - * - * lock must be held - */ -static int sca3000_write_raw_samp_freq(struct sca3000_state *st, int val) -{ - int ret, base_freq, ctrlval; - - ret = __sca3000_get_base_freq(st, st->info, &base_freq); - if (ret) - return ret; - - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); - if (ret < 0) - return ret; - - ctrlval = ret & ~SCA3000_REG_OUT_CTRL_BUF_DIV_MASK; - - if (val == base_freq / 2) - ctrlval |= SCA3000_REG_OUT_CTRL_BUF_DIV_2; - if (val == base_freq / 4) - ctrlval |= SCA3000_REG_OUT_CTRL_BUF_DIV_4; - else if (val != base_freq) - return -EINVAL; - - return sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, - ctrlval); -} - -static int sca3000_read_3db_freq(struct sca3000_state *st, int *val) -{ - int ret; - - ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); - if (ret) - return ret; - - /* mask bottom 2 bits - only ones that are relevant */ - st->rx[0] &= SCA3000_REG_MODE_MODE_MASK; - switch (st->rx[0]) { - case SCA3000_REG_MODE_MEAS_MODE_NORMAL: - *val = st->info->measurement_mode_3db_freq; - return IIO_VAL_INT; - case SCA3000_REG_MODE_MEAS_MODE_MOT_DET: - return -EBUSY; - case SCA3000_REG_MODE_MEAS_MODE_OP_1: - *val = st->info->option_mode_1_3db_freq; - return IIO_VAL_INT; - case SCA3000_REG_MODE_MEAS_MODE_OP_2: - *val = st->info->option_mode_2_3db_freq; - return IIO_VAL_INT; - default: - return -EINVAL; - } -} - -static int sca3000_write_3db_freq(struct sca3000_state *st, int val) -{ - int ret; - int mode; - - if (val == st->info->measurement_mode_3db_freq) - mode = SCA3000_REG_MODE_MEAS_MODE_NORMAL; - else if (st->info->option_mode_1 && - (val == st->info->option_mode_1_3db_freq)) - mode = SCA3000_REG_MODE_MEAS_MODE_OP_1; - else if (st->info->option_mode_2 && - (val == st->info->option_mode_2_3db_freq)) - mode = SCA3000_REG_MODE_MEAS_MODE_OP_2; - else - return -EINVAL; - ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); - if (ret) - return ret; - - st->rx[0] &= ~SCA3000_REG_MODE_MODE_MASK; - st->rx[0] |= (mode & SCA3000_REG_MODE_MODE_MASK); - - return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, st->rx[0]); -} - -static int sca3000_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - u8 address; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&st->lock); - if (chan->type == IIO_ACCEL) { - if (st->mo_det_use_count) { - mutex_unlock(&st->lock); - return -EBUSY; - } - address = sca3000_addresses[chan->address][0]; - ret = sca3000_read_data_short(st, address, 2); - if (ret < 0) { - mutex_unlock(&st->lock); - return ret; - } - *val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF; - *val = ((*val) << (sizeof(*val) * 8 - 13)) >> - (sizeof(*val) * 8 - 13); - } else { - /* get the temperature when available */ - ret = sca3000_read_data_short(st, - SCA3000_REG_TEMP_MSB_ADDR, - 2); - if (ret < 0) { - mutex_unlock(&st->lock); - return ret; - } - *val = ((st->rx[0] & 0x3F) << 3) | - ((st->rx[1] & 0xE0) >> 5); - } - mutex_unlock(&st->lock); - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - *val = 0; - if (chan->type == IIO_ACCEL) - *val2 = st->info->scale; - else /* temperature */ - *val2 = 555556; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_CHAN_INFO_OFFSET: - *val = -214; - *val2 = 600000; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(&st->lock); - ret = sca3000_read_raw_samp_freq(st, val); - mutex_unlock(&st->lock); - return ret ? ret : IIO_VAL_INT; - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - mutex_lock(&st->lock); - ret = sca3000_read_3db_freq(st, val); - mutex_unlock(&st->lock); - return ret; - default: - return -EINVAL; - } -} - -static int sca3000_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - - switch (mask) { - case IIO_CHAN_INFO_SAMP_FREQ: - if (val2) - return -EINVAL; - mutex_lock(&st->lock); - ret = sca3000_write_raw_samp_freq(st, val); - mutex_unlock(&st->lock); - return ret; - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - if (val2) - return -EINVAL; - mutex_lock(&st->lock); - ret = sca3000_write_3db_freq(st, val); - mutex_unlock(&st->lock); - default: - return -EINVAL; - } - - return ret; -} - -/** - * sca3000_read_av_freq() - sysfs function to get available frequencies - * @dev: Device structure for this device. - * @attr: Description of the attribute. - * @buf: Incoming string - * - * The later modes are only relevant to the ring buffer - and depend on current - * mode. Note that data sheet gives rather wide tolerances for these so integer - * division will give good enough answer and not all chips have them specified - * at all. - **/ -static ssize_t sca3000_read_av_freq(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int len = 0, ret, val; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret) - goto error_ret; - - switch (val & SCA3000_REG_MODE_MODE_MASK) { - case SCA3000_REG_MODE_MEAS_MODE_NORMAL: - len += sprintf(buf + len, "%d %d %d\n", - st->info->measurement_mode_freq, - st->info->measurement_mode_freq / 2, - st->info->measurement_mode_freq / 4); - break; - case SCA3000_REG_MODE_MEAS_MODE_OP_1: - len += sprintf(buf + len, "%d %d %d\n", - st->info->option_mode_1_freq, - st->info->option_mode_1_freq / 2, - st->info->option_mode_1_freq / 4); - break; - case SCA3000_REG_MODE_MEAS_MODE_OP_2: - len += sprintf(buf + len, "%d %d %d\n", - st->info->option_mode_2_freq, - st->info->option_mode_2_freq / 2, - st->info->option_mode_2_freq / 4); - break; - } - return len; -error_ret: - return ret; -} - -/* - * Should only really be registered if ring buffer support is compiled in. - * Does no harm however and doing it right would add a fair bit of complexity - */ -static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sca3000_read_av_freq); - -/** - * sca3000_read_event_value() - query of a threshold or period - **/ -static int sca3000_read_event_value(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int *val, int *val2) -{ - int ret, i; - struct sca3000_state *st = iio_priv(indio_dev); - - switch (info) { - case IIO_EV_INFO_VALUE: - mutex_lock(&st->lock); - ret = sca3000_read_ctrl_reg(st, - sca3000_addresses[chan->address][1]); - mutex_unlock(&st->lock); - if (ret < 0) - return ret; - *val = 0; - if (chan->channel2 == IIO_MOD_Y) - for_each_set_bit(i, (unsigned long *)&ret, - ARRAY_SIZE(st->info->mot_det_mult_y)) - *val += st->info->mot_det_mult_y[i]; - else - for_each_set_bit(i, (unsigned long *)&ret, - ARRAY_SIZE(st->info->mot_det_mult_xz)) - *val += st->info->mot_det_mult_xz[i]; - - return IIO_VAL_INT; - case IIO_EV_INFO_PERIOD: - *val = 0; - *val2 = 226000; - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } -} - -/** - * sca3000_write_value() - control of threshold and period - * @indio_dev: Device instance specific IIO information. - * @chan: Description of the channel for which the event is being - * configured. - * @type: The type of event being configured, here magnitude rising - * as everything else is read only. - * @dir: Direction of the event (here rising) - * @info: What information about the event are we configuring. - * Here the threshold only. - * @val: Integer part of the value being written.. - * @val2: Non integer part of the value being written. Here always 0. - */ -static int sca3000_write_event_value(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int val, int val2) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - int i; - u8 nonlinear = 0; - - if (chan->channel2 == IIO_MOD_Y) { - i = ARRAY_SIZE(st->info->mot_det_mult_y); - while (i > 0) - if (val >= st->info->mot_det_mult_y[--i]) { - nonlinear |= (1 << i); - val -= st->info->mot_det_mult_y[i]; - } - } else { - i = ARRAY_SIZE(st->info->mot_det_mult_xz); - while (i > 0) - if (val >= st->info->mot_det_mult_xz[--i]) { - nonlinear |= (1 << i); - val -= st->info->mot_det_mult_xz[i]; - } - } - - mutex_lock(&st->lock); - ret = sca3000_write_ctrl_reg(st, - sca3000_addresses[chan->address][1], - nonlinear); - mutex_unlock(&st->lock); - - return ret; -} - -static struct attribute *sca3000_attributes[] = { - &iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr, - &iio_dev_attr_sampling_frequency_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group sca3000_attribute_group = { - .attrs = sca3000_attributes, -}; - -static int sca3000_read_data(struct sca3000_state *st, - u8 reg_address_high, - u8 *rx, - int len) -{ - int ret; - struct spi_transfer xfer[2] = { - { - .len = 1, - .tx_buf = st->tx, - }, { - .len = len, - .rx_buf = rx, - } - }; - - st->tx[0] = SCA3000_READ_REG(reg_address_high); - ret = spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); - if (ret) { - dev_err(get_device(&st->us->dev), "problem reading register"); - return ret; - } - - return 0; -} - -/** - * sca3000_ring_int_process() - ring specific interrupt handling. - * @val: Value of the interrupt status register. - * @indio_dev: Device instance specific IIO device structure. - */ -static void sca3000_ring_int_process(u8 val, struct iio_dev *indio_dev) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret, i, num_available; - - mutex_lock(&st->lock); - - if (val & SCA3000_REG_INT_STATUS_HALF) { - ret = sca3000_read_data_short(st, SCA3000_REG_BUF_COUNT_ADDR, - 1); - if (ret) - goto error_ret; - num_available = st->rx[0]; - /* - * num_available is the total number of samples available - * i.e. number of time points * number of channels. - */ - ret = sca3000_read_data(st, SCA3000_REG_RING_OUT_ADDR, st->rx, - num_available * 2); - if (ret) - goto error_ret; - for (i = 0; i < num_available / 3; i++) { - /* - * Dirty hack to cover for 11 bit in fifo, 13 bit - * direct reading. - * - * In theory the bottom two bits are undefined. - * In reality they appear to always be 0. - */ - iio_push_to_buffers(indio_dev, st->rx + i * 3 * 2); - } - } -error_ret: - mutex_unlock(&st->lock); -} - -/** - * sca3000_event_handler() - handling ring and non ring events - * @irq: The irq being handled. - * @private: struct iio_device pointer for the device. - * - * Ring related interrupt handler. Depending on event, push to - * the ring buffer event chrdev or the event one. - * - * This function is complicated by the fact that the devices can signify ring - * and non ring events via the same interrupt line and they can only - * be distinguished via a read of the relevant status register. - */ -static irqreturn_t sca3000_event_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct sca3000_state *st = iio_priv(indio_dev); - int ret, val; - s64 last_timestamp = iio_get_time_ns(indio_dev); - - /* - * Could lead if badly timed to an extra read of status reg, - * but ensures no interrupt is missed. - */ - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_INT_STATUS_ADDR, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret) - goto done; - - sca3000_ring_int_process(val, indio_dev); - - if (val & SCA3000_INT_STATUS_FREE_FALL) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_X_AND_Y_AND_Z, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_FALLING), - last_timestamp); - - if (val & SCA3000_INT_STATUS_Y_TRIGGER) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Y, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_RISING), - last_timestamp); - - if (val & SCA3000_INT_STATUS_X_TRIGGER) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_X, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_RISING), - last_timestamp); - - if (val & SCA3000_INT_STATUS_Z_TRIGGER) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Z, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_RISING), - last_timestamp); - -done: - return IRQ_HANDLED; -} - -/** - * sca3000_read_event_config() what events are enabled - **/ -static int sca3000_read_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - /* read current value of mode register */ - mutex_lock(&st->lock); - - ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); - if (ret) - goto error_ret; - - switch (chan->channel2) { - case IIO_MOD_X_AND_Y_AND_Z: - ret = !!(st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT); - break; - case IIO_MOD_X: - case IIO_MOD_Y: - case IIO_MOD_Z: - /* - * Motion detection mode cannot run at the same time as - * acceleration data being read. - */ - if ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) - != SCA3000_REG_MODE_MEAS_MODE_MOT_DET) { - ret = 0; - } else { - ret = sca3000_read_ctrl_reg(st, - SCA3000_REG_CTRL_SEL_MD_CTRL); - if (ret < 0) - goto error_ret; - /* only supporting logical or's for now */ - ret = !!(ret & sca3000_addresses[chan->address][2]); - } - break; - default: - ret = -EINVAL; - } - -error_ret: - mutex_unlock(&st->lock); - - return ret; -} - -static int sca3000_freefall_set_state(struct iio_dev *indio_dev, int state) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - - /* read current value of mode register */ - ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); - if (ret) - return ret; - - /* if off and should be on */ - if (state && !(st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT)) - return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, - st->rx[0] | SCA3000_REG_MODE_FREE_FALL_DETECT); - /* if on and should be off */ - else if (!state && (st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT)) - return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, - st->rx[0] & ~SCA3000_REG_MODE_FREE_FALL_DETECT); - else - return 0; -} - -static int sca3000_motion_detect_set_state(struct iio_dev *indio_dev, int axis, - int state) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret, ctrlval; - - /* - * First read the motion detector config to find out if - * this axis is on - */ - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); - if (ret < 0) - return ret; - ctrlval = ret; - /* if off and should be on */ - if (state && !(ctrlval & sca3000_addresses[axis][2])) { - ret = sca3000_write_ctrl_reg(st, - SCA3000_REG_CTRL_SEL_MD_CTRL, - ctrlval | - sca3000_addresses[axis][2]); - if (ret) - return ret; - st->mo_det_use_count++; - } else if (!state && (ctrlval & sca3000_addresses[axis][2])) { - ret = sca3000_write_ctrl_reg(st, - SCA3000_REG_CTRL_SEL_MD_CTRL, - ctrlval & - ~(sca3000_addresses[axis][2])); - if (ret) - return ret; - st->mo_det_use_count--; - } - - /* read current value of mode register */ - ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); - if (ret) - return ret; - /* if off and should be on */ - if ((st->mo_det_use_count) && - ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) - != SCA3000_REG_MODE_MEAS_MODE_MOT_DET)) - return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, - (st->rx[0] & ~SCA3000_REG_MODE_MODE_MASK) - | SCA3000_REG_MODE_MEAS_MODE_MOT_DET); - /* if on and should be off */ - else if (!(st->mo_det_use_count) && - ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) - == SCA3000_REG_MODE_MEAS_MODE_MOT_DET)) - return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, - st->rx[0] & SCA3000_REG_MODE_MODE_MASK); - else - return 0; -} - -/** - * sca3000_write_event_config() - simple on off control for motion detector - * @indio_dev: IIO device instance specific structure. Data specific to this - * particular driver may be accessed via iio_priv(indio_dev). - * @chan: Description of the channel whose event we are configuring. - * @type: The type of event. - * @dir: The direction of the event. - * @state: Desired state of event being configured. - * - * This is a per axis control, but enabling any will result in the - * motion detector unit being enabled. - * N.B. enabling motion detector stops normal data acquisition. - * There is a complexity in knowing which mode to return to when - * this mode is disabled. Currently normal mode is assumed. - **/ -static int sca3000_write_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - int state) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->lock); - switch (chan->channel2) { - case IIO_MOD_X_AND_Y_AND_Z: - ret = sca3000_freefall_set_state(indio_dev, state); - break; - - case IIO_MOD_X: - case IIO_MOD_Y: - case IIO_MOD_Z: - ret = sca3000_motion_detect_set_state(indio_dev, - chan->address, - state); - break; - default: - ret = -EINVAL; - break; - } - mutex_unlock(&st->lock); - - return ret; -} - -static int sca3000_configure_ring(struct iio_dev *indio_dev) -{ - struct iio_buffer *buffer; - - buffer = iio_kfifo_allocate(); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - indio_dev->modes |= INDIO_BUFFER_SOFTWARE; - - return 0; -} - -static void sca3000_unconfigure_ring(struct iio_dev *indio_dev) -{ - iio_kfifo_free(indio_dev->buffer); -} - -static inline -int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); - if (ret) - goto error_ret; - if (state) { - dev_info(&indio_dev->dev, "supposedly enabling ring buffer\n"); - ret = sca3000_write_reg(st, - SCA3000_REG_MODE_ADDR, - (st->rx[0] | SCA3000_REG_MODE_RING_BUF_ENABLE)); - } else - ret = sca3000_write_reg(st, - SCA3000_REG_MODE_ADDR, - (st->rx[0] & ~SCA3000_REG_MODE_RING_BUF_ENABLE)); -error_ret: - mutex_unlock(&st->lock); - - return ret; -} - -/** - * sca3000_hw_ring_preenable() - hw ring buffer preenable function - * @indio_dev: structure representing the IIO device. Device instance - * specific state can be accessed via iio_priv(indio_dev). - * - * Very simple enable function as the chip will allows normal reads - * during ring buffer operation so as long as it is indeed running - * before we notify the core, the precise ordering does not matter. - */ -static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) -{ - int ret; - struct sca3000_state *st = iio_priv(indio_dev); - - mutex_lock(&st->lock); - - /* Enable the 50% full interrupt */ - ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); - if (ret) - goto error_unlock; - ret = sca3000_write_reg(st, - SCA3000_REG_INT_MASK_ADDR, - st->rx[0] | SCA3000_REG_INT_MASK_RING_HALF); - if (ret) - goto error_unlock; - - mutex_unlock(&st->lock); - - return __sca3000_hw_ring_state_set(indio_dev, 1); - -error_unlock: - mutex_unlock(&st->lock); - - return ret; -} - -static int sca3000_hw_ring_postdisable(struct iio_dev *indio_dev) -{ - int ret; - struct sca3000_state *st = iio_priv(indio_dev); - - ret = __sca3000_hw_ring_state_set(indio_dev, 0); - if (ret) - return ret; - - /* Disable the 50% full interrupt */ - mutex_lock(&st->lock); - - ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); - if (ret) - goto unlock; - ret = sca3000_write_reg(st, - SCA3000_REG_INT_MASK_ADDR, - st->rx[0] & ~SCA3000_REG_INT_MASK_RING_HALF); -unlock: - mutex_unlock(&st->lock); - return ret; -} - -static const struct iio_buffer_setup_ops sca3000_ring_setup_ops = { - .preenable = &sca3000_hw_ring_preenable, - .postdisable = &sca3000_hw_ring_postdisable, -}; - -/** - * sca3000_clean_setup() - get the device into a predictable state - * @st: Device instance specific private data structure - * - * Devices use flash memory to store many of the register values - * and hence can come up in somewhat unpredictable states. - * Hence reset everything on driver load. - */ -static int sca3000_clean_setup(struct sca3000_state *st) -{ - int ret; - - mutex_lock(&st->lock); - /* Ensure all interrupts have been acknowledged */ - ret = sca3000_read_data_short(st, SCA3000_REG_INT_STATUS_ADDR, 1); - if (ret) - goto error_ret; - - /* Turn off all motion detection channels */ - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); - if (ret < 0) - goto error_ret; - ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL, - ret & SCA3000_MD_CTRL_PROT_MASK); - if (ret) - goto error_ret; - - /* Disable ring buffer */ - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); - if (ret < 0) - goto error_ret; - ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, - (ret & SCA3000_REG_OUT_CTRL_PROT_MASK) - | SCA3000_REG_OUT_CTRL_BUF_X_EN - | SCA3000_REG_OUT_CTRL_BUF_Y_EN - | SCA3000_REG_OUT_CTRL_BUF_Z_EN - | SCA3000_REG_OUT_CTRL_BUF_DIV_4); - if (ret) - goto error_ret; - /* Enable interrupts, relevant to mode and set up as active low */ - ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); - if (ret) - goto error_ret; - ret = sca3000_write_reg(st, - SCA3000_REG_INT_MASK_ADDR, - (ret & SCA3000_REG_INT_MASK_PROT_MASK) - | SCA3000_REG_INT_MASK_ACTIVE_LOW); - if (ret) - goto error_ret; - /* - * Select normal measurement mode, free fall off, ring off - * Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5 - * as that occurs in one of the example on the datasheet - */ - ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); - if (ret) - goto error_ret; - ret = sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, - (st->rx[0] & SCA3000_MODE_PROT_MASK)); - -error_ret: - mutex_unlock(&st->lock); - return ret; -} - -static const struct iio_info sca3000_info = { - .attrs = &sca3000_attribute_group, - .read_raw = &sca3000_read_raw, - .write_raw = &sca3000_write_raw, - .read_event_value = &sca3000_read_event_value, - .write_event_value = &sca3000_write_event_value, - .read_event_config = &sca3000_read_event_config, - .write_event_config = &sca3000_write_event_config, - .driver_module = THIS_MODULE, -}; - -static int sca3000_probe(struct spi_device *spi) -{ - int ret; - struct sca3000_state *st; - struct iio_dev *indio_dev; - - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - - st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); - st->us = spi; - mutex_init(&st->lock); - st->info = &sca3000_spi_chip_info_tbl[spi_get_device_id(spi) - ->driver_data]; - - indio_dev->dev.parent = &spi->dev; - indio_dev->name = spi_get_device_id(spi)->name; - indio_dev->info = &sca3000_info; - if (st->info->temp_output) { - indio_dev->channels = sca3000_channels_with_temp; - indio_dev->num_channels = - ARRAY_SIZE(sca3000_channels_with_temp); - } else { - indio_dev->channels = sca3000_channels; - indio_dev->num_channels = ARRAY_SIZE(sca3000_channels); - } - indio_dev->modes = INDIO_DIRECT_MODE; - - sca3000_configure_ring(indio_dev); - - if (spi->irq) { - ret = request_threaded_irq(spi->irq, - NULL, - &sca3000_event_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "sca3000", - indio_dev); - if (ret) - return ret; - } - indio_dev->setup_ops = &sca3000_ring_setup_ops; - ret = sca3000_clean_setup(st); - if (ret) - goto error_free_irq; - - ret = sca3000_print_rev(indio_dev); - if (ret) - goto error_free_irq; - - return iio_device_register(indio_dev); - -error_free_irq: - if (spi->irq) - free_irq(spi->irq, indio_dev); - - return ret; -} - -static int sca3000_stop_all_interrupts(struct sca3000_state *st) -{ - int ret; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); - if (ret) - goto error_ret; - ret = sca3000_write_reg(st, SCA3000_REG_INT_MASK_ADDR, - (st->rx[0] & - ~(SCA3000_REG_INT_MASK_RING_THREE_QUARTER | - SCA3000_REG_INT_MASK_RING_HALF | - SCA3000_REG_INT_MASK_ALL_INTS))); -error_ret: - mutex_unlock(&st->lock); - return ret; -} - -static int sca3000_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct sca3000_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - /* Must ensure no interrupts can be generated after this! */ - sca3000_stop_all_interrupts(st); - if (spi->irq) - free_irq(spi->irq, indio_dev); - - sca3000_unconfigure_ring(indio_dev); - - return 0; -} - -static const struct spi_device_id sca3000_id[] = { - {"sca3000_d01", d01}, - {"sca3000_e02", e02}, - {"sca3000_e04", e04}, - {"sca3000_e05", e05}, - {} -}; -MODULE_DEVICE_TABLE(spi, sca3000_id); - -static struct spi_driver sca3000_driver = { - .driver = { - .name = "sca3000", - }, - .probe = sca3000_probe, - .remove = sca3000_remove, - .id_table = sca3000_id, -}; -module_spi_driver(sca3000_driver); - -MODULE_AUTHOR("Jonathan Cameron "); -MODULE_DESCRIPTION("VTI SCA3000 Series Accelerometers SPI driver"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 218e95e9769b8335defc09b04244a78546cfb1e0 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Sat, 15 Oct 2016 22:00:53 -0700 Subject: iio: light: ltr501: claim direct mode during select raw reads Driver was checking for direct mode but not locking it. Use claim/release helper functions to guarantee the device stays in direct mode during required raw read cases. Signed-off-by: Alison Schofield Acked-by: Peter Meerwald-Stadler Signed-off-by: Jonathan Cameron --- drivers/iio/light/ltr501.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 3afc53a3d0b6..d57747771197 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -631,14 +631,16 @@ static int ltr501_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_PROCESSED: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; - switch (chan->type) { case IIO_LIGHT: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + mutex_lock(&data->lock_als); ret = ltr501_read_als(data, buf); mutex_unlock(&data->lock_als); + iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; *val = ltr501_calculate_lux(le16_to_cpu(buf[1]), @@ -648,8 +650,9 @@ static int ltr501_read_raw(struct iio_dev *indio_dev, return -EINVAL; } case IIO_CHAN_INFO_RAW: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; switch (chan->type) { case IIO_INTENSITY: @@ -657,21 +660,28 @@ static int ltr501_read_raw(struct iio_dev *indio_dev, ret = ltr501_read_als(data, buf); mutex_unlock(&data->lock_als); if (ret < 0) - return ret; + break; *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ? buf[0] : buf[1]); - return IIO_VAL_INT; + ret = IIO_VAL_INT; + break; case IIO_PROXIMITY: mutex_lock(&data->lock_ps); ret = ltr501_read_ps(data); mutex_unlock(&data->lock_ps); if (ret < 0) - return ret; + break; *val = ret & LTR501_PS_DATA_MASK; - return IIO_VAL_INT; + ret = IIO_VAL_INT; + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + + iio_device_release_direct_mode(indio_dev); + return ret; + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_INTENSITY: -- cgit v1.2.3 From 4aee987380432c5814ef0275d4041de857dc0617 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Sat, 15 Oct 2016 22:02:19 -0700 Subject: iio: light: ltr501: claim direct mode during raw writes Driver was checking for direct mode but not locking it. Use claim/release helper functions to guarantee the device stays in direct mode during all raw write operations. Signed-off-by: Alison Schofield Acked-by: Peter Meerwald-Stadler Signed-off-by: Jonathan Cameron --- drivers/iio/light/ltr501.c | 81 +++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index d57747771197..b30e0c1c6cc4 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -739,8 +739,9 @@ static int ltr501_write_raw(struct iio_dev *indio_dev, int i, ret, freq_val, freq_val2; struct ltr501_chip_info *info = data->chip_info; - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -749,85 +750,105 @@ static int ltr501_write_raw(struct iio_dev *indio_dev, i = ltr501_get_gain_index(info->als_gain, info->als_gain_tbl_size, val, val2); - if (i < 0) - return -EINVAL; + if (i < 0) { + ret = -EINVAL; + break; + } data->als_contr &= ~info->als_gain_mask; data->als_contr |= i << info->als_gain_shift; - return regmap_write(data->regmap, LTR501_ALS_CONTR, - data->als_contr); + ret = regmap_write(data->regmap, LTR501_ALS_CONTR, + data->als_contr); + break; case IIO_PROXIMITY: i = ltr501_get_gain_index(info->ps_gain, info->ps_gain_tbl_size, val, val2); - if (i < 0) - return -EINVAL; + if (i < 0) { + ret = -EINVAL; + break; + } data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK; data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT; - return regmap_write(data->regmap, LTR501_PS_CONTR, - data->ps_contr); + ret = regmap_write(data->regmap, LTR501_PS_CONTR, + data->ps_contr); + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + break; + case IIO_CHAN_INFO_INT_TIME: switch (chan->type) { case IIO_INTENSITY: - if (val != 0) - return -EINVAL; + if (val != 0) { + ret = -EINVAL; + break; + } mutex_lock(&data->lock_als); - i = ltr501_set_it_time(data, val2); + ret = ltr501_set_it_time(data, val2); mutex_unlock(&data->lock_als); - return i; + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + break; + case IIO_CHAN_INFO_SAMP_FREQ: switch (chan->type) { case IIO_INTENSITY: ret = ltr501_als_read_samp_freq(data, &freq_val, &freq_val2); if (ret < 0) - return ret; + break; ret = ltr501_als_write_samp_freq(data, val, val2); if (ret < 0) - return ret; + break; /* update persistence count when changing frequency */ ret = ltr501_write_intr_prst(data, chan->type, 0, data->als_period); if (ret < 0) - return ltr501_als_write_samp_freq(data, - freq_val, - freq_val2); - return ret; + ret = ltr501_als_write_samp_freq(data, freq_val, + freq_val2); + break; case IIO_PROXIMITY: ret = ltr501_ps_read_samp_freq(data, &freq_val, &freq_val2); if (ret < 0) - return ret; + break; ret = ltr501_ps_write_samp_freq(data, val, val2); if (ret < 0) - return ret; + break; /* update persistence count when changing frequency */ ret = ltr501_write_intr_prst(data, chan->type, 0, data->ps_period); if (ret < 0) - return ltr501_ps_write_samp_freq(data, - freq_val, - freq_val2); - return ret; + ret = ltr501_ps_write_samp_freq(data, freq_val, + freq_val2); + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + break; + + default: + ret = -EINVAL; + break; } - return -EINVAL; + + iio_device_release_direct_mode(indio_dev); + return ret; } static int ltr501_read_thresh(struct iio_dev *indio_dev, -- cgit v1.2.3 From e4a70e3e7d846a8db8e20c18a4d8a6cf35bcf29c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 13 Oct 2016 22:06:04 +0200 Subject: iio: humidity: add support to hts221 rh/temp combo device Add support to STM HTS221 humidity + temperature sensor http://www.st.com/resource/en/datasheet/hts221.pdf - continuous mode support - i2c support - spi support - trigger mode support Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/Kconfig | 22 ++ drivers/iio/humidity/Makefile | 7 + drivers/iio/humidity/hts221.h | 73 ++++ drivers/iio/humidity/hts221_buffer.c | 169 +++++++++ drivers/iio/humidity/hts221_core.c | 687 +++++++++++++++++++++++++++++++++++ drivers/iio/humidity/hts221_i2c.c | 110 ++++++ drivers/iio/humidity/hts221_spi.c | 125 +++++++ 7 files changed, 1193 insertions(+) create mode 100644 drivers/iio/humidity/hts221.h create mode 100644 drivers/iio/humidity/hts221_buffer.c create mode 100644 drivers/iio/humidity/hts221_core.c create mode 100644 drivers/iio/humidity/hts221_i2c.c create mode 100644 drivers/iio/humidity/hts221_spi.c (limited to 'drivers') diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig index b17e2e2bd4f5..6fd11d0813ad 100644 --- a/drivers/iio/humidity/Kconfig +++ b/drivers/iio/humidity/Kconfig @@ -34,6 +34,28 @@ config HDC100X To compile this driver as a module, choose M here: the module will be called hdc100x. +config HTS221 + tristate "STMicroelectronics HTS221 sensor Driver" + depends on (I2C || SPI) + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HTS221_I2C if (I2C) + select HTS221_SPI if (SPI_MASTER) + help + Say yes here to build support for STMicroelectronics HTS221 + temperature-humidity sensor + + To compile this driver as a module, choose M here: the module + will be called hts221. + +config HTS221_I2C + tristate + depends on HTS221 + +config HTS221_SPI + tristate + depends on HTS221 + config HTU21 tristate "Measurement Specialties HTU21 humidity & temperature sensor" depends on I2C diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile index 4a73442fcd9c..a6850e47c100 100644 --- a/drivers/iio/humidity/Makefile +++ b/drivers/iio/humidity/Makefile @@ -5,6 +5,13 @@ obj-$(CONFIG_AM2315) += am2315.o obj-$(CONFIG_DHT11) += dht11.o obj-$(CONFIG_HDC100X) += hdc100x.o + +hts221-y := hts221_core.o \ + hts221_buffer.o +obj-$(CONFIG_HTS221) += hts221.o +obj-$(CONFIG_HTS221_I2C) += hts221_i2c.o +obj-$(CONFIG_HTS221_SPI) += hts221_spi.o + obj-$(CONFIG_HTU21) += htu21.o obj-$(CONFIG_SI7005) += si7005.o obj-$(CONFIG_SI7020) += si7020.o diff --git a/drivers/iio/humidity/hts221.h b/drivers/iio/humidity/hts221.h new file mode 100644 index 000000000000..c7154665512e --- /dev/null +++ b/drivers/iio/humidity/hts221.h @@ -0,0 +1,73 @@ +/* + * STMicroelectronics hts221 sensor driver + * + * Copyright 2016 STMicroelectronics Inc. + * + * Lorenzo Bianconi + * + * Licensed under the GPL-2. + */ + +#ifndef HTS221_H +#define HTS221_H + +#define HTS221_DEV_NAME "hts221" + +#include + +#define HTS221_RX_MAX_LENGTH 8 +#define HTS221_TX_MAX_LENGTH 8 + +#define HTS221_DATA_SIZE 2 + +struct hts221_transfer_buffer { + u8 rx_buf[HTS221_RX_MAX_LENGTH]; + u8 tx_buf[HTS221_TX_MAX_LENGTH] ____cacheline_aligned; +}; + +struct hts221_transfer_function { + int (*read)(struct device *dev, u8 addr, int len, u8 *data); + int (*write)(struct device *dev, u8 addr, int len, u8 *data); +}; + +#define HTS221_AVG_DEPTH 8 +struct hts221_avg_avl { + u16 avg; + u8 val; +}; + +enum hts221_sensor_type { + HTS221_SENSOR_H, + HTS221_SENSOR_T, + HTS221_SENSOR_MAX, +}; + +struct hts221_sensor { + u8 cur_avg_idx; + int slope, b_gen; +}; + +struct hts221_hw { + const char *name; + struct device *dev; + + struct mutex lock; + struct iio_trigger *trig; + int irq; + + struct hts221_sensor sensors[HTS221_SENSOR_MAX]; + + u8 odr; + + const struct hts221_transfer_function *tf; + struct hts221_transfer_buffer tb; +}; + +int hts221_config_drdy(struct hts221_hw *hw, bool enable); +int hts221_probe(struct iio_dev *iio_dev); +int hts221_power_on(struct hts221_hw *hw); +int hts221_power_off(struct hts221_hw *hw); +int hts221_allocate_buffers(struct hts221_hw *hw); +int hts221_allocate_trigger(struct hts221_hw *hw); + +#endif /* HTS221_H */ diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c new file mode 100644 index 000000000000..76b2e8130b6f --- /dev/null +++ b/drivers/iio/humidity/hts221_buffer.c @@ -0,0 +1,169 @@ +/* + * STMicroelectronics hts221 sensor driver + * + * Copyright 2016 STMicroelectronics Inc. + * + * Lorenzo Bianconi + * + * Licensed under the GPL-2. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "hts221.h" + +#define HTS221_REG_STATUS_ADDR 0x27 +#define HTS221_RH_DRDY_MASK BIT(1) +#define HTS221_TEMP_DRDY_MASK BIT(0) + +static int hts221_trig_set_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *iio_dev = iio_trigger_get_drvdata(trig); + struct hts221_hw *hw = iio_priv(iio_dev); + + return hts221_config_drdy(hw, state); +} + +static const struct iio_trigger_ops hts221_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = hts221_trig_set_state, +}; + +static irqreturn_t hts221_trigger_handler_thread(int irq, void *private) +{ + struct hts221_hw *hw = (struct hts221_hw *)private; + u8 status; + int err; + + err = hw->tf->read(hw->dev, HTS221_REG_STATUS_ADDR, sizeof(status), + &status); + if (err < 0) + return IRQ_HANDLED; + + /* + * H_DA bit (humidity data available) is routed to DRDY line. + * Humidity sample is computed after temperature one. + * Here we can assume data channels are both available if H_DA bit + * is set in status register + */ + if (!(status & HTS221_RH_DRDY_MASK)) + return IRQ_NONE; + + iio_trigger_poll_chained(hw->trig); + + return IRQ_HANDLED; +} + +int hts221_allocate_trigger(struct hts221_hw *hw) +{ + struct iio_dev *iio_dev = iio_priv_to_dev(hw); + unsigned long irq_type; + int err; + + irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq)); + + switch (irq_type) { + case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: + break; + default: + dev_info(hw->dev, + "mode %lx unsupported, using IRQF_TRIGGER_RISING\n", + irq_type); + irq_type = IRQF_TRIGGER_RISING; + break; + } + + err = devm_request_threaded_irq(hw->dev, hw->irq, NULL, + hts221_trigger_handler_thread, + irq_type | IRQF_ONESHOT, + hw->name, hw); + if (err) { + dev_err(hw->dev, "failed to request trigger irq %d\n", + hw->irq); + return err; + } + + hw->trig = devm_iio_trigger_alloc(hw->dev, "%s-trigger", + iio_dev->name); + if (!hw->trig) + return -ENOMEM; + + iio_trigger_set_drvdata(hw->trig, iio_dev); + hw->trig->ops = &hts221_trigger_ops; + hw->trig->dev.parent = hw->dev; + iio_dev->trig = iio_trigger_get(hw->trig); + + return devm_iio_trigger_register(hw->dev, hw->trig); +} + +static int hts221_buffer_preenable(struct iio_dev *iio_dev) +{ + return hts221_power_on(iio_priv(iio_dev)); +} + +static int hts221_buffer_postdisable(struct iio_dev *iio_dev) +{ + return hts221_power_off(iio_priv(iio_dev)); +} + +static const struct iio_buffer_setup_ops hts221_buffer_ops = { + .preenable = hts221_buffer_preenable, + .postenable = iio_triggered_buffer_postenable, + .predisable = iio_triggered_buffer_predisable, + .postdisable = hts221_buffer_postdisable, +}; + +static irqreturn_t hts221_buffer_handler_thread(int irq, void *p) +{ + u8 buffer[ALIGN(2 * HTS221_DATA_SIZE, sizeof(s64)) + sizeof(s64)]; + struct iio_poll_func *pf = p; + struct iio_dev *iio_dev = pf->indio_dev; + struct hts221_hw *hw = iio_priv(iio_dev); + struct iio_chan_spec const *ch; + int err; + + /* humidity data */ + ch = &iio_dev->channels[HTS221_SENSOR_H]; + err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE, + buffer); + if (err < 0) + goto out; + + /* temperature data */ + ch = &iio_dev->channels[HTS221_SENSOR_T]; + err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE, + buffer + HTS221_DATA_SIZE); + if (err < 0) + goto out; + + iio_push_to_buffers_with_timestamp(iio_dev, buffer, + iio_get_time_ns(iio_dev)); + +out: + iio_trigger_notify_done(hw->trig); + + return IRQ_HANDLED; +} + +int hts221_allocate_buffers(struct hts221_hw *hw) +{ + return devm_iio_triggered_buffer_setup(hw->dev, iio_priv_to_dev(hw), + NULL, hts221_buffer_handler_thread, + &hts221_buffer_ops); +} + +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("STMicroelectronics hts221 buffer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c new file mode 100644 index 000000000000..3f3ef4a1a474 --- /dev/null +++ b/drivers/iio/humidity/hts221_core.c @@ -0,0 +1,687 @@ +/* + * STMicroelectronics hts221 sensor driver + * + * Copyright 2016 STMicroelectronics Inc. + * + * Lorenzo Bianconi + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include + +#include "hts221.h" + +#define HTS221_REG_WHOAMI_ADDR 0x0f +#define HTS221_REG_WHOAMI_VAL 0xbc + +#define HTS221_REG_CNTRL1_ADDR 0x20 +#define HTS221_REG_CNTRL2_ADDR 0x21 +#define HTS221_REG_CNTRL3_ADDR 0x22 + +#define HTS221_REG_AVG_ADDR 0x10 +#define HTS221_REG_H_OUT_L 0x28 +#define HTS221_REG_T_OUT_L 0x2a + +#define HTS221_HUMIDITY_AVG_MASK 0x07 +#define HTS221_TEMP_AVG_MASK 0x38 + +#define HTS221_ODR_MASK 0x87 +#define HTS221_BDU_MASK BIT(2) + +#define HTS221_DRDY_MASK BIT(2) + +#define HTS221_ENABLE_SENSOR BIT(7) + +#define HTS221_HUMIDITY_AVG_4 0x00 /* 0.4 %RH */ +#define HTS221_HUMIDITY_AVG_8 0x01 /* 0.3 %RH */ +#define HTS221_HUMIDITY_AVG_16 0x02 /* 0.2 %RH */ +#define HTS221_HUMIDITY_AVG_32 0x03 /* 0.15 %RH */ +#define HTS221_HUMIDITY_AVG_64 0x04 /* 0.1 %RH */ +#define HTS221_HUMIDITY_AVG_128 0x05 /* 0.07 %RH */ +#define HTS221_HUMIDITY_AVG_256 0x06 /* 0.05 %RH */ +#define HTS221_HUMIDITY_AVG_512 0x07 /* 0.03 %RH */ + +#define HTS221_TEMP_AVG_2 0x00 /* 0.08 degC */ +#define HTS221_TEMP_AVG_4 0x08 /* 0.05 degC */ +#define HTS221_TEMP_AVG_8 0x10 /* 0.04 degC */ +#define HTS221_TEMP_AVG_16 0x18 /* 0.03 degC */ +#define HTS221_TEMP_AVG_32 0x20 /* 0.02 degC */ +#define HTS221_TEMP_AVG_64 0x28 /* 0.015 degC */ +#define HTS221_TEMP_AVG_128 0x30 /* 0.01 degC */ +#define HTS221_TEMP_AVG_256 0x38 /* 0.007 degC */ + +/* calibration registers */ +#define HTS221_REG_0RH_CAL_X_H 0x36 +#define HTS221_REG_1RH_CAL_X_H 0x3a +#define HTS221_REG_0RH_CAL_Y_H 0x30 +#define HTS221_REG_1RH_CAL_Y_H 0x31 +#define HTS221_REG_0T_CAL_X_L 0x3c +#define HTS221_REG_1T_CAL_X_L 0x3e +#define HTS221_REG_0T_CAL_Y_H 0x32 +#define HTS221_REG_1T_CAL_Y_H 0x33 +#define HTS221_REG_T1_T0_CAL_Y_H 0x35 + +struct hts221_odr { + u8 hz; + u8 val; +}; + +struct hts221_avg { + u8 addr; + u8 mask; + struct hts221_avg_avl avg_avl[HTS221_AVG_DEPTH]; +}; + +static const struct hts221_odr hts221_odr_table[] = { + { 1, 0x01 }, /* 1Hz */ + { 7, 0x02 }, /* 7Hz */ + { 13, 0x03 }, /* 12.5Hz */ +}; + +static const struct hts221_avg hts221_avg_list[] = { + { + .addr = HTS221_REG_AVG_ADDR, + .mask = HTS221_HUMIDITY_AVG_MASK, + .avg_avl = { + { 4, HTS221_HUMIDITY_AVG_4 }, + { 8, HTS221_HUMIDITY_AVG_8 }, + { 16, HTS221_HUMIDITY_AVG_16 }, + { 32, HTS221_HUMIDITY_AVG_32 }, + { 64, HTS221_HUMIDITY_AVG_64 }, + { 128, HTS221_HUMIDITY_AVG_128 }, + { 256, HTS221_HUMIDITY_AVG_256 }, + { 512, HTS221_HUMIDITY_AVG_512 }, + }, + }, + { + .addr = HTS221_REG_AVG_ADDR, + .mask = HTS221_TEMP_AVG_MASK, + .avg_avl = { + { 2, HTS221_TEMP_AVG_2 }, + { 4, HTS221_TEMP_AVG_4 }, + { 8, HTS221_TEMP_AVG_8 }, + { 16, HTS221_TEMP_AVG_16 }, + { 32, HTS221_TEMP_AVG_32 }, + { 64, HTS221_TEMP_AVG_64 }, + { 128, HTS221_TEMP_AVG_128 }, + { 256, HTS221_TEMP_AVG_256 }, + }, + }, +}; + +static const struct iio_chan_spec hts221_channels[] = { + { + .type = IIO_HUMIDITYRELATIVE, + .address = HTS221_REG_H_OUT_L, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + }, + { + .type = IIO_TEMP, + .address = HTS221_REG_T_OUT_L, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_index = 1, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(2), +}; + +static int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask, + u8 val) +{ + u8 data; + int err; + + mutex_lock(&hw->lock); + + err = hw->tf->read(hw->dev, addr, sizeof(data), &data); + if (err < 0) { + dev_err(hw->dev, "failed to read %02x register\n", addr); + goto unlock; + } + + data = (data & ~mask) | (val & mask); + + err = hw->tf->write(hw->dev, addr, sizeof(data), &data); + if (err < 0) + dev_err(hw->dev, "failed to write %02x register\n", addr); + +unlock: + mutex_unlock(&hw->lock); + + return err; +} + +static int hts221_check_whoami(struct hts221_hw *hw) +{ + u8 data; + int err; + + err = hw->tf->read(hw->dev, HTS221_REG_WHOAMI_ADDR, sizeof(data), + &data); + if (err < 0) { + dev_err(hw->dev, "failed to read whoami register\n"); + return err; + } + + if (data != HTS221_REG_WHOAMI_VAL) { + dev_err(hw->dev, "wrong whoami {%02x vs %02x}\n", + data, HTS221_REG_WHOAMI_VAL); + return -ENODEV; + } + + return 0; +} + +int hts221_config_drdy(struct hts221_hw *hw, bool enable) +{ + u8 val = enable ? BIT(2) : 0; + int err; + + err = hts221_write_with_mask(hw, HTS221_REG_CNTRL3_ADDR, + HTS221_DRDY_MASK, val); + + return err < 0 ? err : 0; +} + +static int hts221_update_odr(struct hts221_hw *hw, u8 odr) +{ + int i, err; + u8 val; + + for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++) + if (hts221_odr_table[i].hz == odr) + break; + + if (i == ARRAY_SIZE(hts221_odr_table)) + return -EINVAL; + + val = HTS221_ENABLE_SENSOR | HTS221_BDU_MASK | hts221_odr_table[i].val; + err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR, + HTS221_ODR_MASK, val); + if (err < 0) + return err; + + hw->odr = odr; + + return 0; +} + +static int hts221_update_avg(struct hts221_hw *hw, + enum hts221_sensor_type type, + u16 val) +{ + int i, err; + const struct hts221_avg *avg = &hts221_avg_list[type]; + + for (i = 0; i < HTS221_AVG_DEPTH; i++) + if (avg->avg_avl[i].avg == val) + break; + + if (i == HTS221_AVG_DEPTH) + return -EINVAL; + + err = hts221_write_with_mask(hw, avg->addr, avg->mask, + avg->avg_avl[i].val); + if (err < 0) + return err; + + hw->sensors[type].cur_avg_idx = i; + + return 0; +} + +static ssize_t hts221_sysfs_sampling_freq(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i; + ssize_t len = 0; + + for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", + hts221_odr_table[i].hz); + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t +hts221_sysfs_rh_oversampling_avail(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_H]; + ssize_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", + avg->avg_avl[i].avg); + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t +hts221_sysfs_temp_oversampling_avail(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_T]; + ssize_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", + avg->avg_avl[i].avg); + buf[len - 1] = '\n'; + + return len; +} + +int hts221_power_on(struct hts221_hw *hw) +{ + return hts221_update_odr(hw, hw->odr); +} + +int hts221_power_off(struct hts221_hw *hw) +{ + u8 data[] = {0x00, 0x00}; + + return hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data), + data); +} + +static int hts221_parse_temp_caldata(struct hts221_hw *hw) +{ + int err, *slope, *b_gen; + s16 cal_x0, cal_x1, cal_y0, cal_y1; + u8 cal0, cal1; + + err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_Y_H, + sizeof(cal0), &cal0); + if (err < 0) + return err; + + err = hw->tf->read(hw->dev, HTS221_REG_T1_T0_CAL_Y_H, + sizeof(cal1), &cal1); + if (err < 0) + return err; + cal_y0 = (le16_to_cpu(cal1 & 0x3) << 8) | cal0; + + err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_Y_H, + sizeof(cal0), &cal0); + if (err < 0) + return err; + cal_y1 = (((cal1 & 0xc) >> 2) << 8) | cal0; + + err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_X_L, sizeof(cal_x0), + (u8 *)&cal_x0); + if (err < 0) + return err; + cal_x0 = le16_to_cpu(cal_x0); + + err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_X_L, sizeof(cal_x1), + (u8 *)&cal_x1); + if (err < 0) + return err; + cal_x1 = le16_to_cpu(cal_x1); + + slope = &hw->sensors[HTS221_SENSOR_T].slope; + b_gen = &hw->sensors[HTS221_SENSOR_T].b_gen; + + *slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0); + *b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) / + (cal_x1 - cal_x0); + *b_gen *= 8; + + return 0; +} + +static int hts221_parse_rh_caldata(struct hts221_hw *hw) +{ + int err, *slope, *b_gen; + s16 cal_x0, cal_x1, cal_y0, cal_y1; + u8 data; + + err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_Y_H, sizeof(data), + &data); + if (err < 0) + return err; + cal_y0 = data; + + err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_Y_H, sizeof(data), + &data); + if (err < 0) + return err; + cal_y1 = data; + + err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_X_H, sizeof(cal_x0), + (u8 *)&cal_x0); + if (err < 0) + return err; + cal_x0 = le16_to_cpu(cal_x0); + + err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_X_H, sizeof(cal_x1), + (u8 *)&cal_x1); + if (err < 0) + return err; + cal_x1 = le16_to_cpu(cal_x1); + + slope = &hw->sensors[HTS221_SENSOR_H].slope; + b_gen = &hw->sensors[HTS221_SENSOR_H].b_gen; + + *slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0); + *b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) / + (cal_x1 - cal_x0); + *b_gen *= 8; + + return 0; +} + +static int hts221_get_sensor_scale(struct hts221_hw *hw, + enum iio_chan_type ch_type, + int *val, int *val2) +{ + s64 tmp; + s32 rem, div, data; + + switch (ch_type) { + case IIO_HUMIDITYRELATIVE: + data = hw->sensors[HTS221_SENSOR_H].slope; + div = (1 << 4) * 1000; + break; + case IIO_TEMP: + data = hw->sensors[HTS221_SENSOR_T].slope; + div = (1 << 6) * 1000; + break; + default: + return -EINVAL; + } + + tmp = div_s64(data * 1000000000LL, div); + tmp = div_s64_rem(tmp, 1000000000LL, &rem); + + *val = tmp; + *val2 = rem; + + return IIO_VAL_INT_PLUS_NANO; +} + +static int hts221_get_sensor_offset(struct hts221_hw *hw, + enum iio_chan_type ch_type, + int *val, int *val2) +{ + s64 tmp; + s32 rem, div, data; + + switch (ch_type) { + case IIO_HUMIDITYRELATIVE: + data = hw->sensors[HTS221_SENSOR_H].b_gen; + div = hw->sensors[HTS221_SENSOR_H].slope; + break; + case IIO_TEMP: + data = hw->sensors[HTS221_SENSOR_T].b_gen; + div = hw->sensors[HTS221_SENSOR_T].slope; + break; + default: + return -EINVAL; + } + + tmp = div_s64(data * 1000000000LL, div); + tmp = div_s64_rem(tmp, 1000000000LL, &rem); + + *val = tmp; + *val2 = rem; + + return IIO_VAL_INT_PLUS_NANO; +} + +static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val) +{ + u8 data[HTS221_DATA_SIZE]; + int err; + + err = hts221_power_on(hw); + if (err < 0) + return err; + + msleep(50); + + err = hw->tf->read(hw->dev, addr, sizeof(data), data); + if (err < 0) + return err; + + hts221_power_off(hw); + + *val = (s16)get_unaligned_le16(data); + + return IIO_VAL_INT; +} + +static int hts221_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *ch, + int *val, int *val2, long mask) +{ + struct hts221_hw *hw = iio_priv(iio_dev); + int ret; + + ret = iio_device_claim_direct_mode(iio_dev); + if (ret) + return ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = hts221_read_oneshot(hw, ch->address, val); + break; + case IIO_CHAN_INFO_SCALE: + ret = hts221_get_sensor_scale(hw, ch->type, val, val2); + break; + case IIO_CHAN_INFO_OFFSET: + ret = hts221_get_sensor_offset(hw, ch->type, val, val2); + break; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = hw->odr; + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + u8 idx; + const struct hts221_avg *avg; + + switch (ch->type) { + case IIO_HUMIDITYRELATIVE: + avg = &hts221_avg_list[HTS221_SENSOR_H]; + idx = hw->sensors[HTS221_SENSOR_H].cur_avg_idx; + *val = avg->avg_avl[idx].avg; + ret = IIO_VAL_INT; + break; + case IIO_TEMP: + avg = &hts221_avg_list[HTS221_SENSOR_T]; + idx = hw->sensors[HTS221_SENSOR_T].cur_avg_idx; + *val = avg->avg_avl[idx].avg; + ret = IIO_VAL_INT; + break; + default: + ret = -EINVAL; + break; + } + break; + } + default: + ret = -EINVAL; + break; + } + + iio_device_release_direct_mode(iio_dev); + + return ret; +} + +static int hts221_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct hts221_hw *hw = iio_priv(iio_dev); + int ret; + + ret = iio_device_claim_direct_mode(iio_dev); + if (ret) + return ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hts221_update_odr(hw, val); + break; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + switch (chan->type) { + case IIO_HUMIDITYRELATIVE: + ret = hts221_update_avg(hw, HTS221_SENSOR_H, val); + break; + case IIO_TEMP: + ret = hts221_update_avg(hw, HTS221_SENSOR_T, val); + break; + default: + ret = -EINVAL; + break; + } + break; + default: + ret = -EINVAL; + break; + } + + iio_device_release_direct_mode(iio_dev); + + return ret; +} + +static int hts221_validate_trigger(struct iio_dev *iio_dev, + struct iio_trigger *trig) +{ + struct hts221_hw *hw = iio_priv(iio_dev); + + return hw->trig == trig ? 0 : -EINVAL; +} + +static IIO_DEVICE_ATTR(in_humidity_oversampling_ratio_available, S_IRUGO, + hts221_sysfs_rh_oversampling_avail, NULL, 0); +static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available, S_IRUGO, + hts221_sysfs_temp_oversampling_avail, NULL, 0); +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hts221_sysfs_sampling_freq); + +static struct attribute *hts221_attributes[] = { + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_in_humidity_oversampling_ratio_available.dev_attr.attr, + &iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group hts221_attribute_group = { + .attrs = hts221_attributes, +}; + +static const struct iio_info hts221_info = { + .driver_module = THIS_MODULE, + .attrs = &hts221_attribute_group, + .read_raw = hts221_read_raw, + .write_raw = hts221_write_raw, + .validate_trigger = hts221_validate_trigger, +}; + +static const unsigned long hts221_scan_masks[] = {0x3, 0x0}; + +int hts221_probe(struct iio_dev *iio_dev) +{ + struct hts221_hw *hw = iio_priv(iio_dev); + int err; + u8 data; + + mutex_init(&hw->lock); + + err = hts221_check_whoami(hw); + if (err < 0) + return err; + + hw->odr = hts221_odr_table[0].hz; + + iio_dev->modes = INDIO_DIRECT_MODE; + iio_dev->dev.parent = hw->dev; + iio_dev->available_scan_masks = hts221_scan_masks; + iio_dev->channels = hts221_channels; + iio_dev->num_channels = ARRAY_SIZE(hts221_channels); + iio_dev->name = HTS221_DEV_NAME; + iio_dev->info = &hts221_info; + + /* configure humidity sensor */ + err = hts221_parse_rh_caldata(hw); + if (err < 0) { + dev_err(hw->dev, "failed to get rh calibration data\n"); + return err; + } + + data = hts221_avg_list[HTS221_SENSOR_H].avg_avl[3].avg; + err = hts221_update_avg(hw, HTS221_SENSOR_H, data); + if (err < 0) { + dev_err(hw->dev, "failed to set rh oversampling ratio\n"); + return err; + } + + /* configure temperature sensor */ + err = hts221_parse_temp_caldata(hw); + if (err < 0) { + dev_err(hw->dev, + "failed to get temperature calibration data\n"); + return err; + } + + data = hts221_avg_list[HTS221_SENSOR_T].avg_avl[3].avg; + err = hts221_update_avg(hw, HTS221_SENSOR_T, data); + if (err < 0) { + dev_err(hw->dev, + "failed to set temperature oversampling ratio\n"); + return err; + } + + if (hw->irq > 0) { + err = hts221_allocate_buffers(hw); + if (err < 0) + return err; + + err = hts221_allocate_trigger(hw); + if (err) + return err; + } + + return devm_iio_device_register(hw->dev, iio_dev); +} +EXPORT_SYMBOL(hts221_probe); + +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("STMicroelectronics hts221 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c new file mode 100644 index 000000000000..367ecd509f31 --- /dev/null +++ b/drivers/iio/humidity/hts221_i2c.c @@ -0,0 +1,110 @@ +/* + * STMicroelectronics hts221 i2c driver + * + * Copyright 2016 STMicroelectronics Inc. + * + * Lorenzo Bianconi + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include "hts221.h" + +#define I2C_AUTO_INCREMENT 0x80 + +static int hts221_i2c_read(struct device *dev, u8 addr, int len, u8 *data) +{ + struct i2c_msg msg[2]; + struct i2c_client *client = to_i2c_client(dev); + + if (len > 1) + addr |= I2C_AUTO_INCREMENT; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].len = 1; + msg[0].buf = &addr; + + msg[1].addr = client->addr; + msg[1].flags = client->flags | I2C_M_RD; + msg[1].len = len; + msg[1].buf = data; + + return i2c_transfer(client->adapter, msg, 2); +} + +static int hts221_i2c_write(struct device *dev, u8 addr, int len, u8 *data) +{ + u8 send[len + 1]; + struct i2c_msg msg; + struct i2c_client *client = to_i2c_client(dev); + + if (len > 1) + addr |= I2C_AUTO_INCREMENT; + + send[0] = addr; + memcpy(&send[1], data, len * sizeof(u8)); + + msg.addr = client->addr; + msg.flags = client->flags; + msg.len = len + 1; + msg.buf = send; + + return i2c_transfer(client->adapter, &msg, 1); +} + +static const struct hts221_transfer_function hts221_transfer_fn = { + .read = hts221_i2c_read, + .write = hts221_i2c_write, +}; + +static int hts221_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct hts221_hw *hw; + struct iio_dev *iio_dev; + + iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*hw)); + if (!iio_dev) + return -ENOMEM; + + i2c_set_clientdata(client, iio_dev); + + hw = iio_priv(iio_dev); + hw->name = client->name; + hw->dev = &client->dev; + hw->irq = client->irq; + hw->tf = &hts221_transfer_fn; + + return hts221_probe(iio_dev); +} + +static const struct of_device_id hts221_i2c_of_match[] = { + { .compatible = "st,hts221", }, + {}, +}; +MODULE_DEVICE_TABLE(of, hts221_i2c_of_match); + +static const struct i2c_device_id hts221_i2c_id_table[] = { + { HTS221_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table); + +static struct i2c_driver hts221_driver = { + .driver = { + .name = "hts221_i2c", + .of_match_table = of_match_ptr(hts221_i2c_of_match), + }, + .probe = hts221_i2c_probe, + .id_table = hts221_i2c_id_table, +}; +module_i2c_driver(hts221_driver); + +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("STMicroelectronics hts221 i2c driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c new file mode 100644 index 000000000000..70df5e7150c1 --- /dev/null +++ b/drivers/iio/humidity/hts221_spi.c @@ -0,0 +1,125 @@ +/* + * STMicroelectronics hts221 spi driver + * + * Copyright 2016 STMicroelectronics Inc. + * + * Lorenzo Bianconi + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include "hts221.h" + +#define SENSORS_SPI_READ 0x80 +#define SPI_AUTO_INCREMENT 0x40 + +static int hts221_spi_read(struct device *dev, u8 addr, int len, u8 *data) +{ + int err; + struct spi_device *spi = to_spi_device(dev); + struct iio_dev *iio_dev = spi_get_drvdata(spi); + struct hts221_hw *hw = iio_priv(iio_dev); + + struct spi_transfer xfers[] = { + { + .tx_buf = hw->tb.tx_buf, + .bits_per_word = 8, + .len = 1, + }, + { + .rx_buf = hw->tb.rx_buf, + .bits_per_word = 8, + .len = len, + } + }; + + if (len > 1) + addr |= SPI_AUTO_INCREMENT; + hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ; + + err = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); + if (err < 0) + return err; + + memcpy(data, hw->tb.rx_buf, len * sizeof(u8)); + + return len; +} + +static int hts221_spi_write(struct device *dev, u8 addr, int len, u8 *data) +{ + struct spi_device *spi = to_spi_device(dev); + struct iio_dev *iio_dev = spi_get_drvdata(spi); + struct hts221_hw *hw = iio_priv(iio_dev); + + struct spi_transfer xfers = { + .tx_buf = hw->tb.tx_buf, + .bits_per_word = 8, + .len = len + 1, + }; + + if (len >= HTS221_TX_MAX_LENGTH) + return -ENOMEM; + + if (len > 1) + addr |= SPI_AUTO_INCREMENT; + hw->tb.tx_buf[0] = addr; + memcpy(&hw->tb.tx_buf[1], data, len); + + return spi_sync_transfer(spi, &xfers, 1); +} + +static const struct hts221_transfer_function hts221_transfer_fn = { + .read = hts221_spi_read, + .write = hts221_spi_write, +}; + +static int hts221_spi_probe(struct spi_device *spi) +{ + struct hts221_hw *hw; + struct iio_dev *iio_dev; + + iio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*hw)); + if (!iio_dev) + return -ENOMEM; + + spi_set_drvdata(spi, iio_dev); + + hw = iio_priv(iio_dev); + hw->name = spi->modalias; + hw->dev = &spi->dev; + hw->irq = spi->irq; + hw->tf = &hts221_transfer_fn; + + return hts221_probe(iio_dev); +} + +static const struct of_device_id hts221_spi_of_match[] = { + { .compatible = "st,hts221", }, + {}, +}; +MODULE_DEVICE_TABLE(of, hts221_spi_of_match); + +static const struct spi_device_id hts221_spi_id_table[] = { + { HTS221_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(spi, hts221_spi_id_table); + +static struct spi_driver hts221_driver = { + .driver = { + .name = "hts221_spi", + .of_match_table = of_match_ptr(hts221_spi_of_match), + }, + .probe = hts221_spi_probe, + .id_table = hts221_spi_id_table, +}; +module_spi_driver(hts221_driver); + +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("STMicroelectronics hts221 spi driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 36534b40673510a0bd0a87cdfaf07cb4596a3159 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:06:56 +0200 Subject: staging:iio:ad7606: Remove unused int_vref_mv field Remove the int_vref_mv field from the ad7606_chip_info struct since the field is never used by the driver. The value is also the same for all derivatives of this chip, so if it will ever be used in the driver a constant value will work just fine. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.h | 2 -- drivers/staging/iio/adc/ad7606_core.c | 3 --- 2 files changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 39f50440d915..b7e59a6c4b05 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -43,14 +43,12 @@ struct ad7606_platform_data { /** * struct ad7606_chip_info - chip specific information * @name: identification string for chip - * @int_vref_mv: the internal reference voltage * @channels: channel specification * @num_channels: number of channels */ struct ad7606_chip_info { const char *name; - u16 int_vref_mv; const struct iio_chan_spec *channels; unsigned int num_channels; }; diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index 204222517a39..a1f18d412cb0 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -261,19 +261,16 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { */ [ID_AD7606_8] = { .name = "ad7606", - .int_vref_mv = 2500, .channels = ad7606_channels, .num_channels = 9, }, [ID_AD7606_6] = { .name = "ad7606-6", - .int_vref_mv = 2500, .channels = ad7606_channels, .num_channels = 7, }, [ID_AD7606_4] = { .name = "ad7606-4", - .int_vref_mv = 2500, .channels = ad7606_channels, .num_channels = 5, }, -- cgit v1.2.3 From 063a51c5bdefaf7972c6ee7945b05eeb7a842961 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:06:57 +0200 Subject: staging:iio:ad7606: Remove redundant name field from ad7606_chip_info The name field in the ad7606_chip_info struct is set to the same value as the as the name field in the corresponding {platform,spi}_device_id table entry. Remove it from the ad7606_chip_info struct and pass the name from the ID to the probe function. This slightly reduces the size of the chip_info table and adding new entries requires less boilerplate. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.h | 4 ++-- drivers/staging/iio/adc/ad7606_core.c | 11 ++++------- drivers/staging/iio/adc/ad7606_par.c | 3 ++- drivers/staging/iio/adc/ad7606_spi.c | 3 ++- 4 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index b7e59a6c4b05..380c56ae6570 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -48,7 +48,6 @@ struct ad7606_platform_data { */ struct ad7606_chip_info { - const char *name; const struct iio_chan_spec *channels; unsigned int num_channels; }; @@ -84,7 +83,8 @@ struct ad7606_bus_ops { }; struct iio_dev *ad7606_probe(struct device *dev, int irq, - void __iomem *base_address, unsigned int id, + void __iomem *base_address, + const char *name, unsigned int id, const struct ad7606_bus_ops *bops); int ad7606_remove(struct iio_dev *indio_dev, int irq); int ad7606_reset(struct ad7606_state *st); diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index a1f18d412cb0..109364750ac7 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -260,17 +260,14 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { * More devices added in future */ [ID_AD7606_8] = { - .name = "ad7606", .channels = ad7606_channels, .num_channels = 9, }, [ID_AD7606_6] = { - .name = "ad7606-6", .channels = ad7606_channels, .num_channels = 7, }, [ID_AD7606_4] = { - .name = "ad7606-4", .channels = ad7606_channels, .num_channels = 5, }, @@ -438,7 +435,7 @@ static const struct iio_info ad7606_info_range = { struct iio_dev *ad7606_probe(struct device *dev, int irq, void __iomem *base_address, - unsigned int id, + const char *name, unsigned int id, const struct ad7606_bus_ops *bops) { struct ad7606_platform_data *pdata = dev->platform_data; @@ -491,7 +488,7 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, indio_dev->info = &ad7606_info_no_os_or_range; } indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->name = st->chip_info->name; + indio_dev->name = name; indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; @@ -505,8 +502,8 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, if (ret) dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); - ret = request_irq(irq, ad7606_interrupt, - IRQF_TRIGGER_FALLING, st->chip_info->name, indio_dev); + ret = request_irq(irq, ad7606_interrupt, IRQF_TRIGGER_FALLING, name, + indio_dev); if (ret) goto error_free_gpios; diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index 84d23930fdde..0a23cd923415 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -49,6 +49,7 @@ static const struct ad7606_bus_ops ad7606_par8_bops = { static int ad7606_par_probe(struct platform_device *pdev) { + const struct platform_device_id *id = platform_get_device_id(pdev); struct resource *res; struct iio_dev *indio_dev; void __iomem *addr; @@ -69,7 +70,7 @@ static int ad7606_par_probe(struct platform_device *pdev) remap_size = resource_size(res); indio_dev = ad7606_probe(&pdev->dev, irq, addr, - platform_get_device_id(pdev)->driver_data, + id->name, id->driver_data, remap_size > 1 ? &ad7606_par16_bops : &ad7606_par8_bops); diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c index 9587fa86dc69..f69db597d6e0 100644 --- a/drivers/staging/iio/adc/ad7606_spi.c +++ b/drivers/staging/iio/adc/ad7606_spi.c @@ -42,10 +42,11 @@ static const struct ad7606_bus_ops ad7606_spi_bops = { static int ad7606_spi_probe(struct spi_device *spi) { + const struct spi_device_id *id = spi_get_device_id(spi); struct iio_dev *indio_dev; indio_dev = ad7606_probe(&spi->dev, spi->irq, NULL, - spi_get_device_id(spi)->driver_data, + id->name, id->driver_data, &ad7606_spi_bops); if (IS_ERR(indio_dev)) -- cgit v1.2.3 From 9f72520fa4e0a1c3060c523ca075f323b9c77488 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:06:58 +0200 Subject: staging:iio:ad7606: Remove default device configuration from platform data While for some very selected setups it might be useful to be able to provide default configuration data via the platform data, generally this becomes very impractical as the number of configuration options increases. So the general policy is to use the power-on default values of the device and let the application using the device configure it according to its needs. Implement this scheme for the ad7606 driver by removing support for specifying a default configuration via the platform data. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.h | 4 ---- drivers/staging/iio/adc/ad7606_core.c | 12 ++---------- 2 files changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 380c56ae6570..cf6be6500bfb 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -15,8 +15,6 @@ /** * struct ad7606_platform_data - platform/board specific information - * @default_os: default oversampling value {0, 2, 4, 8, 16, 32, 64} - * @default_range: default range +/-{5000, 10000} mVolt * @gpio_convst: number of gpio connected to the CONVST pin * @gpio_reset: gpio connected to the RESET pin, if not used set to -1 * @gpio_range: gpio connected to the RANGE pin, if not used set to -1 @@ -28,8 +26,6 @@ */ struct ad7606_platform_data { - unsigned int default_os; - unsigned int default_range; unsigned int gpio_convst; unsigned int gpio_reset; unsigned int gpio_range; diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index 109364750ac7..a16c6f5a333b 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -452,16 +452,8 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, st->dev = dev; st->bops = bops; st->base_address = base_address; - st->range = pdata->default_range == 10000 ? 10000 : 5000; - - ret = ad7606_oversampling_get_index(pdata->default_os); - if (ret < 0) { - dev_warn(dev, "oversampling %d is not supported\n", - pdata->default_os); - st->oversampling = 0; - } else { - st->oversampling = pdata->default_os; - } + st->range = 5000; + st->oversampling = 0; st->reg = devm_regulator_get(dev, "vcc"); if (!IS_ERR(st->reg)) { -- cgit v1.2.3 From aa9602666894ca02935267c348286b4f1efda186 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:06:59 +0200 Subject: staging:iio:ad7606: Remove out-of-band error reporting Currently the ad7606 driver prints a error message to the kernel log when an application writes an invalid value to a sysfs attribute. While for initial driver development and testing this might be useful it is quite disadvantageous in a production environment. The write() call to the sysfs attribute will already return an error if the value was invalid so the application is aware that the operation failed. And generally speaking it is impossible for an application to reliably match a log message in the kernel log to a specific operation it performed, so the message becomes just noise and might distract from more critical messages. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606_core.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index a16c6f5a333b..d3a35512261a 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -132,10 +132,9 @@ static ssize_t ad7606_store_range(struct device *dev, if (ret) return ret; - if (!(lval == 5000 || lval == 10000)) { - dev_err(dev, "range is not supported\n"); + if (!(lval == 5000 || lval == 10000)) return -EINVAL; - } + mutex_lock(&indio_dev->mlock); gpio_set_value(st->pdata->gpio_range, lval == 10000); st->range = lval; @@ -174,11 +173,8 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, if (val2) return -EINVAL; ret = ad7606_oversampling_get_index(val); - if (ret < 0) { - dev_err(st->dev, "oversampling %d is not supported\n", - val); + if (ret < 0) return ret; - } mutex_lock(&indio_dev->mlock); gpio_set_value(st->pdata->gpio_os0, (ret >> 0) & 1); -- cgit v1.2.3 From e79e8027c1bb9e5525ad186efef1d89309c378f2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:07:00 +0200 Subject: staging:iio:ad7606: Use oversampling ratio of 1 for no oversampling Currently the ad7606 driver uses a value of 0 for the oversampling ratio to express that no oversampling is done. Strictly speaking this means though that no data capture is done at all. Instead change the driver to use a value of 1, this is in accordance with what other drivers do and what the IIO spec suggests. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index d3a35512261a..7c093e2a0faf 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -149,7 +149,7 @@ static IIO_CONST_ATTR(in_voltage_range_available, "5000 10000"); static int ad7606_oversampling_get_index(unsigned int val) { - unsigned char supported[] = {0, 2, 4, 8, 16, 32, 64}; + unsigned char supported[] = {1, 2, 4, 8, 16, 32, 64}; int i; for (i = 0; i < ARRAY_SIZE(supported); i++) @@ -188,7 +188,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, } } -static IIO_CONST_ATTR(oversampling_ratio_available, "0 2 4 8 16 32 64"); +static IIO_CONST_ATTR(oversampling_ratio_available, "1 2 4 8 16 32 64"); static struct attribute *ad7606_attributes_os_and_range[] = { &iio_dev_attr_in_voltage_range.dev_attr.attr, @@ -449,7 +449,7 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, st->bops = bops; st->base_address = base_address; st->range = 5000; - st->oversampling = 0; + st->oversampling = 1; st->reg = devm_regulator_get(dev, "vcc"); if (!IS_ERR(st->reg)) { -- cgit v1.2.3 From f915f7aafba79784b8d89cf186fd63d3b16b91b9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:07:01 +0200 Subject: staging:iio:ad7606: Avoid allocating buffer for each data capture Currently the ad7606 driver dynamically allocates and frees a transfer buffer each time a sample capture is performed in buffered mode, which introduces unnecessary overhead. The driver state struct already contains a buffer that is used for transfers in one-shot mode. This buffer is large enough to hold all samples, but not the timestamp that might be present in buffered mode. Extend the buffer size to be able to contain the timestamp and update the buffered capture function to use this buffer. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.h | 4 ++-- drivers/staging/iio/adc/ad7606_ring.c | 14 ++++---------- 2 files changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index cf6be6500bfb..129f94e57c23 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -68,9 +68,9 @@ struct ad7606_state { /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. + * 8 * 16-bit samples + 64-bit timestamp */ - - unsigned short data[8] ____cacheline_aligned; + unsigned short data[12] ____cacheline_aligned; }; struct ad7606_bus_ops { diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c index 0572df9aad85..7fa4ccccb727 100644 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ b/drivers/staging/iio/adc/ad7606_ring.c @@ -46,15 +46,10 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) struct ad7606_state *st = container_of(work_s, struct ad7606_state, poll_work); struct iio_dev *indio_dev = iio_priv_to_dev(st); - __u8 *buf; int ret; - buf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (!buf) - return; - if (gpio_is_valid(st->pdata->gpio_frstdata)) { - ret = st->bops->read_block(st->dev, 1, buf); + ret = st->bops->read_block(st->dev, 1, st->data); if (ret) goto done; if (!gpio_get_value(st->pdata->gpio_frstdata)) { @@ -67,22 +62,21 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) goto done; } ret = st->bops->read_block(st->dev, - st->chip_info->num_channels - 1, buf + 2); + st->chip_info->num_channels - 1, st->data + 1); if (ret) goto done; } else { ret = st->bops->read_block(st->dev, - st->chip_info->num_channels, buf); + st->chip_info->num_channels, st->data); if (ret) goto done; } - iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_push_to_buffers_with_timestamp(indio_dev, st->data, iio_get_time_ns(indio_dev)); done: gpio_set_value(st->pdata->gpio_convst, 0); iio_trigger_notify_done(indio_dev->trig); - kfree(buf); } int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev) -- cgit v1.2.3 From 91b7334bae734586b153a79fd82873c5d00eb950 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:07:02 +0200 Subject: staging:iio:ad7606: Factor out common code between periodic and one-shot capture Both the periodic buffer based and one-shot sysfs based capture methods share a large portion of their code. Factor this out into a common helper function. Also provide a comment that better explains in more detail what is going on in the capture function. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.h | 1 + drivers/staging/iio/adc/ad7606_core.c | 58 ++++++++++++++++++++++------------- drivers/staging/iio/adc/ad7606_ring.c | 30 +++--------------- 3 files changed, 41 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 129f94e57c23..2257bdbcd73a 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -84,6 +84,7 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, const struct ad7606_bus_ops *bops); int ad7606_remove(struct iio_dev *indio_dev, int irq); int ad7606_reset(struct ad7606_state *st); +int ad7606_read_samples(struct ad7606_state *st); enum ad7606_supported_device_ids { ID_AD7606_8, diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index 7c093e2a0faf..4ce103a16eeb 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -36,6 +36,39 @@ int ad7606_reset(struct ad7606_state *st) return -ENODEV; } +int ad7606_read_samples(struct ad7606_state *st) +{ + unsigned int num = st->chip_info->num_channels; + u16 *data = st->data; + int ret; + + /* + * The frstdata signal is set to high while and after reading the sample + * of the first channel and low for all other channels. This can be used + * to check that the incoming data is correctly aligned. During normal + * operation the data should never become unaligned, but some glitch or + * electrostatic discharge might cause an extra read or clock cycle. + * Monitoring the frstdata signal allows to recover from such failure + * situations. + */ + + if (gpio_is_valid(st->pdata->gpio_frstdata)) { + ret = st->bops->read_block(st->dev, 1, data); + if (ret) + return ret; + + if (!gpio_get_value(st->pdata->gpio_frstdata)) { + ad7606_reset(st); + return -EIO; + } + + data++; + num--; + } + + return st->bops->read_block(st->dev, num, data); +} + static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) { struct ad7606_state *st = iio_priv(indio_dev); @@ -48,28 +81,9 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) if (ret) goto error_ret; - if (gpio_is_valid(st->pdata->gpio_frstdata)) { - ret = st->bops->read_block(st->dev, 1, st->data); - if (ret) - goto error_ret; - if (!gpio_get_value(st->pdata->gpio_frstdata)) { - /* This should never happen */ - ad7606_reset(st); - ret = -EIO; - goto error_ret; - } - ret = st->bops->read_block(st->dev, - st->chip_info->num_channels - 1, &st->data[1]); - if (ret) - goto error_ret; - } else { - ret = st->bops->read_block(st->dev, - st->chip_info->num_channels, st->data); - if (ret) - goto error_ret; - } - - ret = st->data[ch]; + ret = ad7606_read_samples(st); + if (ret == 0) + ret = st->data[ch]; error_ret: gpio_set_value(st->pdata->gpio_convst, 0); diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c index 7fa4ccccb727..b7bf0cf87b10 100644 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ b/drivers/staging/iio/adc/ad7606_ring.c @@ -48,33 +48,11 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) struct iio_dev *indio_dev = iio_priv_to_dev(st); int ret; - if (gpio_is_valid(st->pdata->gpio_frstdata)) { - ret = st->bops->read_block(st->dev, 1, st->data); - if (ret) - goto done; - if (!gpio_get_value(st->pdata->gpio_frstdata)) { - /* This should never happen. However - * some signal glitch caused by bad PCB desgin or - * electrostatic discharge, could cause an extra read - * or clock. This allows recovery. - */ - ad7606_reset(st); - goto done; - } - ret = st->bops->read_block(st->dev, - st->chip_info->num_channels - 1, st->data + 1); - if (ret) - goto done; - } else { - ret = st->bops->read_block(st->dev, - st->chip_info->num_channels, st->data); - if (ret) - goto done; - } + ret = ad7606_read_samples(st); + if (ret == 0) + iio_push_to_buffers_with_timestamp(indio_dev, st->data, + iio_get_time_ns(indio_dev)); - iio_push_to_buffers_with_timestamp(indio_dev, st->data, - iio_get_time_ns(indio_dev)); -done: gpio_set_value(st->pdata->gpio_convst, 0); iio_trigger_notify_done(indio_dev->trig); } -- cgit v1.2.3 From 382a4777ec03ef2b3320a39eec415003f76e9be4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:07:03 +0200 Subject: staging:iio:ad7606: Move set_drvdata() into common code Both the platform_device and SPI driver call set_drvdata() at the end of their probe function. Move this into the common probe() function to reduce duplicated code. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606_core.c | 2 ++ drivers/staging/iio/adc/ad7606_par.c | 2 -- drivers/staging/iio/adc/ad7606_spi.c | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index 4ce103a16eeb..13d8090bd821 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -517,6 +517,8 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, if (ret) goto error_unregister_ring; + dev_set_drvdata(dev, indio_dev); + return indio_dev; error_unregister_ring: ad7606_ring_cleanup(indio_dev); diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index 0a23cd923415..c273993a7f2e 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -77,8 +77,6 @@ static int ad7606_par_probe(struct platform_device *pdev) if (IS_ERR(indio_dev)) return PTR_ERR(indio_dev); - platform_set_drvdata(pdev, indio_dev); - return 0; } diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c index f69db597d6e0..9abbc151a771 100644 --- a/drivers/staging/iio/adc/ad7606_spi.c +++ b/drivers/staging/iio/adc/ad7606_spi.c @@ -52,8 +52,6 @@ static int ad7606_spi_probe(struct spi_device *spi) if (IS_ERR(indio_dev)) return PTR_ERR(indio_dev); - spi_set_drvdata(spi, indio_dev); - return 0; } -- cgit v1.2.3 From 71faca73af90df461c2cb3fccaefcf06793ab99f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:07:04 +0200 Subject: staging:iio:ad7606: Let the common probe function return int The common probe function for the ad7606 currently returns a struct iio_dev pointer. The returned value is not used by the individual driver probe functions other than for error checking. Let the common probe function return a int instead to report the error value directly (or 0 on success). This allows to simplify the code. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.h | 7 +++---- drivers/staging/iio/adc/ad7606_core.c | 15 +++++++-------- drivers/staging/iio/adc/ad7606_par.c | 14 ++++---------- drivers/staging/iio/adc/ad7606_spi.c | 12 +++--------- 4 files changed, 17 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 2257bdbcd73a..b4b25a2202f2 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -78,10 +78,9 @@ struct ad7606_bus_ops { int (*read_block)(struct device *, int, void *); }; -struct iio_dev *ad7606_probe(struct device *dev, int irq, - void __iomem *base_address, - const char *name, unsigned int id, - const struct ad7606_bus_ops *bops); +int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, + const char *name, unsigned int id, + const struct ad7606_bus_ops *bops); int ad7606_remove(struct iio_dev *indio_dev, int irq); int ad7606_reset(struct ad7606_state *st); int ad7606_read_samples(struct ad7606_state *st); diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index 13d8090bd821..1ee7a290cf4d 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -443,10 +443,9 @@ static const struct iio_info ad7606_info_range = { .attrs = &ad7606_attribute_group_range, }; -struct iio_dev *ad7606_probe(struct device *dev, int irq, - void __iomem *base_address, - const char *name, unsigned int id, - const struct ad7606_bus_ops *bops) +int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, + const char *name, unsigned int id, + const struct ad7606_bus_ops *bops) { struct ad7606_platform_data *pdata = dev->platform_data; struct ad7606_state *st; @@ -455,7 +454,7 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) - return ERR_PTR(-ENOMEM); + return -ENOMEM; st = iio_priv(indio_dev); @@ -469,7 +468,7 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - return ERR_PTR(ret); + return ret; } st->pdata = pdata; @@ -519,7 +518,7 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, dev_set_drvdata(dev, indio_dev); - return indio_dev; + return 0; error_unregister_ring: ad7606_ring_cleanup(indio_dev); @@ -532,7 +531,7 @@ error_free_gpios: error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); - return ERR_PTR(ret); + return ret; } EXPORT_SYMBOL_GPL(ad7606_probe); diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index c273993a7f2e..42eb9e0cae1a 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -51,7 +51,6 @@ static int ad7606_par_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); struct resource *res; - struct iio_dev *indio_dev; void __iomem *addr; resource_size_t remap_size; int irq; @@ -69,15 +68,10 @@ static int ad7606_par_probe(struct platform_device *pdev) remap_size = resource_size(res); - indio_dev = ad7606_probe(&pdev->dev, irq, addr, - id->name, id->driver_data, - remap_size > 1 ? &ad7606_par16_bops : - &ad7606_par8_bops); - - if (IS_ERR(indio_dev)) - return PTR_ERR(indio_dev); - - return 0; + return ad7606_probe(&pdev->dev, irq, addr, + id->name, id->driver_data, + remap_size > 1 ? &ad7606_par16_bops : + &ad7606_par8_bops); } static int ad7606_par_remove(struct platform_device *pdev) diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c index 9abbc151a771..064c4c217b9b 100644 --- a/drivers/staging/iio/adc/ad7606_spi.c +++ b/drivers/staging/iio/adc/ad7606_spi.c @@ -43,16 +43,10 @@ static const struct ad7606_bus_ops ad7606_spi_bops = { static int ad7606_spi_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); - struct iio_dev *indio_dev; - indio_dev = ad7606_probe(&spi->dev, spi->irq, NULL, - id->name, id->driver_data, - &ad7606_spi_bops); - - if (IS_ERR(indio_dev)) - return PTR_ERR(indio_dev); - - return 0; + return ad7606_probe(&spi->dev, spi->irq, NULL, + id->name, id->driver_data, + &ad7606_spi_bops); } static int ad7606_spi_remove(struct spi_device *spi) -- cgit v1.2.3 From a866058f8e40a30c62027990c91aa71008617207 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:07:05 +0200 Subject: staging:iio:ad7606: Let common remove function take a struct device * Currently the common remove function takes a struct iio_dev *. This parameter is retrieved by the individual driver remove functions by calling get_drvdata() on their device. To simplify the code let the common remove function directly take a struct dev * and do the IIO device in retrieval the common remove function. This also aligns the interface with the common probe function. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.h | 2 +- drivers/staging/iio/adc/ad7606_core.c | 3 ++- drivers/staging/iio/adc/ad7606_par.c | 6 +----- drivers/staging/iio/adc/ad7606_spi.c | 4 +--- 4 files changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index b4b25a2202f2..6dde987f15c1 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -81,7 +81,7 @@ struct ad7606_bus_ops { int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, const char *name, unsigned int id, const struct ad7606_bus_ops *bops); -int ad7606_remove(struct iio_dev *indio_dev, int irq); +int ad7606_remove(struct device *dev, int irq); int ad7606_reset(struct ad7606_state *st); int ad7606_read_samples(struct ad7606_state *st); diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index 1ee7a290cf4d..670caa2d3343 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -535,8 +535,9 @@ error_disable_reg: } EXPORT_SYMBOL_GPL(ad7606_probe); -int ad7606_remove(struct iio_dev *indio_dev, int irq) +int ad7606_remove(struct device *dev, int irq) { + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad7606_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index 42eb9e0cae1a..cd6c410c0484 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -76,11 +76,7 @@ static int ad7606_par_probe(struct platform_device *pdev) static int ad7606_par_remove(struct platform_device *pdev) { - struct iio_dev *indio_dev = platform_get_drvdata(pdev); - - ad7606_remove(indio_dev, platform_get_irq(pdev, 0)); - - return 0; + return ad7606_remove(&pdev->dev, platform_get_irq(pdev, 0)); } static const struct platform_device_id ad7606_driver_ids[] = { diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c index 064c4c217b9b..c9b1f26685f4 100644 --- a/drivers/staging/iio/adc/ad7606_spi.c +++ b/drivers/staging/iio/adc/ad7606_spi.c @@ -51,9 +51,7 @@ static int ad7606_spi_probe(struct spi_device *spi) static int ad7606_spi_remove(struct spi_device *spi) { - struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev); - - return ad7606_remove(indio_dev, spi->irq); + return ad7606_remove(&spi->dev, spi->irq); } static const struct spi_device_id ad7606_id[] = { -- cgit v1.2.3 From f52666772d579233b5aa3e1fb57187bbec80fc50 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:07:06 +0200 Subject: staging:iio:ad7606: Run trigger handler only once per trigger event Currently the ad7606 driver installs the same function for the hard-irq and threaded trigger handlers. This was introduced in commit 1caf7cb46135 ("staging:iio:adc:ad7606 Convert to new channel registration method Update Add missing call to iio_trigger_notify_done() Set pollfunc top and bottom half handler"). Unfortunately the commit message does not mention why this was done and Michael does not remember either. Since the trigger handler function is idempotent (set a GPIO to 1) running it twice does not do any harm, but is simply not necessary either. So set the threaded trigger handler for the driver to NULL. While we are at it also remove the function description comment that does no say anything that can't be derived from the function name itself. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606_ring.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c index b7bf0cf87b10..81e4a0ac51b7 100644 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ b/drivers/staging/iio/adc/ad7606_ring.c @@ -18,11 +18,7 @@ #include "ad7606.h" -/** - * ad7606_trigger_handler_th() th/bh of trigger launched polling to ring buffer - * - **/ -static irqreturn_t ad7606_trigger_handler_th_bh(int irq, void *p) +static irqreturn_t ad7606_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct ad7606_state *st = iio_priv(pf->indio_dev); @@ -63,9 +59,8 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev) INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring); - return iio_triggered_buffer_setup(indio_dev, - &ad7606_trigger_handler_th_bh, &ad7606_trigger_handler_th_bh, - NULL); + return iio_triggered_buffer_setup(indio_dev, &ad7606_trigger_handler, + NULL, NULL); } void ad7606_ring_cleanup(struct iio_dev *indio_dev) -- cgit v1.2.3 From 722407a4e8c03a36736ea4a384688cf8cbf87f4b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:07:07 +0200 Subject: staging:iio:ad7606: Use GPIO descriptor API Convert the ad7606 driver away from the deprecated legacy GPIO API and use the new GPIO descriptor API. This also means that the platform data struct is now empty and can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.h | 35 ++---- drivers/staging/iio/adc/ad7606_core.c | 200 ++++++++++------------------------ drivers/staging/iio/adc/ad7606_ring.c | 4 +- 3 files changed, 64 insertions(+), 175 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 6dde987f15c1..f5f85faf3921 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -9,33 +9,6 @@ #ifndef IIO_ADC_AD7606_H_ #define IIO_ADC_AD7606_H_ -/* - * TODO: struct ad7606_platform_data needs to go into include/linux/iio - */ - -/** - * struct ad7606_platform_data - platform/board specific information - * @gpio_convst: number of gpio connected to the CONVST pin - * @gpio_reset: gpio connected to the RESET pin, if not used set to -1 - * @gpio_range: gpio connected to the RANGE pin, if not used set to -1 - * @gpio_os0: gpio connected to the OS0 pin, if not used set to -1 - * @gpio_os1: gpio connected to the OS1 pin, if not used set to -1 - * @gpio_os2: gpio connected to the OS2 pin, if not used set to -1 - * @gpio_frstdata: gpio connected to the FRSTDAT pin, if not used set to -1 - * @gpio_stby: gpio connected to the STBY pin, if not used set to -1 - */ - -struct ad7606_platform_data { - unsigned int gpio_convst; - unsigned int gpio_reset; - unsigned int gpio_range; - unsigned int gpio_os0; - unsigned int gpio_os1; - unsigned int gpio_os2; - unsigned int gpio_frstdata; - unsigned int gpio_stby; -}; - /** * struct ad7606_chip_info - chip specific information * @name: identification string for chip @@ -55,7 +28,6 @@ struct ad7606_chip_info { struct ad7606_state { struct device *dev; const struct ad7606_chip_info *chip_info; - struct ad7606_platform_data *pdata; struct regulator *reg; struct work_struct poll_work; wait_queue_head_t wq_data_avail; @@ -65,6 +37,13 @@ struct ad7606_state { bool done; void __iomem *base_address; + struct gpio_desc *gpio_convst; + struct gpio_desc *gpio_reset; + struct gpio_desc *gpio_range; + struct gpio_desc *gpio_standby; + struct gpio_desc *gpio_frstdata; + struct gpio_descs *gpio_os; + /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index 670caa2d3343..4ef6cb4a2726 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -26,10 +26,10 @@ int ad7606_reset(struct ad7606_state *st) { - if (gpio_is_valid(st->pdata->gpio_reset)) { - gpio_set_value(st->pdata->gpio_reset, 1); + if (st->gpio_reset) { + gpiod_set_value(st->gpio_reset, 1); ndelay(100); /* t_reset >= 100ns */ - gpio_set_value(st->pdata->gpio_reset, 0); + gpiod_set_value(st->gpio_reset, 0); return 0; } @@ -52,12 +52,12 @@ int ad7606_read_samples(struct ad7606_state *st) * situations. */ - if (gpio_is_valid(st->pdata->gpio_frstdata)) { + if (st->gpio_frstdata) { ret = st->bops->read_block(st->dev, 1, data); if (ret) return ret; - if (!gpio_get_value(st->pdata->gpio_frstdata)) { + if (!gpiod_get_value(st->gpio_frstdata)) { ad7606_reset(st); return -EIO; } @@ -75,7 +75,7 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) int ret; st->done = false; - gpio_set_value(st->pdata->gpio_convst, 1); + gpiod_set_value(st->gpio_convst, 1); ret = wait_event_interruptible(st->wq_data_avail, st->done); if (ret) @@ -86,7 +86,7 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) ret = st->data[ch]; error_ret: - gpio_set_value(st->pdata->gpio_convst, 0); + gpiod_set_value(st->gpio_convst, 0); return ret; } @@ -150,7 +150,7 @@ static ssize_t ad7606_store_range(struct device *dev, return -EINVAL; mutex_lock(&indio_dev->mlock); - gpio_set_value(st->pdata->gpio_range, lval == 10000); + gpiod_set_value(st->gpio_range, lval == 10000); st->range = lval; mutex_unlock(&indio_dev->mlock); @@ -180,6 +180,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, long mask) { struct ad7606_state *st = iio_priv(indio_dev); + int values[3]; int ret; switch (mask) { @@ -190,12 +191,16 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; + values[0] = (ret >> 0) & 1; + values[1] = (ret >> 1) & 1; + values[2] = (ret >> 2) & 1; + mutex_lock(&indio_dev->mlock); - gpio_set_value(st->pdata->gpio_os0, (ret >> 0) & 1); - gpio_set_value(st->pdata->gpio_os1, (ret >> 1) & 1); - gpio_set_value(st->pdata->gpio_os2, (ret >> 2) & 1); + gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, + values); st->oversampling = val; mutex_unlock(&indio_dev->mlock); + return 0; default: return -EINVAL; @@ -285,119 +290,37 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { static int ad7606_request_gpios(struct ad7606_state *st) { - struct gpio gpio_array[3] = { - [0] = { - .gpio = st->pdata->gpio_os0, - .flags = GPIOF_DIR_OUT | ((st->oversampling & 1) ? - GPIOF_INIT_HIGH : GPIOF_INIT_LOW), - .label = "AD7606_OS0", - }, - [1] = { - .gpio = st->pdata->gpio_os1, - .flags = GPIOF_DIR_OUT | ((st->oversampling & 2) ? - GPIOF_INIT_HIGH : GPIOF_INIT_LOW), - .label = "AD7606_OS1", - }, - [2] = { - .gpio = st->pdata->gpio_os2, - .flags = GPIOF_DIR_OUT | ((st->oversampling & 4) ? - GPIOF_INIT_HIGH : GPIOF_INIT_LOW), - .label = "AD7606_OS2", - }, - }; - int ret; + struct device *dev = st->dev; - if (gpio_is_valid(st->pdata->gpio_convst)) { - ret = gpio_request_one(st->pdata->gpio_convst, - GPIOF_OUT_INIT_LOW, - "AD7606_CONVST"); - if (ret) { - dev_err(st->dev, "failed to request GPIO CONVST\n"); - goto error_ret; - } - } else { - ret = -EIO; - goto error_ret; - } + st->gpio_convst = devm_gpiod_get(dev, "conversion-start", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_convst)) + return PTR_ERR(st->gpio_convst); - if (gpio_is_valid(st->pdata->gpio_os0) && - gpio_is_valid(st->pdata->gpio_os1) && - gpio_is_valid(st->pdata->gpio_os2)) { - ret = gpio_request_array(gpio_array, ARRAY_SIZE(gpio_array)); - if (ret < 0) - goto error_free_convst; - } + st->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_reset)) + return PTR_ERR(st->gpio_reset); - if (gpio_is_valid(st->pdata->gpio_reset)) { - ret = gpio_request_one(st->pdata->gpio_reset, - GPIOF_OUT_INIT_LOW, - "AD7606_RESET"); - if (ret < 0) - goto error_free_os; - } + st->gpio_range = devm_gpiod_get_optional(dev, "range", GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_range)) + return PTR_ERR(st->gpio_range); - if (gpio_is_valid(st->pdata->gpio_range)) { - ret = gpio_request_one(st->pdata->gpio_range, GPIOF_DIR_OUT | - ((st->range == 10000) ? GPIOF_INIT_HIGH : - GPIOF_INIT_LOW), "AD7606_RANGE"); - if (ret < 0) - goto error_free_reset; - } - if (gpio_is_valid(st->pdata->gpio_stby)) { - ret = gpio_request_one(st->pdata->gpio_stby, - GPIOF_OUT_INIT_HIGH, - "AD7606_STBY"); - if (ret < 0) - goto error_free_range; - } + st->gpio_standby = devm_gpiod_get_optional(dev, "standby", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_standby)) + return PTR_ERR(st->gpio_standby); - if (gpio_is_valid(st->pdata->gpio_frstdata)) { - ret = gpio_request_one(st->pdata->gpio_frstdata, GPIOF_IN, - "AD7606_FRSTDATA"); - if (ret < 0) - goto error_free_stby; - } + st->gpio_frstdata = devm_gpiod_get_optional(dev, "first-data", + GPIOD_IN); + if (IS_ERR(st->gpio_frstdata)) + return PTR_ERR(st->gpio_frstdata); - return 0; + st->gpio_os = devm_gpiod_get_array_optional(dev, "oversampling-ratio", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_os)) + return PTR_ERR(st->gpio_os); -error_free_stby: - if (gpio_is_valid(st->pdata->gpio_stby)) - gpio_free(st->pdata->gpio_stby); -error_free_range: - if (gpio_is_valid(st->pdata->gpio_range)) - gpio_free(st->pdata->gpio_range); -error_free_reset: - if (gpio_is_valid(st->pdata->gpio_reset)) - gpio_free(st->pdata->gpio_reset); -error_free_os: - if (gpio_is_valid(st->pdata->gpio_os0) && - gpio_is_valid(st->pdata->gpio_os1) && - gpio_is_valid(st->pdata->gpio_os2)) - gpio_free_array(gpio_array, ARRAY_SIZE(gpio_array)); -error_free_convst: - gpio_free(st->pdata->gpio_convst); -error_ret: - return ret; -} - -static void ad7606_free_gpios(struct ad7606_state *st) -{ - if (gpio_is_valid(st->pdata->gpio_frstdata)) - gpio_free(st->pdata->gpio_frstdata); - if (gpio_is_valid(st->pdata->gpio_stby)) - gpio_free(st->pdata->gpio_stby); - if (gpio_is_valid(st->pdata->gpio_range)) - gpio_free(st->pdata->gpio_range); - if (gpio_is_valid(st->pdata->gpio_reset)) - gpio_free(st->pdata->gpio_reset); - if (gpio_is_valid(st->pdata->gpio_os0) && - gpio_is_valid(st->pdata->gpio_os1) && - gpio_is_valid(st->pdata->gpio_os2)) { - gpio_free(st->pdata->gpio_os2); - gpio_free(st->pdata->gpio_os1); - gpio_free(st->pdata->gpio_os0); - } - gpio_free(st->pdata->gpio_convst); + return 0; } /** @@ -447,7 +370,6 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, const char *name, unsigned int id, const struct ad7606_bus_ops *bops) { - struct ad7606_platform_data *pdata = dev->platform_data; struct ad7606_state *st; int ret; struct iio_dev *indio_dev; @@ -471,19 +393,20 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, return ret; } - st->pdata = pdata; + ret = ad7606_request_gpios(st); + if (ret) + goto error_disable_reg; + st->chip_info = &ad7606_chip_info_tbl[id]; indio_dev->dev.parent = dev; - if (gpio_is_valid(st->pdata->gpio_os0) && - gpio_is_valid(st->pdata->gpio_os1) && - gpio_is_valid(st->pdata->gpio_os2)) { - if (gpio_is_valid(st->pdata->gpio_range)) + if (st->gpio_os) { + if (st->gpio_range) indio_dev->info = &ad7606_info_os_and_range; else indio_dev->info = &ad7606_info_os; } else { - if (gpio_is_valid(st->pdata->gpio_range)) + if (st->gpio_range) indio_dev->info = &ad7606_info_range; else indio_dev->info = &ad7606_info_no_os_or_range; @@ -495,10 +418,6 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, init_waitqueue_head(&st->wq_data_avail); - ret = ad7606_request_gpios(st); - if (ret) - goto error_disable_reg; - ret = ad7606_reset(st); if (ret) dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); @@ -506,7 +425,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, ret = request_irq(irq, ad7606_interrupt, IRQF_TRIGGER_FALLING, name, indio_dev); if (ret) - goto error_free_gpios; + goto error_disable_reg; ret = ad7606_register_ring_funcs_and_init(indio_dev); if (ret) @@ -525,9 +444,6 @@ error_unregister_ring: error_free_irq: free_irq(irq, indio_dev); -error_free_gpios: - ad7606_free_gpios(st); - error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); @@ -547,8 +463,6 @@ int ad7606_remove(struct device *dev, int irq) if (!IS_ERR(st->reg)) regulator_disable(st->reg); - ad7606_free_gpios(st); - return 0; } EXPORT_SYMBOL_GPL(ad7606_remove); @@ -560,10 +474,9 @@ static int ad7606_suspend(struct device *dev) struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad7606_state *st = iio_priv(indio_dev); - if (gpio_is_valid(st->pdata->gpio_stby)) { - if (gpio_is_valid(st->pdata->gpio_range)) - gpio_set_value(st->pdata->gpio_range, 1); - gpio_set_value(st->pdata->gpio_stby, 0); + if (st->gpio_standby) { + gpiod_set_value(st->gpio_range, 1); + gpiod_set_value(st->gpio_standby, 0); } return 0; @@ -574,12 +487,9 @@ static int ad7606_resume(struct device *dev) struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad7606_state *st = iio_priv(indio_dev); - if (gpio_is_valid(st->pdata->gpio_stby)) { - if (gpio_is_valid(st->pdata->gpio_range)) - gpio_set_value(st->pdata->gpio_range, - st->range == 10000); - - gpio_set_value(st->pdata->gpio_stby, 1); + if (st->gpio_standby) { + gpiod_set_value(st->gpio_range, st->range == 10000); + gpiod_set_value(st->gpio_standby, 1); ad7606_reset(st); } diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c index 81e4a0ac51b7..68d72b147f59 100644 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ b/drivers/staging/iio/adc/ad7606_ring.c @@ -23,7 +23,7 @@ static irqreturn_t ad7606_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct ad7606_state *st = iio_priv(pf->indio_dev); - gpio_set_value(st->pdata->gpio_convst, 1); + gpiod_set_value(st->gpio_convst, 1); return IRQ_HANDLED; } @@ -49,7 +49,7 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) iio_push_to_buffers_with_timestamp(indio_dev, st->data, iio_get_time_ns(indio_dev)); - gpio_set_value(st->pdata->gpio_convst, 0); + gpiod_set_value(st->gpio_convst, 0); iio_trigger_notify_done(indio_dev->trig); } -- cgit v1.2.3 From fa23105f85749923569a53139a1bb3465bba604d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Oct 2016 19:07:08 +0200 Subject: staging:iio:ad7606: Move buffer code to main source file Currently the ad7606 buffer handling code resides in its own source file. But this file contains only 4 small functions of which half are just wrappers around other functions. Buffer support is also always enabled for this driver, so move them over to the main source file. This reduces the amount of boilerplate code. Also rename the main function from ad7606_core.c to ad7606.c since there is only a single file now. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/Makefile | 1 - drivers/staging/iio/adc/ad7606.c | 545 ++++++++++++++++++++++++++++++++++ drivers/staging/iio/adc/ad7606.h | 5 - drivers/staging/iio/adc/ad7606_core.c | 506 ------------------------------- drivers/staging/iio/adc/ad7606_ring.c | 69 ----- 5 files changed, 545 insertions(+), 581 deletions(-) create mode 100644 drivers/staging/iio/adc/ad7606.c delete mode 100644 drivers/staging/iio/adc/ad7606_core.c delete mode 100644 drivers/staging/iio/adc/ad7606_ring.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 3cdd83ccec8e..ac09485923b6 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -2,7 +2,6 @@ # Makefile for industrial I/O ADC drivers # -ad7606-y := ad7606_core.o ad7606_ring.o obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o obj-$(CONFIG_AD7606) += ad7606.o diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c new file mode 100644 index 000000000000..010c6e16fb7c --- /dev/null +++ b/drivers/staging/iio/adc/ad7606.c @@ -0,0 +1,545 @@ +/* + * AD7606 SPI ADC driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ad7606.h" + +static int ad7606_reset(struct ad7606_state *st) +{ + if (st->gpio_reset) { + gpiod_set_value(st->gpio_reset, 1); + ndelay(100); /* t_reset >= 100ns */ + gpiod_set_value(st->gpio_reset, 0); + return 0; + } + + return -ENODEV; +} + +static int ad7606_read_samples(struct ad7606_state *st) +{ + unsigned int num = st->chip_info->num_channels; + u16 *data = st->data; + int ret; + + /* + * The frstdata signal is set to high while and after reading the sample + * of the first channel and low for all other channels. This can be used + * to check that the incoming data is correctly aligned. During normal + * operation the data should never become unaligned, but some glitch or + * electrostatic discharge might cause an extra read or clock cycle. + * Monitoring the frstdata signal allows to recover from such failure + * situations. + */ + + if (st->gpio_frstdata) { + ret = st->bops->read_block(st->dev, 1, data); + if (ret) + return ret; + + if (!gpiod_get_value(st->gpio_frstdata)) { + ad7606_reset(st); + return -EIO; + } + + data++; + num--; + } + + return st->bops->read_block(st->dev, num, data); +} + +static irqreturn_t ad7606_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct ad7606_state *st = iio_priv(pf->indio_dev); + + gpiod_set_value(st->gpio_convst, 1); + + return IRQ_HANDLED; +} + +/** + * ad7606_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 + * timestamps within the ring. + * I think the one copy of this at a time was to avoid problems if the + * trigger was set far too high and the reads then locked up the computer. + **/ +static void ad7606_poll_bh_to_ring(struct work_struct *work_s) +{ + struct ad7606_state *st = container_of(work_s, struct ad7606_state, + poll_work); + struct iio_dev *indio_dev = iio_priv_to_dev(st); + int ret; + + ret = ad7606_read_samples(st); + if (ret == 0) + iio_push_to_buffers_with_timestamp(indio_dev, st->data, + iio_get_time_ns(indio_dev)); + + gpiod_set_value(st->gpio_convst, 0); + iio_trigger_notify_done(indio_dev->trig); +} + +static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) +{ + struct ad7606_state *st = iio_priv(indio_dev); + int ret; + + st->done = false; + gpiod_set_value(st->gpio_convst, 1); + + ret = wait_event_interruptible(st->wq_data_avail, st->done); + if (ret) + goto error_ret; + + ret = ad7606_read_samples(st); + if (ret == 0) + ret = st->data[ch]; + +error_ret: + gpiod_set_value(st->gpio_convst, 0); + + return ret; +} + +static int ad7606_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + int ret; + struct ad7606_state *st = iio_priv(indio_dev); + + switch (m) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = ad7606_scan_direct(indio_dev, chan->address); + iio_device_release_direct_mode(indio_dev); + + if (ret < 0) + return ret; + *val = (short)ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = st->range * 2; + *val2 = st->chip_info->channels[0].scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = st->oversampling; + return IIO_VAL_INT; + } + return -EINVAL; +} + +static ssize_t ad7606_show_range(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7606_state *st = iio_priv(indio_dev); + + return sprintf(buf, "%u\n", st->range); +} + +static ssize_t ad7606_store_range(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7606_state *st = iio_priv(indio_dev); + unsigned long lval; + int ret; + + ret = kstrtoul(buf, 10, &lval); + if (ret) + return ret; + + if (!(lval == 5000 || lval == 10000)) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + gpiod_set_value(st->gpio_range, lval == 10000); + st->range = lval; + mutex_unlock(&indio_dev->mlock); + + return count; +} + +static IIO_DEVICE_ATTR(in_voltage_range, S_IRUGO | S_IWUSR, + ad7606_show_range, ad7606_store_range, 0); +static IIO_CONST_ATTR(in_voltage_range_available, "5000 10000"); + +static int ad7606_oversampling_get_index(unsigned int val) +{ + unsigned char supported[] = {1, 2, 4, 8, 16, 32, 64}; + int i; + + for (i = 0; i < ARRAY_SIZE(supported); i++) + if (val == supported[i]) + return i; + + return -EINVAL; +} + +static int ad7606_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct ad7606_state *st = iio_priv(indio_dev); + int values[3]; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + if (val2) + return -EINVAL; + ret = ad7606_oversampling_get_index(val); + if (ret < 0) + return ret; + + values[0] = (ret >> 0) & 1; + values[1] = (ret >> 1) & 1; + values[2] = (ret >> 2) & 1; + + mutex_lock(&indio_dev->mlock); + gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, + values); + st->oversampling = val; + mutex_unlock(&indio_dev->mlock); + + return 0; + default: + return -EINVAL; + } +} + +static IIO_CONST_ATTR(oversampling_ratio_available, "1 2 4 8 16 32 64"); + +static struct attribute *ad7606_attributes_os_and_range[] = { + &iio_dev_attr_in_voltage_range.dev_attr.attr, + &iio_const_attr_in_voltage_range_available.dev_attr.attr, + &iio_const_attr_oversampling_ratio_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7606_attribute_group_os_and_range = { + .attrs = ad7606_attributes_os_and_range, +}; + +static struct attribute *ad7606_attributes_os[] = { + &iio_const_attr_oversampling_ratio_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7606_attribute_group_os = { + .attrs = ad7606_attributes_os, +}; + +static struct attribute *ad7606_attributes_range[] = { + &iio_dev_attr_in_voltage_range.dev_attr.attr, + &iio_const_attr_in_voltage_range_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7606_attribute_group_range = { + .attrs = ad7606_attributes_range, +}; + +#define AD7606_CHANNEL(num) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = num, \ + .address = num, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ + .info_mask_shared_by_all = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .scan_index = num, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ + } + +static const struct iio_chan_spec ad7606_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7606_CHANNEL(0), + AD7606_CHANNEL(1), + AD7606_CHANNEL(2), + AD7606_CHANNEL(3), + AD7606_CHANNEL(4), + AD7606_CHANNEL(5), + AD7606_CHANNEL(6), + AD7606_CHANNEL(7), +}; + +static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { + /* + * More devices added in future + */ + [ID_AD7606_8] = { + .channels = ad7606_channels, + .num_channels = 9, + }, + [ID_AD7606_6] = { + .channels = ad7606_channels, + .num_channels = 7, + }, + [ID_AD7606_4] = { + .channels = ad7606_channels, + .num_channels = 5, + }, +}; + +static int ad7606_request_gpios(struct ad7606_state *st) +{ + struct device *dev = st->dev; + + st->gpio_convst = devm_gpiod_get(dev, "conversion-start", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_convst)) + return PTR_ERR(st->gpio_convst); + + st->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_reset)) + return PTR_ERR(st->gpio_reset); + + st->gpio_range = devm_gpiod_get_optional(dev, "range", GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_range)) + return PTR_ERR(st->gpio_range); + + st->gpio_standby = devm_gpiod_get_optional(dev, "standby", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_standby)) + return PTR_ERR(st->gpio_standby); + + st->gpio_frstdata = devm_gpiod_get_optional(dev, "first-data", + GPIOD_IN); + if (IS_ERR(st->gpio_frstdata)) + return PTR_ERR(st->gpio_frstdata); + + st->gpio_os = devm_gpiod_get_array_optional(dev, "oversampling-ratio", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_os)) + return PTR_ERR(st->gpio_os); + + return 0; +} + +/** + * Interrupt handler + */ +static irqreturn_t ad7606_interrupt(int irq, void *dev_id) +{ + struct iio_dev *indio_dev = dev_id; + struct ad7606_state *st = iio_priv(indio_dev); + + if (iio_buffer_enabled(indio_dev)) { + schedule_work(&st->poll_work); + } else { + st->done = true; + wake_up_interruptible(&st->wq_data_avail); + } + + return IRQ_HANDLED; +}; + +static const struct iio_info ad7606_info_no_os_or_range = { + .driver_module = THIS_MODULE, + .read_raw = &ad7606_read_raw, +}; + +static const struct iio_info ad7606_info_os_and_range = { + .driver_module = THIS_MODULE, + .read_raw = &ad7606_read_raw, + .write_raw = &ad7606_write_raw, + .attrs = &ad7606_attribute_group_os_and_range, +}; + +static const struct iio_info ad7606_info_os = { + .driver_module = THIS_MODULE, + .read_raw = &ad7606_read_raw, + .write_raw = &ad7606_write_raw, + .attrs = &ad7606_attribute_group_os, +}; + +static const struct iio_info ad7606_info_range = { + .driver_module = THIS_MODULE, + .read_raw = &ad7606_read_raw, + .attrs = &ad7606_attribute_group_range, +}; + +int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, + const char *name, unsigned int id, + const struct ad7606_bus_ops *bops) +{ + struct ad7606_state *st; + int ret; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + st->dev = dev; + st->bops = bops; + st->base_address = base_address; + st->range = 5000; + st->oversampling = 1; + INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring); + + st->reg = devm_regulator_get(dev, "vcc"); + if (!IS_ERR(st->reg)) { + ret = regulator_enable(st->reg); + if (ret) + return ret; + } + + ret = ad7606_request_gpios(st); + if (ret) + goto error_disable_reg; + + st->chip_info = &ad7606_chip_info_tbl[id]; + + indio_dev->dev.parent = dev; + if (st->gpio_os) { + if (st->gpio_range) + indio_dev->info = &ad7606_info_os_and_range; + else + indio_dev->info = &ad7606_info_os; + } else { + if (st->gpio_range) + indio_dev->info = &ad7606_info_range; + else + indio_dev->info = &ad7606_info_no_os_or_range; + } + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = name; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; + + init_waitqueue_head(&st->wq_data_avail); + + ret = ad7606_reset(st); + if (ret) + dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); + + ret = request_irq(irq, ad7606_interrupt, IRQF_TRIGGER_FALLING, name, + indio_dev); + if (ret) + goto error_disable_reg; + + ret = iio_triggered_buffer_setup(indio_dev, &ad7606_trigger_handler, + NULL, NULL); + if (ret) + goto error_free_irq; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_unregister_ring; + + dev_set_drvdata(dev, indio_dev); + + return 0; +error_unregister_ring: + iio_triggered_buffer_cleanup(indio_dev); + +error_free_irq: + free_irq(irq, indio_dev); + +error_disable_reg: + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); + return ret; +} +EXPORT_SYMBOL_GPL(ad7606_probe); + +int ad7606_remove(struct device *dev, int irq) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad7606_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + + free_irq(irq, indio_dev); + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); + + return 0; +} +EXPORT_SYMBOL_GPL(ad7606_remove); + +#ifdef CONFIG_PM_SLEEP + +static int ad7606_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad7606_state *st = iio_priv(indio_dev); + + if (st->gpio_standby) { + gpiod_set_value(st->gpio_range, 1); + gpiod_set_value(st->gpio_standby, 0); + } + + return 0; +} + +static int ad7606_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad7606_state *st = iio_priv(indio_dev); + + if (st->gpio_standby) { + gpiod_set_value(st->gpio_range, st->range == 10000); + gpiod_set_value(st->gpio_standby, 1); + ad7606_reset(st); + } + + return 0; +} + +SIMPLE_DEV_PM_OPS(ad7606_pm_ops, ad7606_suspend, ad7606_resume); +EXPORT_SYMBOL_GPL(ad7606_pm_ops); + +#endif + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index f5f85faf3921..746f9553d2ba 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -61,8 +61,6 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, const char *name, unsigned int id, const struct ad7606_bus_ops *bops); int ad7606_remove(struct device *dev, int irq); -int ad7606_reset(struct ad7606_state *st); -int ad7606_read_samples(struct ad7606_state *st); enum ad7606_supported_device_ids { ID_AD7606_8, @@ -70,9 +68,6 @@ enum ad7606_supported_device_ids { ID_AD7606_4 }; -int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev); -void ad7606_ring_cleanup(struct iio_dev *indio_dev); - #ifdef CONFIG_PM_SLEEP extern const struct dev_pm_ops ad7606_pm_ops; #define AD7606_PM_OPS (&ad7606_pm_ops) diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c deleted file mode 100644 index 4ef6cb4a2726..000000000000 --- a/drivers/staging/iio/adc/ad7606_core.c +++ /dev/null @@ -1,506 +0,0 @@ -/* - * AD7606 SPI ADC driver - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "ad7606.h" - -int ad7606_reset(struct ad7606_state *st) -{ - if (st->gpio_reset) { - gpiod_set_value(st->gpio_reset, 1); - ndelay(100); /* t_reset >= 100ns */ - gpiod_set_value(st->gpio_reset, 0); - return 0; - } - - return -ENODEV; -} - -int ad7606_read_samples(struct ad7606_state *st) -{ - unsigned int num = st->chip_info->num_channels; - u16 *data = st->data; - int ret; - - /* - * The frstdata signal is set to high while and after reading the sample - * of the first channel and low for all other channels. This can be used - * to check that the incoming data is correctly aligned. During normal - * operation the data should never become unaligned, but some glitch or - * electrostatic discharge might cause an extra read or clock cycle. - * Monitoring the frstdata signal allows to recover from such failure - * situations. - */ - - if (st->gpio_frstdata) { - ret = st->bops->read_block(st->dev, 1, data); - if (ret) - return ret; - - if (!gpiod_get_value(st->gpio_frstdata)) { - ad7606_reset(st); - return -EIO; - } - - data++; - num--; - } - - return st->bops->read_block(st->dev, num, data); -} - -static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) -{ - struct ad7606_state *st = iio_priv(indio_dev); - int ret; - - st->done = false; - gpiod_set_value(st->gpio_convst, 1); - - ret = wait_event_interruptible(st->wq_data_avail, st->done); - if (ret) - goto error_ret; - - ret = ad7606_read_samples(st); - if (ret == 0) - ret = st->data[ch]; - -error_ret: - gpiod_set_value(st->gpio_convst, 0); - - return ret; -} - -static int ad7606_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long m) -{ - int ret; - struct ad7606_state *st = iio_priv(indio_dev); - - switch (m) { - case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = ad7606_scan_direct(indio_dev, chan->address); - iio_device_release_direct_mode(indio_dev); - - if (ret < 0) - return ret; - *val = (short)ret; - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - *val = st->range * 2; - *val2 = st->chip_info->channels[0].scan_type.realbits; - return IIO_VAL_FRACTIONAL_LOG2; - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - *val = st->oversampling; - return IIO_VAL_INT; - } - return -EINVAL; -} - -static ssize_t ad7606_show_range(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7606_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%u\n", st->range); -} - -static ssize_t ad7606_store_range(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7606_state *st = iio_priv(indio_dev); - unsigned long lval; - int ret; - - ret = kstrtoul(buf, 10, &lval); - if (ret) - return ret; - - if (!(lval == 5000 || lval == 10000)) - return -EINVAL; - - mutex_lock(&indio_dev->mlock); - gpiod_set_value(st->gpio_range, lval == 10000); - st->range = lval; - mutex_unlock(&indio_dev->mlock); - - return count; -} - -static IIO_DEVICE_ATTR(in_voltage_range, S_IRUGO | S_IWUSR, - ad7606_show_range, ad7606_store_range, 0); -static IIO_CONST_ATTR(in_voltage_range_available, "5000 10000"); - -static int ad7606_oversampling_get_index(unsigned int val) -{ - unsigned char supported[] = {1, 2, 4, 8, 16, 32, 64}; - int i; - - for (i = 0; i < ARRAY_SIZE(supported); i++) - if (val == supported[i]) - return i; - - return -EINVAL; -} - -static int ad7606_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct ad7606_state *st = iio_priv(indio_dev); - int values[3]; - int ret; - - switch (mask) { - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - if (val2) - return -EINVAL; - ret = ad7606_oversampling_get_index(val); - if (ret < 0) - return ret; - - values[0] = (ret >> 0) & 1; - values[1] = (ret >> 1) & 1; - values[2] = (ret >> 2) & 1; - - mutex_lock(&indio_dev->mlock); - gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, - values); - st->oversampling = val; - mutex_unlock(&indio_dev->mlock); - - return 0; - default: - return -EINVAL; - } -} - -static IIO_CONST_ATTR(oversampling_ratio_available, "1 2 4 8 16 32 64"); - -static struct attribute *ad7606_attributes_os_and_range[] = { - &iio_dev_attr_in_voltage_range.dev_attr.attr, - &iio_const_attr_in_voltage_range_available.dev_attr.attr, - &iio_const_attr_oversampling_ratio_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad7606_attribute_group_os_and_range = { - .attrs = ad7606_attributes_os_and_range, -}; - -static struct attribute *ad7606_attributes_os[] = { - &iio_const_attr_oversampling_ratio_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad7606_attribute_group_os = { - .attrs = ad7606_attributes_os, -}; - -static struct attribute *ad7606_attributes_range[] = { - &iio_dev_attr_in_voltage_range.dev_attr.attr, - &iio_const_attr_in_voltage_range_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad7606_attribute_group_range = { - .attrs = ad7606_attributes_range, -}; - -#define AD7606_CHANNEL(num) \ - { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = num, \ - .address = num, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ - .info_mask_shared_by_all = \ - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ - .scan_index = num, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 16, \ - .storagebits = 16, \ - .endianness = IIO_CPU, \ - }, \ - } - -static const struct iio_chan_spec ad7606_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(8), - AD7606_CHANNEL(0), - AD7606_CHANNEL(1), - AD7606_CHANNEL(2), - AD7606_CHANNEL(3), - AD7606_CHANNEL(4), - AD7606_CHANNEL(5), - AD7606_CHANNEL(6), - AD7606_CHANNEL(7), -}; - -static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { - /* - * More devices added in future - */ - [ID_AD7606_8] = { - .channels = ad7606_channels, - .num_channels = 9, - }, - [ID_AD7606_6] = { - .channels = ad7606_channels, - .num_channels = 7, - }, - [ID_AD7606_4] = { - .channels = ad7606_channels, - .num_channels = 5, - }, -}; - -static int ad7606_request_gpios(struct ad7606_state *st) -{ - struct device *dev = st->dev; - - st->gpio_convst = devm_gpiod_get(dev, "conversion-start", - GPIOD_OUT_LOW); - if (IS_ERR(st->gpio_convst)) - return PTR_ERR(st->gpio_convst); - - st->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(st->gpio_reset)) - return PTR_ERR(st->gpio_reset); - - st->gpio_range = devm_gpiod_get_optional(dev, "range", GPIOD_OUT_LOW); - if (IS_ERR(st->gpio_range)) - return PTR_ERR(st->gpio_range); - - st->gpio_standby = devm_gpiod_get_optional(dev, "standby", - GPIOD_OUT_HIGH); - if (IS_ERR(st->gpio_standby)) - return PTR_ERR(st->gpio_standby); - - st->gpio_frstdata = devm_gpiod_get_optional(dev, "first-data", - GPIOD_IN); - if (IS_ERR(st->gpio_frstdata)) - return PTR_ERR(st->gpio_frstdata); - - st->gpio_os = devm_gpiod_get_array_optional(dev, "oversampling-ratio", - GPIOD_OUT_LOW); - if (IS_ERR(st->gpio_os)) - return PTR_ERR(st->gpio_os); - - return 0; -} - -/** - * Interrupt handler - */ -static irqreturn_t ad7606_interrupt(int irq, void *dev_id) -{ - struct iio_dev *indio_dev = dev_id; - struct ad7606_state *st = iio_priv(indio_dev); - - if (iio_buffer_enabled(indio_dev)) { - schedule_work(&st->poll_work); - } else { - st->done = true; - wake_up_interruptible(&st->wq_data_avail); - } - - return IRQ_HANDLED; -}; - -static const struct iio_info ad7606_info_no_os_or_range = { - .driver_module = THIS_MODULE, - .read_raw = &ad7606_read_raw, -}; - -static const struct iio_info ad7606_info_os_and_range = { - .driver_module = THIS_MODULE, - .read_raw = &ad7606_read_raw, - .write_raw = &ad7606_write_raw, - .attrs = &ad7606_attribute_group_os_and_range, -}; - -static const struct iio_info ad7606_info_os = { - .driver_module = THIS_MODULE, - .read_raw = &ad7606_read_raw, - .write_raw = &ad7606_write_raw, - .attrs = &ad7606_attribute_group_os, -}; - -static const struct iio_info ad7606_info_range = { - .driver_module = THIS_MODULE, - .read_raw = &ad7606_read_raw, - .attrs = &ad7606_attribute_group_range, -}; - -int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, - const char *name, unsigned int id, - const struct ad7606_bus_ops *bops) -{ - struct ad7606_state *st; - int ret; - struct iio_dev *indio_dev; - - indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - - st = iio_priv(indio_dev); - - st->dev = dev; - st->bops = bops; - st->base_address = base_address; - st->range = 5000; - st->oversampling = 1; - - st->reg = devm_regulator_get(dev, "vcc"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; - } - - ret = ad7606_request_gpios(st); - if (ret) - goto error_disable_reg; - - st->chip_info = &ad7606_chip_info_tbl[id]; - - indio_dev->dev.parent = dev; - if (st->gpio_os) { - if (st->gpio_range) - indio_dev->info = &ad7606_info_os_and_range; - else - indio_dev->info = &ad7606_info_os; - } else { - if (st->gpio_range) - indio_dev->info = &ad7606_info_range; - else - indio_dev->info = &ad7606_info_no_os_or_range; - } - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->name = name; - indio_dev->channels = st->chip_info->channels; - indio_dev->num_channels = st->chip_info->num_channels; - - init_waitqueue_head(&st->wq_data_avail); - - ret = ad7606_reset(st); - if (ret) - dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); - - ret = request_irq(irq, ad7606_interrupt, IRQF_TRIGGER_FALLING, name, - indio_dev); - if (ret) - goto error_disable_reg; - - ret = ad7606_register_ring_funcs_and_init(indio_dev); - if (ret) - goto error_free_irq; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_unregister_ring; - - dev_set_drvdata(dev, indio_dev); - - return 0; -error_unregister_ring: - ad7606_ring_cleanup(indio_dev); - -error_free_irq: - free_irq(irq, indio_dev); - -error_disable_reg: - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); - return ret; -} -EXPORT_SYMBOL_GPL(ad7606_probe); - -int ad7606_remove(struct device *dev, int irq) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad7606_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - ad7606_ring_cleanup(indio_dev); - - free_irq(irq, indio_dev); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); - - return 0; -} -EXPORT_SYMBOL_GPL(ad7606_remove); - -#ifdef CONFIG_PM_SLEEP - -static int ad7606_suspend(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad7606_state *st = iio_priv(indio_dev); - - if (st->gpio_standby) { - gpiod_set_value(st->gpio_range, 1); - gpiod_set_value(st->gpio_standby, 0); - } - - return 0; -} - -static int ad7606_resume(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad7606_state *st = iio_priv(indio_dev); - - if (st->gpio_standby) { - gpiod_set_value(st->gpio_range, st->range == 10000); - gpiod_set_value(st->gpio_standby, 1); - ad7606_reset(st); - } - - return 0; -} - -SIMPLE_DEV_PM_OPS(ad7606_pm_ops, ad7606_suspend, ad7606_resume); -EXPORT_SYMBOL_GPL(ad7606_pm_ops); - -#endif - -MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c deleted file mode 100644 index 68d72b147f59..000000000000 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2011-2012 Analog Devices Inc. - * - * Licensed under the GPL-2. - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "ad7606.h" - -static irqreturn_t ad7606_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct ad7606_state *st = iio_priv(pf->indio_dev); - - gpiod_set_value(st->gpio_convst, 1); - - return IRQ_HANDLED; -} - -/** - * ad7606_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 - * timestamps within the ring. - * I think the one copy of this at a time was to avoid problems if the - * trigger was set far too high and the reads then locked up the computer. - **/ -static void ad7606_poll_bh_to_ring(struct work_struct *work_s) -{ - struct ad7606_state *st = container_of(work_s, struct ad7606_state, - poll_work); - struct iio_dev *indio_dev = iio_priv_to_dev(st); - int ret; - - ret = ad7606_read_samples(st); - if (ret == 0) - iio_push_to_buffers_with_timestamp(indio_dev, st->data, - iio_get_time_ns(indio_dev)); - - gpiod_set_value(st->gpio_convst, 0); - iio_trigger_notify_done(indio_dev->trig); -} - -int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev) -{ - struct ad7606_state *st = iio_priv(indio_dev); - - INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring); - - return iio_triggered_buffer_setup(indio_dev, &ad7606_trigger_handler, - NULL, NULL); -} - -void ad7606_ring_cleanup(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); -} -- cgit v1.2.3 From 12edb97471fd4877bc0e527a42e0cbf8ab3937a5 Mon Sep 17 00:00:00 2001 From: Eva Rachel Retuya Date: Thu, 20 Oct 2016 21:08:22 +0800 Subject: staging: iio: ad7606: set proper supply name to devm_regulator_get() The name passed to devm_regulator_get() should match the name of the supply as specified in the device datasheet. The supply on this device is called 'AVcc' while currently, the driver uses just 'vcc'. Use 'avcc' to specify the supply voltage since it is custom to use the lower-caps version of the datasheet name. Suggested-by: Lars-Peter Clausen Signed-off-by: Eva Rachel Retuya Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index 010c6e16fb7c..f9b354ff820a 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -424,7 +424,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, st->oversampling = 1; INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring); - st->reg = devm_regulator_get(dev, "vcc"); + st->reg = devm_regulator_get(dev, "avcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) -- cgit v1.2.3 From f0879217a8710289f3a9bac9e5db8f73e8189750 Mon Sep 17 00:00:00 2001 From: Eva Rachel Retuya Date: Thu, 20 Oct 2016 21:08:23 +0800 Subject: staging: iio: ad7606: rework regulator handling Currently, this driver ignores all errors from regulator_get(). The way it is now, it also breaks probe deferral (EPROBE_DEFER). The correct behavior is to propagate the error to the upper layers so they can handle it accordingly. Rework the regulator handling so that it matches the standard behavior. If the specific design uses a static always-on regulator and does not explicitly specify it, regulator_get() will return the dummy regulator. Suggested-by: Lars-Peter Clausen Signed-off-by: Eva Rachel Retuya Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index f9b354ff820a..b0ae04a449ea 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -425,10 +425,13 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring); st->reg = devm_regulator_get(dev, "avcc"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; + if (IS_ERR(st->reg)) + return PTR_ERR(st->reg); + + ret = regulator_enable(st->reg); + if (ret) { + dev_err(dev, "Failed to enable specified AVcc supply\n"); + return ret; } ret = ad7606_request_gpios(st); @@ -484,8 +487,7 @@ error_free_irq: free_irq(irq, indio_dev); error_disable_reg: - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + regulator_disable(st->reg); return ret; } EXPORT_SYMBOL_GPL(ad7606_probe); @@ -499,8 +501,7 @@ int ad7606_remove(struct device *dev, int irq) iio_triggered_buffer_cleanup(indio_dev); free_irq(irq, indio_dev); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + regulator_disable(st->reg); return 0; } -- cgit v1.2.3 From 6a31c225f5d5182cd711019f99a4e87c92884e2b Mon Sep 17 00:00:00 2001 From: Tomas Novotny Date: Tue, 18 Oct 2016 19:43:06 +0200 Subject: iio: dac: mcp4725: fix incorrect comment Number 2 is referencing to the settings with the largest available resistor. No functional change. Signed-off-by: Tomas Novotny Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4725.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 2b28b1f5b3a2..5b2dfa0a0d2c 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -374,7 +374,7 @@ static int mcp4725_probe(struct i2c_client *client, } pd = (inbuf[0] >> 1) & 0x3; data->powerdown = pd > 0 ? true : false; - data->powerdown_mode = pd ? pd - 1 : 2; /* largest register to gnd */ + data->powerdown_mode = pd ? pd - 1 : 2; /* largest resistor to gnd */ data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4); err = iio_device_register(indio_dev); -- cgit v1.2.3 From 29157c6d601db8cb9f3bea93fc933b73db3bf869 Mon Sep 17 00:00:00 2001 From: Tomas Novotny Date: Tue, 18 Oct 2016 19:43:08 +0200 Subject: iio: dac: mcp4725: support voltage reference selection MCP47x6 chip supports selection of a voltage reference (VDD, VREF buffered or unbuffered). MCP4725 doesn't have this feature thus the eventual setting is ignored and user is warned. The setting is stored only in the volatile memory of the chip. You need to manually store it to the EEPROM of the chip via 'store_eeprom' sysfs entry. Signed-off-by: Tomas Novotny Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4725.c | 99 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 5b2dfa0a0d2c..1e9d8f387e00 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -27,12 +27,20 @@ #define MCP4725_DRV_NAME "mcp4725" +#define MCP472X_REF_VDD 0x00 +#define MCP472X_REF_VREF_UNBUFFERED 0x02 +#define MCP472X_REF_VREF_BUFFERED 0x03 + struct mcp4725_data { struct i2c_client *client; + int id; + unsigned ref_mode; + bool vref_buffered; u16 dac_value; bool powerdown; unsigned powerdown_mode; struct regulator *vdd_reg; + struct regulator *vref_reg; }; static int mcp4725_suspend(struct device *dev) @@ -87,6 +95,7 @@ static ssize_t mcp4725_store_eeprom(struct device *dev, return 0; inoutbuf[0] = 0x60; /* write EEPROM */ + inoutbuf[0] |= data->ref_mode << 3; inoutbuf[1] = data->dac_value >> 4; inoutbuf[2] = (data->dac_value & 0xf) << 4; @@ -279,6 +288,28 @@ static int mcp4725_set_value(struct iio_dev *indio_dev, int val) return 0; } +static int mcp4726_set_cfg(struct iio_dev *indio_dev) +{ + struct mcp4725_data *data = iio_priv(indio_dev); + u8 outbuf[3]; + int ret; + + outbuf[0] = 0x40; + outbuf[0] |= data->ref_mode << 3; + if (data->powerdown) + outbuf[0] |= data->powerdown << 1; + outbuf[1] = data->dac_value >> 4; + outbuf[2] = (data->dac_value & 0xf) << 4; + + ret = i2c_master_send(data->client, outbuf, 3); + if (ret < 0) + return ret; + else if (ret != 3) + return -EIO; + else + return 0; +} + static int mcp4725_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -291,7 +322,11 @@ static int mcp4725_read_raw(struct iio_dev *indio_dev, *val = data->dac_value; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - ret = regulator_get_voltage(data->vdd_reg); + if (data->ref_mode == MCP472X_REF_VDD) + ret = regulator_get_voltage(data->vdd_reg); + else + ret = regulator_get_voltage(data->vref_reg); + if (ret < 0) return ret; @@ -335,8 +370,9 @@ static int mcp4725_probe(struct i2c_client *client, struct mcp4725_data *data; struct iio_dev *indio_dev; struct mcp4725_platform_data *pdata = dev_get_platdata(&client->dev); - u8 inbuf[3]; + u8 inbuf[4]; u8 pd; + u8 ref; int err; if (!pdata) { @@ -350,6 +386,26 @@ static int mcp4725_probe(struct i2c_client *client, data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; + data->id = id->driver_data; + + if (data->id == MCP4725 && pdata->use_vref) { + dev_err(&client->dev, + "external reference is unavailable on MCP4725"); + return -EINVAL; + } + + if (!pdata->use_vref && pdata->vref_buffered) { + dev_err(&client->dev, + "buffering is unavailable on the internal reference"); + return -EINVAL; + } + + if (!pdata->use_vref) + data->ref_mode = MCP472X_REF_VDD; + else + data->ref_mode = pdata->vref_buffered ? + MCP472X_REF_VREF_BUFFERED : + MCP472X_REF_VREF_UNBUFFERED; data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(data->vdd_reg)) @@ -359,6 +415,18 @@ static int mcp4725_probe(struct i2c_client *client, if (err) return err; + if (pdata->use_vref) { + data->vref_reg = devm_regulator_get(&client->dev, "vref"); + if (IS_ERR(data->vref_reg)) { + err = PTR_ERR(data->vdd_reg); + goto err_disable_vdd_reg; + } + + err = regulator_enable(data->vref_reg); + if (err) + goto err_disable_vdd_reg; + } + indio_dev->dev.parent = &client->dev; indio_dev->name = id->name; indio_dev->info = &mcp4725_info; @@ -366,23 +434,38 @@ static int mcp4725_probe(struct i2c_client *client, indio_dev->num_channels = 1; indio_dev->modes = INDIO_DIRECT_MODE; - /* read current DAC value */ - err = i2c_master_recv(client, inbuf, 3); + /* read current DAC value and settings */ + err = i2c_master_recv(client, inbuf, data->id == MCP4725 ? 3 : 4); + if (err < 0) { dev_err(&client->dev, "failed to read DAC value"); - goto err_disable_vdd_reg; + goto err_disable_vref_reg; } pd = (inbuf[0] >> 1) & 0x3; data->powerdown = pd > 0 ? true : false; data->powerdown_mode = pd ? pd - 1 : 2; /* largest resistor to gnd */ data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4); - + if (data->id == MCP4726) + ref = (inbuf[3] >> 3) & 0x3; + + if (data->id == MCP4726 && ref != data->ref_mode) { + dev_info(&client->dev, + "voltage reference mode differs (conf: %u, eeprom: %u), setting %u", + data->ref_mode, ref, data->ref_mode); + err = mcp4726_set_cfg(indio_dev); + if (err < 0) + goto err_disable_vref_reg; + } + err = iio_device_register(indio_dev); if (err) - goto err_disable_vdd_reg; + goto err_disable_vref_reg; return 0; +err_disable_vref_reg: + if (data->vref_reg) + regulator_disable(data->vref_reg); err_disable_vdd_reg: regulator_disable(data->vdd_reg); @@ -397,6 +480,8 @@ static int mcp4725_remove(struct i2c_client *client) iio_device_unregister(indio_dev); + if (data->vref_reg) + regulator_disable(data->vref_reg); regulator_disable(data->vdd_reg); return 0; -- cgit v1.2.3 From 88e39a88b7ff4ec0deaf596bb653a6ca2c0c1f30 Mon Sep 17 00:00:00 2001 From: Tomas Novotny Date: Tue, 18 Oct 2016 19:43:09 +0200 Subject: iio: dac: mcp4725: add devicetree support Signed-off-by: Tomas Novotny Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4725.c | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 1e9d8f387e00..fae80eb1a98a 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -364,22 +365,41 @@ static const struct iio_info mcp4725_info = { .driver_module = THIS_MODULE, }; +#ifdef CONFIG_OF +static int mcp4725_probe_dt(struct device *dev, + struct mcp4725_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + + if (!np) + return -ENODEV; + + /* check if is the vref-supply defined */ + pdata->use_vref = of_property_read_bool(np, "vref-supply"); + pdata->vref_buffered = + of_property_read_bool(np, "microchip,vref-buffered"); + + return 0; +} +#else +static int mcp4725_probe_dt(struct device *dev, + struct mcp4725_platform_data *platform_data) +{ + return -ENODEV; +} +#endif + static int mcp4725_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct mcp4725_data *data; struct iio_dev *indio_dev; - struct mcp4725_platform_data *pdata = dev_get_platdata(&client->dev); + struct mcp4725_platform_data *pdata, pdata_dt; u8 inbuf[4]; u8 pd; u8 ref; int err; - if (!pdata) { - dev_err(&client->dev, "invalid platform data"); - return -EINVAL; - } - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (indio_dev == NULL) return -ENOMEM; @@ -387,6 +407,17 @@ static int mcp4725_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); data->client = client; data->id = id->driver_data; + pdata = dev_get_platdata(&client->dev); + + if (!pdata) { + err = mcp4725_probe_dt(&client->dev, &pdata_dt); + if (err) { + dev_err(&client->dev, + "invalid platform or devicetree data"); + return err; + } + pdata = &pdata_dt; + } if (data->id == MCP4725 && pdata->use_vref) { dev_err(&client->dev, -- cgit v1.2.3 From 16bf793f86b21959fd683ec28b8d196a0520de2f Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Fri, 2 Sep 2016 10:23:17 -0700 Subject: iio: humidity: hdc100x: add triggered buffer support for HDC100X Triggered buffer support uses the HDC100X's dual acquisition mode to read both humidity and temperature in one shot. This patch depends on 447136effbf4 ("iio: humidity: hdc100x: fix sensor data reads of temp and humidity") Signed-off-by: Alison Schofield Cc: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/Kconfig | 2 + drivers/iio/humidity/hdc100x.c | 130 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 130 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig index 6fd11d0813ad..912477d54be2 100644 --- a/drivers/iio/humidity/Kconfig +++ b/drivers/iio/humidity/Kconfig @@ -27,6 +27,8 @@ config DHT11 config HDC100X tristate "TI HDC100x relative humidity and temperature sensor" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to build support for the Texas Instruments HDC1000 and HDC1008 relative humidity and temperature sensors. diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index e0c9c70c2a4a..265c34da52d1 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -22,11 +22,15 @@ #include #include +#include +#include +#include #define HDC100X_REG_TEMP 0x00 #define HDC100X_REG_HUMIDITY 0x01 #define HDC100X_REG_CONFIG 0x02 +#define HDC100X_REG_CONFIG_ACQ_MODE BIT(12) #define HDC100X_REG_CONFIG_HEATER_EN BIT(13) struct hdc100x_data { @@ -87,22 +91,40 @@ static const struct iio_chan_spec hdc100x_channels[] = { BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + }, }, { .type = IIO_HUMIDITYRELATIVE, .address = HDC100X_REG_HUMIDITY, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_INT_TIME) + BIT(IIO_CHAN_INFO_INT_TIME), + .scan_index = 1, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + }, }, { .type = IIO_CURRENT, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .extend_name = "heater", .output = 1, + .scan_index = -1, }, + IIO_CHAN_SOFT_TIMESTAMP(2), }; +static const unsigned long hdc100x_scan_masks[] = {0x3, 0}; + static int hdc100x_update_config(struct hdc100x_data *data, int mask, int val) { int tmp = (~mask & data->config) | val; @@ -183,7 +205,14 @@ static int hdc100x_read_raw(struct iio_dev *indio_dev, *val = hdc100x_get_heater_status(data); ret = IIO_VAL_INT; } else { + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) { + mutex_unlock(&data->lock); + return ret; + } + ret = hdc100x_get_measurement(data, chan); + iio_device_release_direct_mode(indio_dev); if (ret >= 0) { *val = ret; ret = IIO_VAL_INT; @@ -246,6 +275,78 @@ static int hdc100x_write_raw(struct iio_dev *indio_dev, } } +static int hdc100x_buffer_postenable(struct iio_dev *indio_dev) +{ + struct hdc100x_data *data = iio_priv(indio_dev); + int ret; + + /* Buffer is enabled. First set ACQ Mode, then attach poll func */ + mutex_lock(&data->lock); + ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, + HDC100X_REG_CONFIG_ACQ_MODE); + mutex_unlock(&data->lock); + if (ret) + return ret; + + return iio_triggered_buffer_postenable(indio_dev); +} + +static int hdc100x_buffer_predisable(struct iio_dev *indio_dev) +{ + struct hdc100x_data *data = iio_priv(indio_dev); + int ret; + + /* First detach poll func, then reset ACQ mode. OK to disable buffer */ + ret = iio_triggered_buffer_predisable(indio_dev); + if (ret) + return ret; + + mutex_lock(&data->lock); + ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0); + mutex_unlock(&data->lock); + + return ret; +} + +static const struct iio_buffer_setup_ops hdc_buffer_setup_ops = { + .postenable = hdc100x_buffer_postenable, + .predisable = hdc100x_buffer_predisable, +}; + +static irqreturn_t hdc100x_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct hdc100x_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + int delay = data->adc_int_us[0] + data->adc_int_us[1]; + int ret; + s16 buf[8]; /* 2x s16 + padding + 8 byte timestamp */ + + /* dual read starts at temp register */ + mutex_lock(&data->lock); + ret = i2c_smbus_write_byte(client, HDC100X_REG_TEMP); + if (ret < 0) { + dev_err(&client->dev, "cannot start measurement\n"); + goto err; + } + usleep_range(delay, delay + 1000); + + ret = i2c_master_recv(client, (u8 *)buf, 4); + if (ret < 0) { + dev_err(&client->dev, "cannot read sensor data\n"); + goto err; + } + + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); +err: + mutex_unlock(&data->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static const struct iio_info hdc100x_info = { .read_raw = hdc100x_read_raw, .write_raw = hdc100x_write_raw, @@ -258,6 +359,7 @@ static int hdc100x_probe(struct i2c_client *client, { struct iio_dev *indio_dev; struct hdc100x_data *data; + int ret; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C)) @@ -279,12 +381,35 @@ static int hdc100x_probe(struct i2c_client *client, indio_dev->channels = hdc100x_channels; indio_dev->num_channels = ARRAY_SIZE(hdc100x_channels); + indio_dev->available_scan_masks = hdc100x_scan_masks; /* be sure we are in a known state */ hdc100x_set_it_time(data, 0, hdc100x_int_time[0][0]); hdc100x_set_it_time(data, 1, hdc100x_int_time[1][0]); + hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0); + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + hdc100x_trigger_handler, + &hdc_buffer_setup_ops); + if (ret < 0) { + dev_err(&client->dev, "iio triggered buffer setup failed\n"); + return ret; + } + ret = iio_device_register(indio_dev); + if (ret < 0) + iio_triggered_buffer_cleanup(indio_dev); + + return ret; +} + +static int hdc100x_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); - return devm_iio_device_register(&client->dev, indio_dev); + return 0; } static const struct i2c_device_id hdc100x_id[] = { @@ -298,6 +423,7 @@ static struct i2c_driver hdc100x_driver = { .name = "hdc100x", }, .probe = hdc100x_probe, + .remove = hdc100x_remove, .id_table = hdc100x_id, }; module_i2c_driver(hdc100x_driver); -- cgit v1.2.3 From 815bbc87462ae6e5b4d126f6e698fb990270c891 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 17 Oct 2016 00:59:42 +0900 Subject: iio: ti-adc0832: add triggered buffer support This adds triggered buffer support for the ti-adc0832 driver. Tested with ADC0831 and ADC0832 by using SYSFS trigger. Signed-off-by: Akinobu Mita Cc: Jonathan Cameron Cc: Hartmut Knaack Cc: Lars-Peter Clausen Cc: Peter Meerwald-Stadler Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 2 + drivers/iio/adc/ti-adc0832.c | 106 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 89 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 60426685d55d..c3fe98d2dc3b 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -459,6 +459,8 @@ config TI_ADC081C config TI_ADC0832 tristate "Texas Instruments ADC0831/ADC0832/ADC0834/ADC0838" depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help If you say yes here you get support for Texas Instruments ADC0831, ADC0832, ADC0834, ADC0838 ADC chips. diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c index f4ba23effe9a..e952e94a14af 100644 --- a/drivers/iio/adc/ti-adc0832.c +++ b/drivers/iio/adc/ti-adc0832.c @@ -14,6 +14,10 @@ #include #include #include +#include +#include +#include +#include enum { adc0831, @@ -38,10 +42,16 @@ struct adc0832 { .indexed = 1, \ .channel = chan, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = chan, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 8, \ + .storagebits = 8, \ + }, \ } -#define ADC0832_VOLTAGE_CHANNEL_DIFF(chan1, chan2) \ +#define ADC0832_VOLTAGE_CHANNEL_DIFF(chan1, chan2, si) \ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -49,18 +59,26 @@ struct adc0832 { .channel2 = (chan2), \ .differential = 1, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = si, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 8, \ + .storagebits = 8, \ + }, \ } static const struct iio_chan_spec adc0831_channels[] = { - ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1), + ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1, 0), + IIO_CHAN_SOFT_TIMESTAMP(1), }; static const struct iio_chan_spec adc0832_channels[] = { ADC0832_VOLTAGE_CHANNEL(0), ADC0832_VOLTAGE_CHANNEL(1), - ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1), - ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0), + ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1, 2), + ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0, 3), + IIO_CHAN_SOFT_TIMESTAMP(4), }; static const struct iio_chan_spec adc0834_channels[] = { @@ -68,10 +86,11 @@ static const struct iio_chan_spec adc0834_channels[] = { ADC0832_VOLTAGE_CHANNEL(1), ADC0832_VOLTAGE_CHANNEL(2), ADC0832_VOLTAGE_CHANNEL(3), - ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1), - ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0), - ADC0832_VOLTAGE_CHANNEL_DIFF(2, 3), - ADC0832_VOLTAGE_CHANNEL_DIFF(3, 2), + ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1, 4), + ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0, 5), + ADC0832_VOLTAGE_CHANNEL_DIFF(2, 3, 6), + ADC0832_VOLTAGE_CHANNEL_DIFF(3, 2, 7), + IIO_CHAN_SOFT_TIMESTAMP(8), }; static const struct iio_chan_spec adc0838_channels[] = { @@ -83,14 +102,15 @@ static const struct iio_chan_spec adc0838_channels[] = { ADC0832_VOLTAGE_CHANNEL(5), ADC0832_VOLTAGE_CHANNEL(6), ADC0832_VOLTAGE_CHANNEL(7), - ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1), - ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0), - ADC0832_VOLTAGE_CHANNEL_DIFF(2, 3), - ADC0832_VOLTAGE_CHANNEL_DIFF(3, 2), - ADC0832_VOLTAGE_CHANNEL_DIFF(4, 5), - ADC0832_VOLTAGE_CHANNEL_DIFF(5, 4), - ADC0832_VOLTAGE_CHANNEL_DIFF(6, 7), - ADC0832_VOLTAGE_CHANNEL_DIFF(7, 6), + ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1, 8), + ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0, 9), + ADC0832_VOLTAGE_CHANNEL_DIFF(2, 3, 10), + ADC0832_VOLTAGE_CHANNEL_DIFF(3, 2, 11), + ADC0832_VOLTAGE_CHANNEL_DIFF(4, 5, 12), + ADC0832_VOLTAGE_CHANNEL_DIFF(5, 4, 13), + ADC0832_VOLTAGE_CHANNEL_DIFF(6, 7, 14), + ADC0832_VOLTAGE_CHANNEL_DIFF(7, 6, 15), + IIO_CHAN_SOFT_TIMESTAMP(16), }; static int adc0831_adc_conversion(struct adc0832 *adc) @@ -178,6 +198,42 @@ static const struct iio_info adc0832_info = { .driver_module = THIS_MODULE, }; +static irqreturn_t adc0832_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct adc0832 *adc = iio_priv(indio_dev); + u8 data[24] = { }; /* 16x 1 byte ADC data + 8 bytes timestamp */ + int scan_index; + int i = 0; + + mutex_lock(&adc->lock); + + for_each_set_bit(scan_index, indio_dev->active_scan_mask, + indio_dev->masklength) { + const struct iio_chan_spec *scan_chan = + &indio_dev->channels[scan_index]; + int ret = adc0832_adc_conversion(adc, scan_chan->channel, + scan_chan->differential); + if (ret < 0) { + dev_warn(&adc->spi->dev, + "failed to get conversion data\n"); + goto out; + } + + data[i] = ret; + i++; + } + iio_push_to_buffers_with_timestamp(indio_dev, data, + iio_get_time_ns(indio_dev)); +out: + mutex_unlock(&adc->lock); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static int adc0832_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -233,9 +289,20 @@ static int adc0832_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); + ret = iio_triggered_buffer_setup(indio_dev, NULL, + adc0832_trigger_handler, NULL); + if (ret) + goto err_reg_disable; + ret = iio_device_register(indio_dev); if (ret) - regulator_disable(adc->reg); + goto err_buffer_cleanup; + + return 0; +err_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); +err_reg_disable: + regulator_disable(adc->reg); return ret; } @@ -246,6 +313,7 @@ static int adc0832_remove(struct spi_device *spi) struct adc0832 *adc = iio_priv(indio_dev); iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); regulator_disable(adc->reg); return 0; -- cgit v1.2.3 From a84a6a8aa0f6e02dec63a2ff69946f80785e35b9 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 15 Oct 2016 11:04:37 -0700 Subject: iio: proximity: pulsedlight-lidar-lite-v2: cleanup power management Remove pm_runtime_mark_last_busy() call that wasn't need in the probe since the device should be put to sleep. Clarification from Matt: Basically it going to be suspended once pm_runtime_idle() is called, and setting the last busy is useless and not needed. Clearly this doesn't affect the device running but just makes the code more consistent with other uses. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 3141c3c161bb..1fa9eefa0982 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -301,8 +301,6 @@ static int lidar_probe(struct i2c_client *client, if (ret) goto error_unreg_buffer; pm_runtime_enable(&client->dev); - - pm_runtime_mark_last_busy(&client->dev); pm_runtime_idle(&client->dev); return 0; -- cgit v1.2.3 From dbdef9ba693a5ac7d92368cef7d436b3093e9f4e Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sun, 23 Oct 2016 03:12:42 +0800 Subject: staging:iio:ad7606: fix ptr_ret.cocci warnings drivers/staging/iio/adc/ad7606.c:357:1-3: WARNING: PTR_ERR_OR_ZERO can be used Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR Generated by: scripts/coccinelle/api/ptr_ret.cocci CC: Lars-Peter Clausen Signed-off-by: Fengguang Wu Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index b0ae04a449ea..453190864b2f 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -354,10 +354,7 @@ static int ad7606_request_gpios(struct ad7606_state *st) st->gpio_os = devm_gpiod_get_array_optional(dev, "oversampling-ratio", GPIOD_OUT_LOW); - if (IS_ERR(st->gpio_os)) - return PTR_ERR(st->gpio_os); - - return 0; + return PTR_ERR_OR_ZERO(st->gpio_os); } /** -- cgit v1.2.3 From 30df2d1879ff65af7b269ee94e9c7fc276b54105 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 22 Oct 2016 22:41:32 +0200 Subject: iio: dac: mcp4725: fix odd_ptr_err.cocci warnings PTR_ERR should access the value just tested by IS_ERR Generated by: scripts/coccinelle/tests/odd_ptr_err.cocci CC: Tomas Novotny Signed-off-by: Julia Lawall Signed-off-by: Fengguang Wu Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4725.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index fae80eb1a98a..db109f0cdd8c 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -449,7 +449,7 @@ static int mcp4725_probe(struct i2c_client *client, if (pdata->use_vref) { data->vref_reg = devm_regulator_get(&client->dev, "vref"); if (IS_ERR(data->vref_reg)) { - err = PTR_ERR(data->vdd_reg); + err = PTR_ERR(data->vref_reg); goto err_disable_vdd_reg; } -- cgit v1.2.3