linux-stable/drivers/iio/imu/adis.c
Greg Kroah-Hartman 821f7ce79f First set of new device support, features and cleanups for IIO in the 5.6 cycle
New device support
 
 * ad7091r5 ADC
   - New driver with follow up patch adding scale and vref support.
   - DT bindings
 * ad7923
   - Support for ad7908, ad7918 and ad7928 added to driver.
 * bma180
   - Support the BMA254 accelerometer. Required fairly substantial rework
     to allow for small differences between this an existing parts.
 * bma400 accelerometer
   - New driver with follow up patch for regulator support.
   - DT bindings.
 * asc dlhl60d
   - New driver support this range of pressure and temperature sensors.
   - DT bindings.
 * ltc2496 ADC
   - New driver to support this ADC.
   - Split the existing LTC2497 driver generic component out and reuse.
   - DT bindings.
 * parallax ping
   - New driver supporting ultrasonic and laser tof distance sensors.
   - Bindings for these sensors.
 
 New features
 
 * core
   - New char type for read_raw returns, used for thermocouple types.
   - Rename read_first_n callback to read.   The reasons behind the original
     naming are lost to the mists of time.
 * ad799x
   - Allow pm_ops to disable device completely allowing regulator power down.
 * bma180
   - Enable basic regulator support.
 * dmaengine buffer
   - Report platform data alignment requirements via new ABI.
 * max31856
   - Add option to set mains filter rejection frequency and document
     new in_temp_filter_notch_center_frequency ABI.
   - Add support for configuring HW averaging (oversampling ratio)
   - Add runtime configuration of thermocouple type and document new ABI.
 * maxim-thermocouple
   - Add read only access to thermocouple type using new ABI, includes
     adding more specific compatibles to reflect which variant of the
     chip is being used.
 * mpu6050
   - Provide option to support the PMU9150 in package magnetometer directly
     rather than via auxiliary bus.
 * stm32_adc
   - Add overrun interrupt checks to detect if this happens.
 * st_lsm6dsx
   - Enable the sensor-hub support for lsm6dsm. Includes various reworks to
     allow this.
 
 Cleanups and minor fixes
 
 * Subsystem wide
   - Tidy up indentation in Kconfig and fix alphabetical order of AD7091R5.
   - Drop linux/gpio.h and linux/of_gpio.h from drivers that don't use them.
 * ad7266
   - Convert to GPIO descriptors.
 * ad7303
   - Avoid a dance with checking if the regulator is supplied by just
     using the optional request interface.
 * ad7887
   - Simplify channel specification assignment to enable adding more devices.
 * ad7923
   - Drop some unused and largely pointless defines of BOB_N==N variety.
   - Tidy up checkpatch warnings.
   - Add missing of_device_id table.
 * adf4350
   - Convert to GPIO descriptors.
 * ak8975
   - Convert to GPIO descriptors.
 * ADIS library and drivers
   - Expand scope of txrx_lock to cover all state and rename as state_lock
   - Add unlocked read / write to allow grouping of consecutive calls under
     single lock / unlock.
   - Add unlocked check_status, reset to allow grouping under single
     lock / unlock.
   - Remove remaining uses of core mlock for local state protection.
     mlock should never be used directly as it protects tightly defined
     core IIO device management state.
 * adis16240
   - Enforce only supported SPI mode on driver load + add DT binding doc.
 * atlas-ph-sensor
   - Rename to atlas-sensor given it now covers things beyond ph sensors.
 * bma180
   - Use local dev variable to tidy up code.
   - Use c99 style explicity .member assignment to make driver more readable.
 * bmp280
   - Drop ACPI support. No evidence this was used and appropriate ID is not
     registered.
   - Allow ACPI to bind device via PRP0001
 * dmaengine buffer
   - Use dma_request_chan instead of dma_request_slave_channel_reason as that
     ABI is going away.
   - Add module info to avoid tainting the kernel.
 * hts221
   - Avoid magic number defines when only used to fill structure elements
     that are self describing.
 * lm3533
   - Drop a stray semicolon.
 * max9611
   - Cleanup enum handling to be more resilient to future changes.
 * mpu6050
   - Delete MPU9150 from supported SPI devices as doesn't provide SPI.
   - Select I2C_MUX again after kbuild issue fixed elsewhere.
 * stm32-timer
   - Drop an unnecessary register update.
 * ssp_sensors
   - Convert to GPIO descriptors.
 * st_sensors
   - drop !CONFIG_ACPI defines as ACPI_PTR() will stop them being used
     anyway.
   - Make default platform data structures __maybe_unsued.
   - Fill in some missing kernel-doc function parameters.
 * st_lsm6dsx
   - white space fixes.
   - Mark some constants that aren't always used as __maybe_unused.
   - Drop of ID table guards as they just pervent use under ACPI.
   - Switch to device properties to allow ACPI usage.
 * st_uvis25
   - Drop acpi.h include as no ACPI APIs used.
 * ti-ads1015
   - Drop legacy platform data as no one seems to be using it.
   - Use the device property API instead of OF specific.
 * ti-ads7950
   - typo fix in error message.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAl4R2mwRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0Fogfow//Rfsrd2oiAwy4ypm70ZWGnr84C3O/Vpic
 Agwdd2/lHiCA2Gjg+n7ZT6XkKQmKiojuBMT05PuskEm5onJVQuSAKMVppXwU6UDP
 uOUS5MAbo87GLogzXJnAR/eCrx/VkC4UqFRBSi7IUIj+lTpjiOhmoqm78VTMxkgT
 hvp5PVN/mLNxNV3eVrR9uILjZLpbBjKjWil00IS2zj0o78sGtd2QtMIdTbn3iBLp
 m0ngCDww1KDH+idwbOIn8YX8GSK8mTjNV5q4r9+xnjoAk8RPk+H317idyRHCKfCM
 wWFSFB6u/oqtHXRgQVi3ndRrZnPLTycA/R20f3ezzhVYZzf3RpH8Upcx0lqqCmrB
 +ZTbYW1L7KL6zCSR4ZYIEmw2TeQngfCGy0yDoEDXm9V8/B2nGWFc3Iknq+fK415V
 7OgJCWAw6ybF2LZfJHpcuJTb0EPxCKnInHbRsaxCsSAPRyERSdAz8RLn3lpH/k2D
 X32Q9hz/6sXKzIAD1Y0jv8ll28D5S7d2FgaWufy1tpB+CMb0Mp0RQn+Ho8lNMh70
 Zh9SF8RvknAiCT9iHeVIdbJxoYEtMuCaDwScliukVcg12gVViY5VzXMbSV/4jCnZ
 bAVZDpcM3LVLxCGbWqCNxjQ9wle99LsVHRld/KDpOfI6VIYDb8Y900Nf6efkQkAs
 a6z6rhpVdDg=
 =8FmM
 -----END PGP SIGNATURE-----

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

Jonathan writes:

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

New device support

* ad7091r5 ADC
  - New driver with follow up patch adding scale and vref support.
  - DT bindings
* ad7923
  - Support for ad7908, ad7918 and ad7928 added to driver.
* bma180
  - Support the BMA254 accelerometer. Required fairly substantial rework
    to allow for small differences between this an existing parts.
* bma400 accelerometer
  - New driver with follow up patch for regulator support.
  - DT bindings.
* asc dlhl60d
  - New driver support this range of pressure and temperature sensors.
  - DT bindings.
* ltc2496 ADC
  - New driver to support this ADC.
  - Split the existing LTC2497 driver generic component out and reuse.
  - DT bindings.
* parallax ping
  - New driver supporting ultrasonic and laser tof distance sensors.
  - Bindings for these sensors.

New features

* core
  - New char type for read_raw returns, used for thermocouple types.
  - Rename read_first_n callback to read.   The reasons behind the original
    naming are lost to the mists of time.
* ad799x
  - Allow pm_ops to disable device completely allowing regulator power down.
* bma180
  - Enable basic regulator support.
* dmaengine buffer
  - Report platform data alignment requirements via new ABI.
* max31856
  - Add option to set mains filter rejection frequency and document
    new in_temp_filter_notch_center_frequency ABI.
  - Add support for configuring HW averaging (oversampling ratio)
  - Add runtime configuration of thermocouple type and document new ABI.
* maxim-thermocouple
  - Add read only access to thermocouple type using new ABI, includes
    adding more specific compatibles to reflect which variant of the
    chip is being used.
* mpu6050
  - Provide option to support the PMU9150 in package magnetometer directly
    rather than via auxiliary bus.
* stm32_adc
  - Add overrun interrupt checks to detect if this happens.
* st_lsm6dsx
  - Enable the sensor-hub support for lsm6dsm. Includes various reworks to
    allow this.

Cleanups and minor fixes

* Subsystem wide
  - Tidy up indentation in Kconfig and fix alphabetical order of AD7091R5.
  - Drop linux/gpio.h and linux/of_gpio.h from drivers that don't use them.
* ad7266
  - Convert to GPIO descriptors.
* ad7303
  - Avoid a dance with checking if the regulator is supplied by just
    using the optional request interface.
* ad7887
  - Simplify channel specification assignment to enable adding more devices.
* ad7923
  - Drop some unused and largely pointless defines of BOB_N==N variety.
  - Tidy up checkpatch warnings.
  - Add missing of_device_id table.
* adf4350
  - Convert to GPIO descriptors.
* ak8975
  - Convert to GPIO descriptors.
* ADIS library and drivers
  - Expand scope of txrx_lock to cover all state and rename as state_lock
  - Add unlocked read / write to allow grouping of consecutive calls under
    single lock / unlock.
  - Add unlocked check_status, reset to allow grouping under single
    lock / unlock.
  - Remove remaining uses of core mlock for local state protection.
    mlock should never be used directly as it protects tightly defined
    core IIO device management state.
* adis16240
  - Enforce only supported SPI mode on driver load + add DT binding doc.
* atlas-ph-sensor
  - Rename to atlas-sensor given it now covers things beyond ph sensors.
* bma180
  - Use local dev variable to tidy up code.
  - Use c99 style explicity .member assignment to make driver more readable.
* bmp280
  - Drop ACPI support. No evidence this was used and appropriate ID is not
    registered.
  - Allow ACPI to bind device via PRP0001
* dmaengine buffer
  - Use dma_request_chan instead of dma_request_slave_channel_reason as that
    ABI is going away.
  - Add module info to avoid tainting the kernel.
* hts221
  - Avoid magic number defines when only used to fill structure elements
    that are self describing.
* lm3533
  - Drop a stray semicolon.
* max9611
  - Cleanup enum handling to be more resilient to future changes.
* mpu6050
  - Delete MPU9150 from supported SPI devices as doesn't provide SPI.
  - Select I2C_MUX again after kbuild issue fixed elsewhere.
* stm32-timer
  - Drop an unnecessary register update.
* ssp_sensors
  - Convert to GPIO descriptors.
* st_sensors
  - drop !CONFIG_ACPI defines as ACPI_PTR() will stop them being used
    anyway.
  - Make default platform data structures __maybe_unsued.
  - Fill in some missing kernel-doc function parameters.
* st_lsm6dsx
  - white space fixes.
  - Mark some constants that aren't always used as __maybe_unused.
  - Drop of ID table guards as they just pervent use under ACPI.
  - Switch to device properties to allow ACPI usage.
* st_uvis25
  - Drop acpi.h include as no ACPI APIs used.
* ti-ads1015
  - Drop legacy platform data as no one seems to be using it.
  - Use the device property API instead of OF specific.
* ti-ads7950
  - typo fix in error message.

* tag 'iio-for-5.6a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (99 commits)
  iio: accel: bma180: BMA254 support
  iio: pressure: bmp280: Allow device to be enumerated from ACPI
  iio: pressure: bmp280: Drop ACPI support
  dt-bindings: iio: adc: convert sd modulator to json-schema
  iio: buffer: rename 'read_first_n' callback to 'read'
  iio: buffer-dmaengine: Report buffer length requirements
  bindings: iio: pressure: Add documentation for dlh driver
  dt-bindings: Add asc vendor
  iio: pressure: Add driver for DLH pressure sensors
  iio: buffer-dmaengine: Add module information
  iio: accel: bma180: Use explicit member assignment
  iio: accel: bma180: Basic regulator support
  iio: accel: bma180: Add dev helper variable
  iio: imu: st_lsm6dsx: enable sensor-hub support for lsm6dsm
  iio: imu: st_lsm6dsx: rename st_lsm6dsx_shub_read_reg in st_lsm6dsx_shub_read_output
  iio: imu: st_lsm6dsx: check if shub_output reg is located in primary page
  iio: imu: st_lsm6dsx: check if pull_up is located in primary page
  iio: imu: st_lsm6dsx: check if master_enable is located in primary page
  iio: imu: st_lsm6dsx: export max num of slave devices in st_lsm6dsx_shub_settings
  iio: light: remove unneeded semicolon
  ...
2020-01-10 10:44:00 +01:00

466 lines
11 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Common library for ADIS16XXX devices
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*/
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <asm/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#define ADIS_MSC_CTRL_DATA_RDY_EN BIT(2)
#define ADIS_MSC_CTRL_DATA_RDY_POL_HIGH BIT(1)
#define ADIS_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
#define ADIS_GLOB_CMD_SW_RESET BIT(7)
/**
* __adis_write_reg() - write N bytes to register (unlocked version)
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @value: The value to write to device (up to 4 bytes)
* @size: The size of the @value (in bytes)
*/
int __adis_write_reg(struct adis *adis, unsigned int reg,
unsigned int value, unsigned int size)
{
unsigned int page = reg / ADIS_PAGE_SIZE;
int ret, i;
struct spi_message msg;
struct spi_transfer xfers[] = {
{
.tx_buf = adis->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 4,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 6,
.bits_per_word = 8,
.len = 2,
.delay_usecs = adis->data->write_delay,
}, {
.tx_buf = adis->tx + 8,
.bits_per_word = 8,
.len = 2,
.delay_usecs = adis->data->write_delay,
},
};
spi_message_init(&msg);
if (adis->current_page != page) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = page;
spi_message_add_tail(&xfers[0], &msg);
}
switch (size) {
case 4:
adis->tx[8] = ADIS_WRITE_REG(reg + 3);
adis->tx[9] = (value >> 24) & 0xff;
adis->tx[6] = ADIS_WRITE_REG(reg + 2);
adis->tx[7] = (value >> 16) & 0xff;
/* fall through */
case 2:
adis->tx[4] = ADIS_WRITE_REG(reg + 1);
adis->tx[5] = (value >> 8) & 0xff;
/* fall through */
case 1:
adis->tx[2] = ADIS_WRITE_REG(reg);
adis->tx[3] = value & 0xff;
break;
default:
return -EINVAL;
}
xfers[size].cs_change = 0;
for (i = 1; i <= size; i++)
spi_message_add_tail(&xfers[i], &msg);
ret = spi_sync(adis->spi, &msg);
if (ret) {
dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n",
reg, ret);
} else {
adis->current_page = page;
}
return ret;
}
EXPORT_SYMBOL_GPL(__adis_write_reg);
/**
* __adis_read_reg() - read N bytes from register (unlocked version)
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @val: The value read back from the device
* @size: The size of the @val buffer
*/
int __adis_read_reg(struct adis *adis, unsigned int reg,
unsigned int *val, unsigned int size)
{
unsigned int page = reg / ADIS_PAGE_SIZE;
struct spi_message msg;
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = adis->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->read_delay,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 4,
.rx_buf = adis->rx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->read_delay,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.rx_buf = adis->rx + 2,
.bits_per_word = 8,
.len = 2,
.delay_usecs = adis->data->read_delay,
},
};
spi_message_init(&msg);
if (adis->current_page != page) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = page;
spi_message_add_tail(&xfers[0], &msg);
}
switch (size) {
case 4:
adis->tx[2] = ADIS_READ_REG(reg + 2);
adis->tx[3] = 0;
spi_message_add_tail(&xfers[1], &msg);
/* fall through */
case 2:
adis->tx[4] = ADIS_READ_REG(reg);
adis->tx[5] = 0;
spi_message_add_tail(&xfers[2], &msg);
spi_message_add_tail(&xfers[3], &msg);
break;
default:
return -EINVAL;
}
ret = spi_sync(adis->spi, &msg);
if (ret) {
dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
reg, ret);
return ret;
} else {
adis->current_page = page;
}
switch (size) {
case 4:
*val = get_unaligned_be32(adis->rx);
break;
case 2:
*val = get_unaligned_be16(adis->rx + 2);
break;
}
return ret;
}
EXPORT_SYMBOL_GPL(__adis_read_reg);
#ifdef CONFIG_DEBUG_FS
int adis_debugfs_reg_access(struct iio_dev *indio_dev,
unsigned int reg, unsigned int writeval, unsigned int *readval)
{
struct adis *adis = iio_device_get_drvdata(indio_dev);
if (readval) {
uint16_t val16;
int ret;
ret = adis_read_reg_16(adis, reg, &val16);
if (ret == 0)
*readval = val16;
return ret;
} else {
return adis_write_reg_16(adis, reg, writeval);
}
}
EXPORT_SYMBOL(adis_debugfs_reg_access);
#endif
/**
* adis_enable_irq() - Enable or disable data ready IRQ
* @adis: The adis device
* @enable: Whether to enable the IRQ
*
* Returns 0 on success, negative error code otherwise
*/
int adis_enable_irq(struct adis *adis, bool enable)
{
int ret = 0;
uint16_t msc;
mutex_lock(&adis->state_lock);
if (adis->data->enable_irq) {
ret = adis->data->enable_irq(adis, enable);
goto out_unlock;
}
ret = __adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
if (ret)
goto out_unlock;
msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;
msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;
if (enable)
msc |= ADIS_MSC_CTRL_DATA_RDY_EN;
else
msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;
ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
out_unlock:
mutex_unlock(&adis->state_lock);
return ret;
}
EXPORT_SYMBOL(adis_enable_irq);
/**
* __adis_check_status() - Check the device for error conditions (unlocked)
* @adis: The adis device
*
* Returns 0 on success, a negative error code otherwise
*/
int __adis_check_status(struct adis *adis)
{
uint16_t status;
int ret;
int i;
ret = __adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
if (ret)
return ret;
status &= adis->data->status_error_mask;
if (status == 0)
return 0;
for (i = 0; i < 16; ++i) {
if (status & BIT(i)) {
dev_err(&adis->spi->dev, "%s.\n",
adis->data->status_error_msgs[i]);
}
}
return -EIO;
}
EXPORT_SYMBOL_GPL(__adis_check_status);
/**
* __adis_reset() - Reset the device (unlocked version)
* @adis: The adis device
*
* Returns 0 on success, a negative error code otherwise
*/
int __adis_reset(struct adis *adis)
{
int ret;
ret = __adis_write_reg_8(adis, adis->data->glob_cmd_reg,
ADIS_GLOB_CMD_SW_RESET);
if (ret)
dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(__adis_reset);
static int adis_self_test(struct adis *adis)
{
int ret;
ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
adis->data->self_test_mask);
if (ret) {
dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n",
ret);
return ret;
}
msleep(adis->data->startup_delay);
ret = __adis_check_status(adis);
if (adis->data->self_test_no_autoclear)
__adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00);
return ret;
}
/**
* adis_inital_startup() - Performs device self-test
* @adis: The adis device
*
* Returns 0 if the device is operational, a negative error code otherwise.
*
* This function should be called early on in the device initialization sequence
* to ensure that the device is in a sane and known state and that it is usable.
*/
int adis_initial_startup(struct adis *adis)
{
int ret;
mutex_lock(&adis->state_lock);
ret = adis_self_test(adis);
if (ret) {
dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n");
__adis_reset(adis);
msleep(adis->data->startup_delay);
ret = adis_self_test(adis);
if (ret) {
dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n");
goto out_unlock;
}
}
out_unlock:
mutex_unlock(&adis->state_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_initial_startup);
/**
* adis_single_conversion() - Performs a single sample conversion
* @indio_dev: The IIO device
* @chan: The IIO channel
* @error_mask: Mask for the error bit
* @val: Result of the conversion
*
* Returns IIO_VAL_INT on success, a negative error code otherwise.
*
* The function performs a single conversion on a given channel and post
* processes the value accordingly to the channel spec. If a error_mask is given
* the function will check if the mask is set in the returned raw value. If it
* is set the function will perform a self-check. If the device does not report
* a error bit in the channels raw value set error_mask to 0.
*/
int adis_single_conversion(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int error_mask, int *val)
{
struct adis *adis = iio_device_get_drvdata(indio_dev);
unsigned int uval;
int ret;
mutex_lock(&adis->state_lock);
ret = __adis_read_reg(adis, chan->address, &uval,
chan->scan_type.storagebits / 8);
if (ret)
goto err_unlock;
if (uval & error_mask) {
ret = __adis_check_status(adis);
if (ret)
goto err_unlock;
}
if (chan->scan_type.sign == 's')
*val = sign_extend32(uval, chan->scan_type.realbits - 1);
else
*val = uval & ((1 << chan->scan_type.realbits) - 1);
ret = IIO_VAL_INT;
err_unlock:
mutex_unlock(&adis->state_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_single_conversion);
/**
* adis_init() - Initialize adis device structure
* @adis: The adis device
* @indio_dev: The iio device
* @spi: The spi device
* @data: Chip specific data
*
* Returns 0 on success, a negative error code otherwise.
*
* This function must be called, before any other adis helper function may be
* called.
*/
int adis_init(struct adis *adis, struct iio_dev *indio_dev,
struct spi_device *spi, const struct adis_data *data)
{
mutex_init(&adis->state_lock);
adis->spi = spi;
adis->data = data;
iio_device_set_drvdata(indio_dev, adis);
if (data->has_paging) {
/* Need to set the page before first read/write */
adis->current_page = -1;
} else {
/* Page will always be 0 */
adis->current_page = 0;
}
return adis_enable_irq(adis, false);
}
EXPORT_SYMBOL_GPL(adis_init);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Common library code for ADIS16XXX devices");