Commit 74eb9c06 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-5.4b-take3' of...

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

Jonathan writes:

Second set of new device support, cleanups and features for IIO in the 5.4 cycle

Revised pull request to fix up a missing Signed-off-by and roll in
a fix in the lsm9ds1 support after I broke it when applying.
Revised again because the fix changed a hash meaning a fix
that previously followed it now had the wrong fixes tag.

A few fixes in here that could have gone a faster path but aren't quite
worth the rush for 5.3.

New device support
* ad7606
  - Support the ad7606b which adds a software controlled mode alongside
    the pin controlled only approach of the ad7606. Including dt-bindings.
* lsm6dsx
  - Add support for the gyro and accelerometer part of the lsm9ds1 which is
    a compound device also including a magnetometer (st_sensors driver).
    Includes bindings and precursor rework of the driver.

Features
* ad7192
  - Add support for low pass filter control.
  - DT binding docs.

Cleanups and minor fixes
* MAINTAINERS
  - Fix a typo in a path.
  - Add entry for ad7606
* ad5380
  - Fix a failure to dereference a pointer before atempting to assign the
    value.
* ad7192
  - Drop platform data as not used in mainline and we now have full DT bindings.
* ad7606
  - YAML conversion for dt-bindings.
* adis16240
  - Rework write_raw to make it more readable using GENMASK.
* adis16460
  - Fix and issue with an unsigned variable holding potential negatives.
* cros_ec
  - Fix missing default of calibration vector so that we get 'something'
    before calibration is complete on a given axis.
* hid-sensors
  - Use int_pow instead of opencoding.
* isl29501
  - rename dt-binding docs to include renesas inline with other renesas parts
    and general current convention.
* kxcjk1013
  - Improve comments on the 'unusual' ACPI ids used to identify which sensor
    is which in certain laptops.
* lsm6dsx
  - Add one bit to the fifo status masks for a number of parts.
  - Drop a reserved entry from the sensitivity values to tidy up interface.
  - Use core conversion macro from G to m/s^2 for lsm9ds1 to make it easier
    to relate to the datasheet and consistent with other parts supported.
* max1027
  - Use device managed APIs to avoid manual error handling and cleanup.
* rfd77402
  - Typo in Kconfig help.
* sc27xx
  - Switch to polling mode from interrupts as interrupt handling typically
    to slow for very short sleeps.
* st-sensors
  - Fix some missing selects for regmap.
* tools
  - Add a .gitignore containing the binary outputs.

* tag 'iio-for-5.4b-take3' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (27 commits)
  iio: imu: st_lsm6dsx: rely on IIO_G_TO_M_S_2 for gain definition for LSM9DS1
  iio: imu: st_lsm6dsx: remove invalid gain value for LSM9DS1
  iio: cros_ec: set calibscale for 3d MEMS to unit vector
  iio: dac: ad5380: fix incorrect assignment to val
  iio: imu: st_lsm6dsx: Fix FIFO diff mask for tagged fifo
  dt-bindings: iio: imu: st_lsm6dsx: add lsm9ds1 device bindings
  iio: imu: st_lsm6dsx: add support for accel/gyro unit of lsm9ds1
  iio: imu: st_lsm6dsx: move register definitions to sensor_settings struct
  iio: imu: st_lsm6dsx: introduce update_fifo function pointer
  dt-bindings: iio: light: isl29501: Rename bindings documentation file
  Kconfig: Fix the reference to the RFD77402 ToF sensor in the 'help' section
  iio: st_sensors: Fix build error
  dt-bindings: iio: adc: Add AD7606B ADC documentation
  dt-bindings: iio: adc: Migrate AD7606 documentation to yaml
  MAINTAINERS: Add Beniamin Bia for AD7606 driver
  iio: adc: ad7606: Add support for AD7606B ADC
  tools: iio: add .gitignore
  iio: adc: sc27xx: Change to polling mode to read data
  iio: hid-sensor-attributes: Convert to use int_pow()
  iio: adc: max1027: Use device-managed APIs
  ...
parents dfa5b30b 6fa02948
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright 2019 Analog Devices Inc.
%YAML 1.2
---
$id: http://devicetree.org/schemas/bindings/iio/adc/adi,ad7192.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD7192 ADC device driver
maintainers:
- Michael Hennerich <michael.hennerich@analog.com>
description: |
Bindings for the Analog Devices AD7192 ADC device. Datasheet can be
found here:
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7192.pdf
properties:
compatible:
enum:
- adi,ad7190
- adi,ad7192
- adi,ad7193
- adi,ad7195
reg:
maxItems: 1
spi-cpol: true
spi-cpha: true
clocks:
maxItems: 1
description: phandle to the master clock (mclk)
clock-names:
items:
- const: mclk
interrupts:
maxItems: 1
dvdd-supply:
description: DVdd voltage supply
items:
- const: dvdd
avdd-supply:
description: AVdd voltage supply
items:
- const: avdd
adi,rejection-60-Hz-enable:
description: |
This bit enables a notch at 60 Hz when the first notch of the sinc
filter is at 50 Hz. When REJ60 is set, a filter notch is placed at
60 Hz when the sinc filter first notch is at 50 Hz. This allows
simultaneous 50 Hz/ 60 Hz rejection.
type: boolean
adi,refin2-pins-enable:
description: |
External reference applied between the P1/REFIN2(+) and P0/REFIN2(−) pins.
type: boolean
adi,buffer-enable:
description: |
Enables the buffer on the analog inputs. If cleared, the analog inputs
are unbuffered, lowering the power consumption of the device. If this
bit is set, the analog inputs are buffered, allowing the user to place
source impedances on the front end without contributing gain errors to
the system.
type: boolean
adi,burnout-currents-enable:
description: |
When this bit is set to 1, the 500 nA current sources in the signal
path are enabled. When BURN = 0, the burnout currents are disabled.
The burnout currents can be enabled only when the buffer is active
and when chop is disabled.
type: boolean
bipolar:
description: see Documentation/devicetree/bindings/iio/adc/adc.txt
type: boolean
required:
- compatible
- reg
- clocks
- clock-names
- interrupts
- dvdd-supply
- avdd-supply
- spi-cpol
- spi-cpha
examples:
- |
spi0 {
adc@0 {
compatible = "adi,ad7192";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
spi-cpha;
clocks = <&ad7192_mclk>;
clock-names = "mclk";
#interrupt-cells = <2>;
interrupts = <25 0x2>;
interrupt-parent = <&gpio>;
dvdd-supply = <&dvdd>;
avdd-supply = <&avdd>;
adi,refin2-pins-enable;
adi,rejection-60-Hz-enable;
adi,buffer-enable;
adi,burnout-currents-enable;
};
};
Analog Devices AD7606 Simultaneous Sampling ADC
Required properties for the AD7606:
- compatible: Must be one of
* "adi,ad7605-4"
* "adi,ad7606-8"
* "adi,ad7606-6"
* "adi,ad7606-4"
* "adi,ad7616"
- reg: SPI chip select number for the device
- spi-max-frequency: Max SPI frequency to use
see: Documentation/devicetree/bindings/spi/spi-bus.txt
- spi-cpha: See Documentation/devicetree/bindings/spi/spi-bus.txt
- avcc-supply: phandle to the Avcc power supply
- interrupts: IRQ line for the ADC
see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- adi,conversion-start-gpios: must be the device tree identifier of the CONVST pin.
This logic input is used to initiate conversions on the analog
input channels. As the line is active high, it should be marked
GPIO_ACTIVE_HIGH.
Optional properties:
- reset-gpios: must be the device tree identifier of the RESET pin. If specified,
it will be asserted during driver probe. As the line is active high,
it should be marked GPIO_ACTIVE_HIGH.
- standby-gpios: must be the device tree identifier of the STBY pin. This pin is used
to place the AD7606 into one of two power-down modes, Standby mode or
Shutdown mode. As the line is active low, it should be marked
GPIO_ACTIVE_LOW.
- adi,first-data-gpios: must be the device tree identifier of the FRSTDATA pin.
The FRSTDATA output indicates when the first channel, V1, is
being read back on either the parallel, byte or serial interface.
As the line is active high, it should be marked GPIO_ACTIVE_HIGH.
- adi,range-gpios: must be the device tree identifier of the RANGE pin. The polarity on
this pin determines the input range of the analog input channels. If
this pin is tied to a logic high, the analog input range is ±10V for
all channels. If this pin is tied to a logic low, the analog input range
is ±5V for all channels. As the line is active high, it should be marked
GPIO_ACTIVE_HIGH.
- adi,oversampling-ratio-gpios: must be the device tree identifier of the over-sampling
mode pins. As the line is active high, it should be marked
GPIO_ACTIVE_HIGH.
Example:
adc@0 {
compatible = "adi,ad7606-8";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
avcc-supply = <&adc_vref>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH
&gpio 23 GPIO_ACTIVE_HIGH
&gpio 26 GPIO_ACTIVE_HIGH>;
standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/adi,ad7606.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD7606 Simultaneous Sampling ADC
maintainers:
- Beniamin Bia <beniamin.bia@analog.com>
- Stefan Popa <stefan.popa@analog.com>
description: |
Analog Devices AD7606 Simultaneous Sampling ADC
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7606B.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf
properties:
compatible:
enum:
- adi,ad7605-4
- adi,ad7606-8
- adi,ad7606-6
- adi,ad7606-4
- adi,ad7606b
- adi,ad7616
reg:
maxItems: 1
spi-cpha: true
avcc-supply:
description:
Phandle to the Avcc power supply
maxItems: 1
interrupts:
maxItems: 1
adi,conversion-start-gpios:
description:
Must be the device tree identifier of the CONVST pin.
This logic input is used to initiate conversions on the analog
input channels. As the line is active high, it should be marked
GPIO_ACTIVE_HIGH.
maxItems: 1
reset-gpios:
description:
Must be the device tree identifier of the RESET pin. If specified,
it will be asserted during driver probe. As the line is active high,
it should be marked GPIO_ACTIVE_HIGH.
maxItems: 1
standby-gpios:
description:
Must be the device tree identifier of the STBY pin. This pin is used
to place the AD7606 into one of two power-down modes, Standby mode or
Shutdown mode. As the line is active low, it should be marked
GPIO_ACTIVE_LOW.
maxItems: 1
adi,first-data-gpios:
description:
Must be the device tree identifier of the FRSTDATA pin.
The FRSTDATA output indicates when the first channel, V1, is
being read back on either the parallel, byte or serial interface.
As the line is active high, it should be marked GPIO_ACTIVE_HIGH.
maxItems: 1
adi,range-gpios:
description:
Must be the device tree identifier of the RANGE pin. The polarity on
this pin determines the input range of the analog input channels. If
this pin is tied to a logic high, the analog input range is ±10V for
all channels. If this pin is tied to a logic low, the analog input range
is ±5V for all channels. As the line is active high, it should be marked
GPIO_ACTIVE_HIGH.
maxItems: 1
adi,oversampling-ratio-gpios:
description:
Must be the device tree identifier of the over-sampling
mode pins. As the line is active high, it should be marked
GPIO_ACTIVE_HIGH.
maxItems: 1
adi,sw-mode:
description:
Software mode of operation, so far available only for ad7616 and ad7606b.
It is enabled when all three oversampling mode pins are connected to
high level. The device is configured by the corresponding registers. If the
adi,oversampling-ratio-gpios property is defined, then the driver will set the
oversampling gpios to high. Otherwise, it is assumed that the pins are hardwired
to VDD.
type: boolean
required:
- compatible
- reg
- spi-cpha
- avcc-supply
- interrupts
- adi,conversion-start-gpios
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,ad7606-8";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
spi-cpha;
avcc-supply = <&adc_vref>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH
&gpio 23 GPIO_ACTIVE_HIGH
&gpio 26 GPIO_ACTIVE_HIGH>;
standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
adi,sw-mode;
};
};
...
......@@ -13,6 +13,7 @@ Required properties:
"st,lsm6dsr"
"st,lsm6ds3tr-c"
"st,ism330dhcx"
"st,lsm9ds1-imu"
- reg: i2c address of the sensor / spi cs line
Optional properties:
......
......@@ -903,11 +903,12 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml
ANALOG DEVICES INC AD7606 DRIVER
M: Stefan Popa <stefan.popa@analog.com>
M: Beniamin Bia <beniamin.bia@analog.com>
L: linux-iio@vger.kernel.org
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: drivers/iio/adc/ad7606.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt
F: Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
ANALOG DEVICES INC AD7768-1 DRIVER
M: Stefan Popa <stefan.popa@analog.com>
......@@ -6341,7 +6342,7 @@ FLEXTIMER FTM-QUADDEC DRIVER
M: Patrick Havelange <patrick.havelange@essensium.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-counter-ftm-quadddec
F: Documentation/ABI/testing/sysfs-bus-counter-ftm-quaddec
F: Documentation/devicetree/bindings/counter/ftm-quaddec.txt
F: drivers/counter/ftm-quaddec.c
......
......@@ -1486,8 +1486,8 @@ static const struct acpi_device_id kx_acpi_match[] = {
{"KIOX0008", KXCJ91008},
{"KIOX0009", KXTJ21009},
{"KIOX000A", KXCJ91008},
{"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */
{"KIOX020A", KXCJ91008},
{"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */
{"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */
{"KXTJ1009", KXTJ21009},
{"KXJ2109", KXTJ21009},
{"SMO8500", KXCJ91008},
......
......@@ -410,12 +410,19 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
},
[ID_AD7606B] = {
.channels = ad7606_channels,
.num_channels = 9,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
},
[ID_AD7616] = {
.channels = ad7616_channels,
.num_channels = 17,
.oversampling_avail = ad7616_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
.os_req_reset = true,
.init_delay_ms = 15,
},
};
......@@ -631,8 +638,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");
/* AD7616 requires al least 15ms to reconfigure after a reset */
if (msleep_interruptible(15))
if (st->chip_info->init_delay_ms) {
if (msleep_interruptible(st->chip_info->init_delay_ms))
return -ERESTARTSYS;
}
st->write_scale = ad7606_write_scale_hw;
st->write_os = ad7606_write_os_hw;
......
......@@ -46,6 +46,8 @@
* oversampling ratios.
* @oversampling_num number of elements stored in oversampling_avail array
* @os_req_reset some devices require a reset to update oversampling
* @init_delay_ms required delay in miliseconds for initialization
* after a restart
*/
struct ad7606_chip_info {
const struct iio_chan_spec *channels;
......@@ -53,6 +55,7 @@ struct ad7606_chip_info {
const unsigned int *oversampling_avail;
unsigned int oversampling_num;
bool os_req_reset;
unsigned long init_delay_ms;
};
/**
......@@ -155,6 +158,7 @@ enum ad7606_supported_device_ids {
ID_AD7606_8,
ID_AD7606_6,
ID_AD7606_4,
ID_AD7606B,
ID_AD7616,
};
......
......@@ -28,9 +28,23 @@
* an offset of 2 for register address.
*/
#define AD7616_RANGE_CH_ADDR(ch) ((ch) >> 2)
/* The range of the channel is stored on 2 bits*/
/* The range of the channel is stored in 2 bits */
#define AD7616_RANGE_CH_MSK(ch) (0b11 << (((ch) & 0b11) * 2))
#define AD7616_RANGE_CH_MODE(ch, mode) ((mode) << ((((ch) & 0b11)) * 2))
#define AD7606_CONFIGURATION_REGISTER 0x02
#define AD7606_SINGLE_DOUT 0x00
/*
* Range for AD7606B channels are stored in registers starting with address 0x3.
* Each register stores range for 2 channels(4 bits per channel).
*/
#define AD7606_RANGE_CH_MSK(ch) (GENMASK(3, 0) << (4 * ((ch) & 0x1)))
#define AD7606_RANGE_CH_MODE(ch, mode) \
((GENMASK(3, 0) & mode) << (4 * ((ch) & 0x1)))
#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1))
#define AD7606_OS_MODE 0x08
static const struct iio_chan_spec ad7616_sw_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(16),
AD7616_CHANNEL(0),
......@@ -51,6 +65,22 @@ static const struct iio_chan_spec ad7616_sw_channels[] = {
AD7616_CHANNEL(15),
};
static const struct iio_chan_spec ad7606b_sw_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(8),
AD7616_CHANNEL(0),
AD7616_CHANNEL(1),
AD7616_CHANNEL(2),
AD7616_CHANNEL(3),
AD7616_CHANNEL(4),
AD7616_CHANNEL(5),
AD7616_CHANNEL(6),
AD7616_CHANNEL(7),
};
static const unsigned int ad7606B_oversampling_avail[9] = {
1, 2, 4, 8, 16, 32, 64, 128, 256
};
static u16 ad7616_spi_rd_wr_cmd(int addr, char isWriteOp)
{
/*
......@@ -60,6 +90,16 @@ static u16 ad7616_spi_rd_wr_cmd(int addr, char isWriteOp)
return ((addr & 0x7F) << 1) | ((isWriteOp & 0x1) << 7);
}
static u16 ad7606B_spi_rd_wr_cmd(int addr, char is_write_op)
{
/*
* The address of register consists of one bit which
* specifies a read command placed in bit 6, followed by
* 6 bits of address.
*/
return (addr & 0x3F) | (((~is_write_op) & 0x1) << 6);
}
static int ad7606_spi_read_block(struct device *dev,
int count, void *buf)
{
......@@ -169,6 +209,23 @@ static int ad7616_write_os_sw(struct iio_dev *indio_dev, int val)
AD7616_OS_MASK, val << 2);
}
static int ad7606_write_scale_sw(struct iio_dev *indio_dev, int ch, int val)
{
struct ad7606_state *st = iio_priv(indio_dev);
return ad7606_spi_write_mask(st,
AD7606_RANGE_CH_ADDR(ch),
AD7606_RANGE_CH_MSK(ch),
AD7606_RANGE_CH_MODE(ch, val));
}
static int ad7606_write_os_sw(struct iio_dev *indio_dev, int val)
{
struct ad7606_state *st = iio_priv(indio_dev);
return ad7606_spi_reg_write(st, AD7606_OS_MODE, val);
}
static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
......@@ -189,6 +246,42 @@ static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
AD7616_BURST_MODE | AD7616_SEQEN_MODE);
}
static int ad7606B_sw_mode_config(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
unsigned long os[3] = {1};
/*
* Software mode is enabled when all three oversampling
* pins are set to high. If oversampling gpios are defined
* in the device tree, then they need to be set to high,
* otherwise, they must be hardwired to VDD
*/
if (st->gpio_os) {
gpiod_set_array_value(ARRAY_SIZE(os),
st->gpio_os->desc, st->gpio_os->info, os);
}
/* OS of 128 and 256 are available only in software mode */
st->oversampling_avail = ad7606B_oversampling_avail;
st->num_os_ratios = ARRAY_SIZE(ad7606B_oversampling_avail);
st->write_scale = ad7606_write_scale_sw;
st->write_os = &ad7606_write_os_sw;
/* Configure device spi to output on a single channel */
st->bops->reg_write(st,
AD7606_CONFIGURATION_REGISTER,
AD7606_SINGLE_DOUT);
/*
* Scale can be configured individually for each channel
* in software mode.
*/
indio_dev->channels = ad7606b_sw_channels;
return 0;
}
static const struct ad7606_bus_ops ad7606_spi_bops = {
.read_block = ad7606_spi_read_block,
};
......@@ -202,6 +295,15 @@ static const struct ad7606_bus_ops ad7616_spi_bops = {
.sw_mode_config = ad7616_sw_mode_config,
};
static const struct ad7606_bus_ops ad7606B_spi_bops = {
.read_block = ad7606_spi_read_block,
.reg_read = ad7606_spi_reg_read,
.reg_write = ad7606_spi_reg_write,
.write_mask = ad7606_spi_write_mask,
.rd_wr_cmd = ad7606B_spi_rd_wr_cmd,
.sw_mode_config = ad7606B_sw_mode_config,
};
static int ad7606_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
......@@ -211,6 +313,9 @@ static int ad7606_spi_probe(struct spi_device *spi)
case ID_AD7616:
bops = &ad7616_spi_bops;
break;
case ID_AD7606B:
bops = &ad7606B_spi_bops;
break;
default:
bops = &ad7606_spi_bops;
break;
......@@ -226,6 +331,7 @@ static const struct spi_device_id ad7606_id_table[] = {
{ "ad7606-4", ID_AD7606_4 },
{ "ad7606-6", ID_AD7606_6 },
{ "ad7606-8", ID_AD7606_8 },
{ "ad7606b", ID_AD7606B },
{ "ad7616", ID_AD7616 },
{}
};
......@@ -236,6 +342,7 @@ static const struct of_device_id ad7606_of_match[] = {
{ .compatible = "adi,ad7606-4" },
{ .compatible = "adi,ad7606-6" },
{ .compatible = "adi,ad7606-8" },
{ .compatible = "adi,ad7606b" },
{ .compatible = "adi,ad7616" },
{ },
};
......
......@@ -427,7 +427,8 @@ static int max1027_probe(struct spi_device *spi)
return -ENOMEM;
}
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
&iio_pollfunc_store_time,
&max1027_trigger_handler, NULL);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to setup buffer\n");
......@@ -439,7 +440,7 @@ static int max1027_probe(struct spi_device *spi)
if (st->trig == NULL) {
ret = -ENOMEM;
dev_err(&indio_dev->dev, "Failed to allocate iio trigger\n");
goto fail_trigger_alloc;
return ret;
}
st->trig->ops = &max1027_trigger_ops;
......@@ -454,7 +455,7 @@ static int max1027_probe(struct spi_device *spi)
spi->dev.driver->name, st->trig);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n");
goto fail_dev_register;
return ret;
}
/* Disable averaging */
......@@ -462,34 +463,10 @@ static int max1027_probe(struct spi_device *spi)
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to configure averaging register\n");
goto fail_dev_register;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to register iio device\n");
goto fail_dev_register;
}
return 0;
fail_dev_register:
fail_trigger_alloc:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int max1027_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
pr_debug("%s: remove(spi = 0x%p)\n", __func__, spi);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
}
return 0;
return devm_iio_device_register(&spi->dev, indio_dev);
}
static struct spi_driver max1027_driver = {
......@@ -498,7 +475,6 @@ static struct spi_driver max1027_driver = {
.of_match_table = of_match_ptr(max1027_adc_dt_ids),
},
.probe = max1027_probe,
.remove = max1027_remove,
.id_table = max1027_id,
};
module_spi_driver(max1027_driver);
......
......@@ -3,7 +3,6 @@
#include <linux/hwspinlock.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
......@@ -46,14 +45,18 @@
/* Bits definitions for SC27XX_ADC_INT_CLR registers */
#define SC27XX_ADC_IRQ_CLR BIT(0)
/* Bits definitions for SC27XX_ADC_INT_RAW registers */
#define SC27XX_ADC_IRQ_RAW BIT(0)
/* Mask definition for SC27XX_ADC_DATA register */
#define SC27XX_ADC_DATA_MASK GENMASK(11, 0)
/* Timeout (ms) for the trylock of hardware spinlocks */
#define SC27XX_ADC_HWLOCK_TIMEOUT 5000
/* Timeout (ms) for ADC data conversion according to ADC datasheet */
#define SC27XX_ADC_RDY_TIMEOUT 100
/* Timeout (us) for ADC data conversion according to ADC datasheet */
#define SC27XX_ADC_RDY_TIMEOUT 1000000
#define SC27XX_ADC_POLL_RAW_STATUS 500
/* Maximum ADC channel number */
#define SC27XX_ADC_CHANNEL_MAX 32
......@@ -72,10 +75,8 @@ struct sc27xx_adc_data {
* subsystems which will access the unique ADC controller.
*/
struct hwspinlock *hwlock;
struct completion completion;
int channel_scale[SC27XX_ADC_CHANNEL_MAX];
u32 base;
int value;
int irq;
};
......@@ -188,9 +189,7 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
int scale, int *val)
{
int ret;
u32 tmp;
reinit_completion(&data->completion);
u32 tmp, value, status;
ret = hwspin_lock_timeout_raw(data->hwlock, SC27XX_ADC_HWLOCK_TIMEOUT);
if (ret) {
......@@ -203,6 +202,11 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
if (ret)
goto unlock_adc;
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR,
SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR);
if (ret)
goto disable_adc;
/* Configure the channel id and scale */
tmp = (scale << SC27XX_ADC_SCALE_SHIFT) & SC27XX_ADC_SCALE_MASK;
tmp |= channel & SC27XX_ADC_CHN_ID_MASK;
......@@ -226,15 +230,22 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
if (ret)
goto disable_adc;
ret = wait_for_completion_timeout(&data->completion,
msecs_to_jiffies(SC27XX_ADC_RDY_TIMEOUT));
if (!ret) {
dev_err(data->dev, "read ADC data timeout\n");
ret = -ETIMEDOUT;
} else {
ret = 0;
ret = regmap_read_poll_timeout(data->regmap,
data->base + SC27XX_ADC_INT_RAW,
status, (status & SC27XX_ADC_IRQ_RAW),
SC27XX_ADC_POLL_RAW_STATUS,
SC27XX_ADC_RDY_TIMEOUT);
if (ret) {
dev_err(data->dev, "read adc timeout, status = 0x%x\n", status);
goto disable_adc;
}
ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA, &value);
if (ret)
goto disable_adc;
value &= SC27XX_ADC_DATA_MASK;
disable_adc:
regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
SC27XX_ADC_EN, 0);
......@@ -242,32 +253,11 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
hwspin_unlock_raw(data->hwlock);
if (!ret)
*val = data->value;
*val = value;
return ret;
}
static irqreturn_t sc27xx_adc_isr(int irq, void *dev_id)
{
struct sc27xx_adc_data *data = dev_id;
int ret;
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR,
SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR);
if (ret)
return IRQ_RETVAL(ret);
ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA,
&data->value);
if (ret)
return IRQ_RETVAL(ret);
data->value &= SC27XX_ADC_DATA_MASK;
complete(&data->completion);
return IRQ_HANDLED;
}
static void sc27xx_adc_volt_ratio(struct sc27xx_adc_data *data,
int channel, int scale,
u32 *div_numerator, u32 *div_denominator)
......@@ -454,11 +444,6 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
if (ret)
goto disable_adc;
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN,
SC27XX_ADC_IRQ_EN, SC27XX_ADC_IRQ_EN);
if (ret)
goto disable_clk;
/* ADC channel scales' calibration from nvmem device */
ret = sc27xx_adc_scale_calibration(data, true);
if (ret)
......@@ -484,9 +469,6 @@ static void sc27xx_adc_disable(void *_data)
{
struct sc27xx_adc_data *data = _data;
regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN,
SC27XX_ADC_IRQ_EN, 0);
/* Disable ADC work clock and controller clock */
regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0);
......@@ -551,7 +533,6 @@ static int sc27xx_adc_probe(struct platform_device *pdev)
return ret;
}
init_completion(&sc27xx_data->completion);
sc27xx_data->dev = dev;
ret = sc27xx_adc_enable(sc27xx_data);
......@@ -566,14 +547,6 @@ static int sc27xx_adc_probe(struct platform_device *pdev)
return ret;
}
ret = devm_request_threaded_irq(dev, sc27xx_data->irq, NULL,
sc27xx_adc_isr, IRQF_ONESHOT,
pdev->name, sc27xx_data);
if (ret) {
dev_err(dev, "failed to request ADC irq\n");
return ret;
}
indio_dev->dev.parent = dev;
indio_dev->name = dev_name(dev);
indio_dev->modes = INDIO_DIRECT_MODE;
......
......@@ -90,7 +90,7 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent);
struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev);
u32 ver_mask;
int ret;
int ret, i;
platform_set_drvdata(pdev, indio_dev);
......@@ -136,6 +136,9 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
/* Set sign vector, only used for backward compatibility. */
memset(state->sign, 1, CROS_EC_SENSOR_MAX_AXIS);
for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
state->calib[i].scale = MOTION_SENSE_DEFAULT_SCALE;
/* 0 is a correct value used to stop the device */
state->frequencies[0] = 0;
if (state->msg->version < 3) {
......
......@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
......@@ -68,16 +69,6 @@ static struct {
{HID_USAGE_SENSOR_HUMIDITY, 0, 1000, 0},
};
static int pow_10(unsigned power)
{
int i;
int ret = 1;
for (i = 0; i < power; ++i)
ret = ret * 10;
return ret;
}
static void simple_div(int dividend, int divisor, int *whole,
int *micro_frac)
{
......@@ -96,14 +87,14 @@ static void simple_div(int dividend, int divisor, int *whole,
rem *= 10;
exp++;
}
*micro_frac = (rem / divisor) * pow_10(6-exp);
*micro_frac = (rem / divisor) * int_pow(10, 6 - exp);
}
}
static void split_micro_fraction(unsigned int no, int exp, int *val1, int *val2)
{
*val1 = no/pow_10(exp);
*val2 = no%pow_10(exp) * pow_10(6-exp);
*val1 = no / int_pow(10, exp);
*val2 = no % int_pow(10, exp) * int_pow(10, 6 - exp);
}
/*
......@@ -125,7 +116,7 @@ static void convert_from_vtf_format(u32 value, int size, int exp,
}
exp = hid_sensor_convert_exponent(exp);
if (exp >= 0) {
*val1 = sign * value * pow_10(exp);
*val1 = sign * value * int_pow(10, exp);
*val2 = 0;
} else {
split_micro_fraction(value, -exp, val1, val2);
......@@ -145,10 +136,10 @@ static u32 convert_to_vtf_format(int size, int exp, int val1, int val2)
sign = -1;
exp = hid_sensor_convert_exponent(exp);
if (exp < 0) {
value = abs(val1) * pow_10(-exp);
value += abs(val2) / pow_10(6+exp);
value = abs(val1) * int_pow(10, -exp);
value += abs(val2) / int_pow(10, 6 + exp);
} else
value = abs(val1) / pow_10(exp);
value = abs(val1) / int_pow(10, exp);
if (sign < 0)
value = ((1LL << (size * 8)) - value);
......@@ -211,12 +202,12 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
if (val1 < 0 || val2 < 0)
return -EINVAL;
value = val1 * pow_10(6) + val2;
value = val1 * int_pow(10, 6) + val2;
if (value) {
if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
value = pow_10(9)/value;
value = int_pow(10, 9) / value;
else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
value = pow_10(6)/value;
value = int_pow(10, 6) / value;
else
value = 0;
}
......@@ -311,34 +302,34 @@ static void adjust_exponent_nano(int *val0, int *val1, int scale0,
int rem;
if (exp > 0) {
*val0 = scale0 * pow_10(exp);
*val0 = scale0 * int_pow(10, exp);
res = 0;
if (exp > 9) {
*val1 = 0;
return;
}
for (i = 0; i < exp; ++i) {
x = scale1 / pow_10(8 - i);
res += (pow_10(exp - 1 - i) * x);
scale1 = scale1 % pow_10(8 - i);
x = scale1 / int_pow(10, 8 - i);
res += int_pow(10, exp - 1 - i) * x;
scale1 = scale1 % int_pow(10, 8 - i);
}
*val0 += res;
*val1 = scale1 * pow_10(exp);
*val1 = scale1 * int_pow(10, exp);
} else if (exp < 0) {
exp = abs(exp);
if (exp > 9) {
*val0 = *val1 = 0;
return;
}
*val0 = scale0 / pow_10(exp);
rem = scale0 % pow_10(exp);
*val0 = scale0 / int_pow(10, exp);
rem = scale0 % int_pow(10, exp);
res = 0;
for (i = 0; i < (9 - exp); ++i) {
x = scale1 / pow_10(8 - i);
res += (pow_10(8 - exp - i) * x);
scale1 = scale1 % pow_10(8 - i);
x = scale1 / int_pow(10, 8 - i);
res += int_pow(10, 8 - exp - i) * x;
scale1 = scale1 % int_pow(10, 8 - i);
}
*val1 = rem * pow_10(9 - exp) + res;
*val1 = rem * int_pow(10, 9 - exp) + res;
} else {
*val0 = scale0;
*val1 = scale1;
......
......@@ -5,9 +5,11 @@
config IIO_ST_SENSORS_I2C
tristate
select REGMAP_I2C
config IIO_ST_SENSORS_SPI
tristate
select REGMAP_SPI
config IIO_ST_SENSORS_CORE
tristate
......
......@@ -220,7 +220,7 @@ static int ad5380_read_raw(struct iio_dev *indio_dev,
if (ret)
return ret;
*val >>= chan->scan_type.shift;
val -= (1 << chan->scan_type.realbits) / 2;
*val -= (1 << chan->scan_type.realbits) / 2;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 2 * st->vref;
......
......@@ -152,7 +152,7 @@ static int adis16460_debugfs_init(struct iio_dev *indio_dev)
static int adis16460_set_freq(struct iio_dev *indio_dev, int val, int val2)
{
struct adis16460 *st = iio_priv(indio_dev);
unsigned int t;
int t;
t = val * 1000 + val2 / 1000;
if (t <= 0)
......
......@@ -12,7 +12,7 @@ config IIO_ST_LSM6DSX
Say yes here to build support for STMicroelectronics LSM6DSx imu
sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr, lsm6ds3tr-c,
ism330dhcx
ism330dhcx and the accelerometer/gyroscope of lsm9ds1.
To compile this driver as a module, choose M here: the module
will be called st_lsm6dsx.
......
......@@ -24,6 +24,7 @@
#define ST_LSM6DSR_DEV_NAME "lsm6dsr"
#define ST_LSM6DS3TRC_DEV_NAME "lsm6ds3tr-c"
#define ST_ISM330DHCX_DEV_NAME "ism330dhcx"
#define ST_LSM9DS1_DEV_NAME "lsm9ds1-imu"
enum st_lsm6dsx_hw_id {
ST_LSM6DS3_ID,
......@@ -37,6 +38,7 @@ enum st_lsm6dsx_hw_id {
ST_LSM6DSR_ID,
ST_LSM6DS3TRC_ID,
ST_ISM330DHCX_ID,
ST_LSM9DS1_ID,
ST_LSM6DSX_MAX_ID,
};
......@@ -75,6 +77,7 @@ struct st_lsm6dsx_reg {
u8 mask;
};
struct st_lsm6dsx_sensor;
struct st_lsm6dsx_hw;
struct st_lsm6dsx_odr {
......@@ -101,12 +104,14 @@ struct st_lsm6dsx_fs_table_entry {
/**
* struct st_lsm6dsx_fifo_ops - ST IMU FIFO settings
* @update_fifo: Update FIFO configuration callback.
* @read_fifo: Read FIFO callback.
* @fifo_th: FIFO threshold register info (addr + mask).
* @fifo_diff: FIFO diff status register info (addr + mask).
* @th_wl: FIFO threshold word length.
*/
struct st_lsm6dsx_fifo_ops {
int (*update_fifo)(struct st_lsm6dsx_sensor *sensor, bool enable);
int (*read_fifo)(struct st_lsm6dsx_hw *hw);
struct {
u8 addr;
......@@ -200,6 +205,9 @@ struct st_lsm6dsx_ext_dev_settings {
/**
* struct st_lsm6dsx_settings - ST IMU sensor settings
* @wai: Sensor WhoAmI default value.
* @int1_addr: Control Register address for INT1
* @int2_addr: Control Register address for INT2
* @reset_addr: register address for reset/reboot
* @max_fifo_size: Sensor max fifo length in FIFO words.
* @id: List of hw id/device name supported by the driver configuration.
* @channels: IIO channels supported by the device.
......@@ -213,6 +221,9 @@ struct st_lsm6dsx_ext_dev_settings {
*/
struct st_lsm6dsx_settings {
u8 wai;
u8 int1_addr;
u8 int2_addr;
u8 reset_addr;
u16 max_fifo_size;
struct {
enum st_lsm6dsx_hw_id hw_id;
......@@ -327,6 +338,7 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val);
int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
u16 watermark);
int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable);
int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
enum st_lsm6dsx_fifo_mode fifo_mode);
......
......@@ -602,9 +602,8 @@ int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
return err;
}
static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable)
{
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
struct st_lsm6dsx_hw *hw = sensor->hw;
int err;
......@@ -676,12 +675,24 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
static int st_lsm6dsx_buffer_preenable(struct iio_dev *iio_dev)
{
return st_lsm6dsx_update_fifo(iio_dev, true);
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
struct st_lsm6dsx_hw *hw = sensor->hw;
if (!hw->settings->fifo_ops.update_fifo)
return -ENOTSUPP;
return hw->settings->fifo_ops.update_fifo(sensor, true);
}
static int st_lsm6dsx_buffer_postdisable(struct iio_dev *iio_dev)
{
return st_lsm6dsx_update_fifo(iio_dev, false);
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
struct st_lsm6dsx_hw *hw = sensor->hw;
if (!hw->settings->fifo_ops.update_fifo)
return -ENOTSUPP;
return hw->settings->fifo_ops.update_fifo(sensor, false);
}
static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = {
......
......@@ -10,6 +10,8 @@
* +-125/+-245/+-500/+-1000/+-2000 dps
* LSM6DSx series has an integrated First-In-First-Out (FIFO) buffer
* allowing dynamic batching of sensor data.
* LSM9DSx series is similar but includes an additional magnetometer, handled
* by a different driver.
*
* Supported sensors:
* - LSM6DS3:
......@@ -30,6 +32,13 @@
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 3KB
*
* - LSM9DS1:
* - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952
* - Gyroscope supported full-scale [dps]: +-245/+-500/+-2000
* - FIFO size: 32
*
* Copyright 2016 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi@st.com>
......@@ -49,17 +58,12 @@
#include "st_lsm6dsx.h"
#define ST_LSM6DSX_REG_INT1_ADDR 0x0d
#define ST_LSM6DSX_REG_INT2_ADDR 0x0e
#define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3)
#define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f
#define ST_LSM6DSX_REG_RESET_ADDR 0x12
#define ST_LSM6DSX_REG_RESET_MASK BIT(0)
#define ST_LSM6DSX_REG_BOOT_MASK BIT(7)
#define ST_LSM6DSX_REG_BDU_ADDR 0x12
#define ST_LSM6DSX_REG_BDU_MASK BIT(6)
#define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR 0x13
#define ST_LSM6DSX_REG_INT2_ON_INT1_MASK BIT(5)
static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x28, IIO_MOD_X, 0),
......@@ -75,9 +79,89 @@ static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(3),
};
static const struct iio_chan_spec st_lsm6ds0_gyro_channels[] = {
ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x18, IIO_MOD_X, 0),
ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x1a, IIO_MOD_Y, 1),
ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x1c, IIO_MOD_Z, 2),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
{
.wai = 0x68,
.int1_addr = 0x0c,
.int2_addr = 0x0d,
.reset_addr = 0x22,
.max_fifo_size = 32,
.id = {
{
.hw_id = ST_LSM9DS1_ID,
.name = ST_LSM9DS1_DEV_NAME,
},
},
.channels = {
[ST_LSM6DSX_ID_ACC] = {
.chan = st_lsm6dsx_acc_channels,
.len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
},
[ST_LSM6DSX_ID_GYRO] = {
.chan = st_lsm6ds0_gyro_channels,
.len = ARRAY_SIZE(st_lsm6ds0_gyro_channels),
},
},
.odr_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x20,
.mask = GENMASK(7, 5),
},
.odr_avl[0] = { 10, 0x01 },
.odr_avl[1] = { 50, 0x02 },
.odr_avl[2] = { 119, 0x03 },
.odr_avl[3] = { 238, 0x04 },
.odr_avl[4] = { 476, 0x05 },
.odr_avl[5] = { 952, 0x06 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(7, 5),
},
.odr_avl[0] = { 15, 0x01 },
.odr_avl[1] = { 60, 0x02 },
.odr_avl[2] = { 119, 0x03 },
.odr_avl[3] = { 238, 0x04 },
.odr_avl[4] = { 476, 0x05 },
.odr_avl[5] = { 952, 0x06 },
},
},
.fs_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x20,
.mask = GENMASK(4, 3),
},
.fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 },
.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
.fs_avl[3] = { IIO_G_TO_M_S_2(732), 0x1 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(4, 3),
},
.fs_avl[0] = { IIO_DEGREE_TO_RAD(245), 0x0 },
.fs_avl[1] = { IIO_DEGREE_TO_RAD(500), 0x1 },
.fs_avl[2] = { IIO_DEGREE_TO_RAD(2000), 0x3 },
},
},
},
{
.wai = 0x69,
.int1_addr = 0x0d,
.int2_addr = 0x0e,
.reset_addr = 0x12,
.max_fifo_size = 1365,
.id = {
{
......@@ -154,6 +238,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
.update_fifo = st_lsm6dsx_update_fifo,
.read_fifo = st_lsm6dsx_read_fifo,
.fifo_th = {
.addr = 0x06,
......@@ -186,6 +271,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
{
.wai = 0x69,
.int1_addr = 0x0d,
.int2_addr = 0x0e,
.reset_addr = 0x12,
.max_fifo_size = 682,
.id = {
{
......@@ -262,6 +350,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
.update_fifo = st_lsm6dsx_update_fifo,
.read_fifo = st_lsm6dsx_read_fifo,
.fifo_th = {
.addr = 0x06,
......@@ -294,6 +383,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
{
.wai = 0x6a,
.int1_addr = 0x0d,
.int2_addr = 0x0e,
.reset_addr = 0x12,
.max_fifo_size = 682,
.id = {
{
......@@ -379,6 +471,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
.update_fifo = st_lsm6dsx_update_fifo,
.read_fifo = st_lsm6dsx_read_fifo,
.fifo_th = {
.addr = 0x06,
......@@ -411,6 +504,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
{
.wai = 0x6c,
.int1_addr = 0x0d,
.int2_addr = 0x0e,
.reset_addr = 0x12,
.max_fifo_size = 512,
.id = {
{
......@@ -490,6 +586,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
.update_fifo = st_lsm6dsx_update_fifo,
.read_fifo = st_lsm6dsx_read_tagged_fifo,
.fifo_th = {
.addr = 0x07,
......@@ -497,7 +594,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
.fifo_diff = {
.addr = 0x3a,
.mask = GENMASK(8, 0),
.mask = GENMASK(9, 0),
},
.th_wl = 1,
},
......@@ -540,6 +637,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
{
.wai = 0x6b,
.int1_addr = 0x0d,
.int2_addr = 0x0e,
.reset_addr = 0x12,
.max_fifo_size = 512,
.id = {
{
......@@ -616,6 +716,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
.update_fifo = st_lsm6dsx_update_fifo,
.read_fifo = st_lsm6dsx_read_tagged_fifo,
.fifo_th = {
.addr = 0x07,
......@@ -623,7 +724,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
.fifo_diff = {
.addr = 0x3a,
.mask = GENMASK(8, 0),
.mask = GENMASK(9, 0),
},
.th_wl = 1,
},
......@@ -640,6 +741,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
{
.wai = 0x6b,
.int1_addr = 0x0d,
.int2_addr = 0x0e,
.reset_addr = 0x12,
.max_fifo_size = 512,
.id = {
{
......@@ -719,6 +823,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
.update_fifo = st_lsm6dsx_update_fifo,
.read_fifo = st_lsm6dsx_read_tagged_fifo,
.fifo_th = {
.addr = 0x07,
......@@ -726,7 +831,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
.fifo_diff = {
.addr = 0x3a,
.mask = GENMASK(8, 0),
.mask = GENMASK(9, 0),
},
.th_wl = 1,
},
......@@ -1090,13 +1195,19 @@ static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev,
char *buf)
{
struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
const struct st_lsm6dsx_fs_table_entry *fs_table;
enum st_lsm6dsx_sensor_id id = sensor->id;
struct st_lsm6dsx_hw *hw = sensor->hw;
int i, len = 0;
for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
fs_table = &hw->settings->fs_table[id];
for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) {
if (!fs_table->fs_avl[i].gain)
break;
len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
hw->settings->fs_table[id].fs_avl[i].gain);
fs_table->fs_avl[i].gain);
}
buf[len - 1] = '\n';
return len;
......@@ -1166,10 +1277,10 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
switch (drdy_pin) {
case 1:
*drdy_reg = ST_LSM6DSX_REG_INT1_ADDR;
*drdy_reg = hw->settings->int1_addr;
break;
case 2:
*drdy_reg = ST_LSM6DSX_REG_INT2_ADDR;
*drdy_reg = hw->settings->int2_addr;
break;
default:
dev_err(hw->dev, "unsupported data ready pin\n");
......@@ -1269,7 +1380,7 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
int err;
/* device sw reset */
err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
err = regmap_update_bits(hw->regmap, hw->settings->reset_addr,
ST_LSM6DSX_REG_RESET_MASK,
FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1));
if (err < 0)
......@@ -1278,7 +1389,7 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
msleep(50);
/* reload trimming parameter */
err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
err = regmap_update_bits(hw->regmap, hw->settings->reset_addr,
ST_LSM6DSX_REG_BOOT_MASK,
FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1));
if (err < 0)
......
......@@ -83,6 +83,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
.compatible = "st,ism330dhcx",
.data = (void *)ST_ISM330DHCX_ID,
},
{
.compatible = "st,lsm9ds1-imu",
.data = (void *)ST_LSM9DS1_ID,
},
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
......@@ -99,6 +103,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID },
{ ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID },
{ ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID },
{ ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID },
{},
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
......
......@@ -83,6 +83,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
.compatible = "st,ism330dhcx",
.data = (void *)ST_ISM330DHCX_ID,
},
{
.compatible = "st,lsm9ds1-imu",
.data = (void *)ST_LSM9DS1_ID,
},
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
......@@ -99,6 +103,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID },
{ ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID },
{ ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID },
{ ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID },
{},
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
......
......@@ -62,7 +62,7 @@ config RFD77402
tristate "RFD77402 ToF sensor"
depends on I2C
help
Say Y to build a driver for the RFD77420 Time-of-Flight (distance)
Say Y to build a driver for the RFD77402 Time-of-Flight (distance)
sensor module with I2C interface.
To compile this driver as a module, choose M here: the
......
......@@ -309,15 +309,12 @@ static int adis16240_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct adis *st = iio_priv(indio_dev);
int bits = 10;
s16 val16;
u8 addr;
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
val16 = val & ((1 << bits) - 1);
addr = adis16240_addresses[chan->scan_index][0];
return adis_write_reg_16(st, addr, val16);
return adis_write_reg_16(st, addr, val & GENMASK(9, 0));
}
return -EINVAL;
}
......
......@@ -25,8 +25,6 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/adc/ad_sigma_delta.h>
#include "ad7192.h"
/* Registers */
#define AD7192_REG_COMM 0 /* Communications Register (WO, 8-bit) */
#define AD7192_REG_STAT 0 /* Status Register (RO, 8-bit) */
......@@ -145,6 +143,10 @@
#define AD7192_EXT_FREQ_MHZ_MAX 5120000
#define AD7192_INT_FREQ_MHZ 4915200
#define AD7192_NO_SYNC_FILTER 1
#define AD7192_SYNC3_FILTER 3
#define AD7192_SYNC4_FILTER 4
/* NOTE:
* The AD7190/2/5 features a dual use data out ready DOUT/RDY output.
* In order to avoid contentions on the SPI bus, it's therefore necessary
......@@ -252,7 +254,7 @@ static int ad7192_of_clock_select(struct ad7192_state *st)
static int ad7192_setup(struct ad7192_state *st, struct device_node *np)
{
struct iio_dev *indio_dev = spi_get_drvdata(st->sd.spi);
bool rej60_en, sinc3_en, refin2_en, chop_en;
bool rej60_en, refin2_en;
bool buf_en, bipolar, burnout_curr_en;
unsigned long long scale_uv;
int i, ret, id;
......@@ -284,24 +286,12 @@ static int ad7192_setup(struct ad7192_state *st, struct device_node *np)
if (rej60_en)
st->mode |= AD7192_MODE_REJ60;
sinc3_en = of_property_read_bool(np, "adi,sinc3-filter-enable");
if (sinc3_en)
st->mode |= AD7192_MODE_SINC3;
refin2_en = of_property_read_bool(np, "adi,refin2-pins-enable");
if (refin2_en && st->devid != ID_AD7195)
st->conf |= AD7192_CONF_REFSEL;
chop_en = of_property_read_bool(np, "adi,chop-enable");
if (chop_en) {
st->conf |= AD7192_CONF_CHOP;
if (sinc3_en)
st->f_order = 3; /* SINC 3rd order */
else
st->f_order = 4; /* SINC 4th order */
} else {
st->f_order = 1;
}
st->conf &= ~AD7192_CONF_CHOP;
st->f_order = AD7192_NO_SYNC_FILTER;
buf_en = of_property_read_bool(np, "adi,buffer-enable");
if (buf_en)
......@@ -313,7 +303,7 @@ static int ad7192_setup(struct ad7192_state *st, struct device_node *np)
burnout_curr_en = of_property_read_bool(np,
"adi,burnout-currents-enable");
if (burnout_curr_en && buf_en && !chop_en) {
if (burnout_curr_en && buf_en) {
st->conf |= AD7192_CONF_BURN;
} else if (burnout_curr_en) {
dev_warn(&st->sd.spi->dev,
......@@ -411,6 +401,49 @@ static ssize_t ad7192_set(struct device *dev,
return ret ? ret : len;
}
static void ad7192_get_available_filter_freq(struct ad7192_state *st,
int *freq)
{
unsigned int fadc;
/* Formulas for filter at page 25 of the datasheet */
fadc = DIV_ROUND_CLOSEST(st->fclk,
AD7192_SYNC4_FILTER * AD7192_MODE_RATE(st->mode));
freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
fadc = DIV_ROUND_CLOSEST(st->fclk,
AD7192_SYNC3_FILTER * AD7192_MODE_RATE(st->mode));
freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
fadc = DIV_ROUND_CLOSEST(st->fclk, AD7192_MODE_RATE(st->mode));
freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
}
static ssize_t ad7192_show_filter_avail(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);
unsigned int freq_avail[4], i;
size_t len = 0;
ad7192_get_available_filter_freq(st, freq_avail);
for (i = 0; i < ARRAY_SIZE(freq_avail); i++)
len += scnprintf(buf + len, PAGE_SIZE - len,
"%d.%d ", freq_avail[i] / 1000,
freq_avail[i] % 1000);
buf[len - 1] = '\n';
return len;
}
static IIO_DEVICE_ATTR(filter_low_pass_3db_frequency_available,
0444, ad7192_show_filter_avail, NULL, 0);
static IIO_DEVICE_ATTR(bridge_switch_en, 0644,
ad7192_show_bridge_switch, ad7192_set,
AD7192_REG_GPOCON);
......@@ -420,6 +453,7 @@ static IIO_DEVICE_ATTR(ac_excitation_en, 0644,
AD7192_REG_MODE);
static struct attribute *ad7192_attributes[] = {
&iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
&iio_dev_attr_ac_excitation_en.dev_attr.attr,
NULL
......@@ -430,6 +464,7 @@ static const struct attribute_group ad7192_attribute_group = {
};
static struct attribute *ad7195_attributes[] = {
&iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
NULL
};
......@@ -443,6 +478,75 @@ static unsigned int ad7192_get_temp_scale(bool unipolar)
return unipolar ? 2815 * 2 : 2815;
}
static int ad7192_set_3db_filter_freq(struct ad7192_state *st,
int val, int val2)
{
int freq_avail[4], i, ret, freq;
unsigned int diff_new, diff_old;
int idx = 0;
diff_old = U32_MAX;
freq = val * 1000 + val2;
ad7192_get_available_filter_freq(st, freq_avail);
for (i = 0; i < ARRAY_SIZE(freq_avail); i++) {
diff_new = abs(freq - freq_avail[i]);
if (diff_new < diff_old) {
diff_old = diff_new;
idx = i;
}
}
switch (idx) {
case 0:
st->f_order = AD7192_SYNC4_FILTER;
st->mode &= ~AD7192_MODE_SINC3;
st->conf |= AD7192_CONF_CHOP;
break;
case 1:
st->f_order = AD7192_SYNC3_FILTER;
st->mode |= AD7192_MODE_SINC3;
st->conf |= AD7192_CONF_CHOP;
break;
case 2:
st->f_order = AD7192_NO_SYNC_FILTER;
st->mode &= ~AD7192_MODE_SINC3;
st->conf &= ~AD7192_CONF_CHOP;
break;
case 3:
st->f_order = AD7192_NO_SYNC_FILTER;
st->mode |= AD7192_MODE_SINC3;
st->conf &= ~AD7192_CONF_CHOP;
break;
}
ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
if (ret < 0)
return ret;
return ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
}
static int ad7192_get_3db_filter_freq(struct ad7192_state *st)
{
unsigned int fadc;
fadc = DIV_ROUND_CLOSEST(st->fclk,
st->f_order * AD7192_MODE_RATE(st->mode));
if (st->conf & AD7192_CONF_CHOP)
return DIV_ROUND_CLOSEST(fadc * 240, 1024);
if (st->mode & AD7192_MODE_SINC3)
return DIV_ROUND_CLOSEST(fadc * 272, 1024);
else
return DIV_ROUND_CLOSEST(fadc * 230, 1024);
}
static int ad7192_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
......@@ -483,6 +587,10 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
*val = st->fclk /
(st->f_order * 1024 * AD7192_MODE_RATE(st->mode));
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*val = ad7192_get_3db_filter_freq(st);
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
}
return -EINVAL;
......@@ -537,6 +645,9 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
st->mode |= AD7192_MODE_RATE(div);
ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
break;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000);
break;
default:
ret = -EINVAL;
}
......@@ -555,6 +666,8 @@ static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
......@@ -655,6 +768,8 @@ static int ad7192_channels_config(struct iio_dev *indio_dev)
for (i = 0; i < indio_dev->num_channels; i++) {
*chan = channels[i];
chan->info_mask_shared_by_all |=
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY);
if (chan->type != IIO_TEMP)
chan->info_mask_shared_by_type_available |=
BIT(IIO_CHAN_INFO_SCALE);
......@@ -666,16 +781,10 @@ static int ad7192_channels_config(struct iio_dev *indio_dev)
static int ad7192_probe(struct spi_device *spi)
{
const struct ad7192_platform_data *pdata = dev_get_platdata(&spi->dev);
struct ad7192_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
if (!pdata) {
dev_err(&spi->dev, "no platform data?\n");
return -ENODEV;
}
if (!spi->irq) {
dev_err(&spi->dev, "no IRQ?\n");
return -ENODEV;
......@@ -713,12 +822,10 @@ static int ad7192_probe(struct spi_device *spi)
voltage_uv = regulator_get_voltage(st->avdd);
if (pdata->vref_mv)
st->int_vref_mv = pdata->vref_mv;
else if (voltage_uv)
if (voltage_uv)
st->int_vref_mv = voltage_uv / 1000;
else
dev_warn(&spi->dev, "reference voltage undefined\n");
dev_err(&spi->dev, "Device tree error, reference voltage undefined\n");
spi_set_drvdata(spi, indio_dev);
st->devid = spi_get_device_id(spi)->driver_data;
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* AD7190 AD7192 AD7195 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc.
*/
#ifndef IIO_ADC_AD7192_H_
#define IIO_ADC_AD7192_H_
/*
* TODO: struct ad7192_platform_data needs to go into include/linux/iio
*/
/**
* struct ad7192_platform_data - platform/board specific information
* @vref_mv: the external reference voltage in millivolt
* @clock_source_sel: [0..3]
* 0 External 4.92 MHz clock connected from MCLK1 to MCLK2
* 1 External Clock applied to MCLK2
* 2 Internal 4.92 MHz Clock not available at the MCLK2 pin
* 3 Internal 4.92 MHz Clock available at the MCLK2 pin
* @ext_clk_Hz: the external clock frequency in Hz, if not set
* the driver uses the internal clock (16.776 MHz)
* @refin2_en: REFIN1/REFIN2 Reference Select (AD7190/2 only)
* @rej60_en: 50/60Hz notch filter enable
* @sinc3_en: SINC3 filter enable (default SINC4)
* @chop_en: CHOP mode enable
* @buf_en: buffered input mode enable
* @unipolar_en: unipolar mode enable
* @burnout_curr_en: constant current generators on AIN(+|-) enable
*/
struct ad7192_platform_data {
u16 vref_mv;
};
#endif /* IIO_ADC_AD7192_H_ */
iio_event_monitor
iio_generic_buffer
lsiio
include/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment