IIO: 2nd set of new device support, features and cleanup for 6.10 (take 2)

The usual mixed bag from towards the end of the cycle.
 Changes since take 1. Fixed the fixes tag and indeed fixed a rebase I
 messed up on the same fix.
 
 New devices support
 ===================
 
 invensense,icm42600
 - Support the ICM-42686-P a high range device going up to 32g and 4000 dps
 
 New features
 ============
 
 adi,ad7944
 - Add support for chain mode in which many ADCs may be daisy chained and
   read out via a single long read.
 adi,ad9467/backend library
 - Add bus tuning related interfaces.
 adi,axi-adc
 - Add control for the AXI clock - seems always enabled early in boot for other
   reasons, but the driver should not rely on that..
 
 Cleanups and minor or late breaking fixes
 =========================================
 
 Micrsoft/ACPI mount matrix handling.
 - Replace several implementations of the Microsoft defined ROTM ACPI
   method with a single one.
 multiple drivers
 - Don't call the result of wait_for_completion() timeout as it's
   more accurate as time_left.
 adi,ad7266
 - Stop setting the iio_dev->masklength as it's done by the IIO core and
   should not be set from drivers.
 adi,ad799x
 - Some checkpatch type fixes.
 adi,ad9839
 - Ensure compelte MU_CNT1 is written during lock phase.
 adi,axi-dac
 - Fix inverted parameter.
 adi,adis16475
 - Drop documentation of non existent sysfs files.
 avago,apds9306
 - Fix an off by one error that overly restricts the range of persistence
   and adaptive thresholds that the driver accepts.
 freescale,mxs-lradc
 - Stop setting the iio_dev->masklength as it's done by the IIO core and
   should not be set from drivers.
 invensense,timestamp library
 - Fix timestamp vs interupt alignment and aovid soms glitches that
   occured when switching sampling frequency.
 microchip,mcp3564
 - Make use of device_for_each_child_node_scoped() to allow early release
   without manual fwnode_handle_put().
 microchip,mcp9600
 - Allow for negative temperatures.
 microchip,pac1934
 - Avoid an out of bounds array index.
 richtek,rtq6056
 - Use iio_device_claim_direct_scoped() to automate lock release and simplify
   the code.
 sensortek,stk3110
 - Drop a likely incorrect ACPI ID. No known users of this ID and it's
   not a valid ACPI ID.
 ti,ads1015
 - Make use of device_for_each_child_node_scoped() to allow early release
   without manual fwnode_handle_put().
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAmY1LaoRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0FojEZA//escavmkn31Q+hQFjaiYsr4YiLFMH2n4a
 qvRoiEoJgE9b1NDBzECSwN4OKqSZVlUxlX02wp2ntBWFFR5s1bXQKP1AL6QDpbgw
 Fc2BtJqoUvZ4E983NCmABCCln20Xyp1OqKYYkbwEINkL6yrr0/rOHHD4iXz++dhh
 QK1dmyUXuHqUbcF+yYJpo0WszWJjKJ0mwJi507v1KeDQPJWx5pygkPFgoJYluxvs
 iV525ZdOr4uNu30NbS4Rsh/RSJN9a+7VVJaYQBUsfLNf3/Z0xiM9OBTtiKUZt3k0
 olL6qo/B+/Akyo9ftch0sbUPrULR9LEPC8ue/XYc8fbVhaJ6Y6/6/5LHK9VV3MCR
 4ygJb7e5ohlaiYcSQeraxATgqRX1qXMHwfcQOjS6LJ3VDTo+Uu6eQhkCcMyuoefk
 /cO12Z9F6CPCfo2aXAdT6ehnGhwwoWAZvTIHiaIairiWNyl39BNe0+Px8M6TUdZt
 rSICiVZLu4j6lMBlMJymH6Y63t/F7vNmLBUSgnHvuolvq9xAyBiWfuNd1EdhhCt7
 ynt/AEb3y9HcDrEEkcSEbbeuvLkKHI5KoZ7zeZgOc5Po8n8o/3Kle6W2Q6pZvWNN
 /5HlDRvhbpZXcAwXrtX8RjIfq/broFI4JkIhoPx0dNwtJYbJtEDHQgNG1jH/UGOE
 DCl7Cyu2RpA=
 =2jqG
 -----END PGP SIGNATURE-----

Merge tag 'iio-for-6.10b-take2' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next

Jonathan writes:

IIO: 2nd set of new device support, features and cleanup for 6.10 (take 2)

The usual mixed bag from towards the end of the cycle.
Changes since take 1. Fixed the fixes tag and indeed fixed a rebase I
messed up on the same fix.

New devices support
===================

invensense,icm42600
- Support the ICM-42686-P a high range device going up to 32g and 4000 dps

New features
============

adi,ad7944
- Add support for chain mode in which many ADCs may be daisy chained and
  read out via a single long read.
adi,ad9467/backend library
- Add bus tuning related interfaces.
adi,axi-adc
- Add control for the AXI clock - seems always enabled early in boot for other
  reasons, but the driver should not rely on that..

Cleanups and minor or late breaking fixes
=========================================

Micrsoft/ACPI mount matrix handling.
- Replace several implementations of the Microsoft defined ROTM ACPI
  method with a single one.
multiple drivers
- Don't call the result of wait_for_completion() timeout as it's
  more accurate as time_left.
adi,ad7266
- Stop setting the iio_dev->masklength as it's done by the IIO core and
  should not be set from drivers.
adi,ad799x
- Some checkpatch type fixes.
adi,ad9839
- Ensure compelte MU_CNT1 is written during lock phase.
adi,axi-dac
- Fix inverted parameter.
adi,adis16475
- Drop documentation of non existent sysfs files.
avago,apds9306
- Fix an off by one error that overly restricts the range of persistence
  and adaptive thresholds that the driver accepts.
freescale,mxs-lradc
- Stop setting the iio_dev->masklength as it's done by the IIO core and
  should not be set from drivers.
invensense,timestamp library
- Fix timestamp vs interupt alignment and aovid soms glitches that
  occured when switching sampling frequency.
microchip,mcp3564
- Make use of device_for_each_child_node_scoped() to allow early release
  without manual fwnode_handle_put().
microchip,mcp9600
- Allow for negative temperatures.
microchip,pac1934
- Avoid an out of bounds array index.
richtek,rtq6056
- Use iio_device_claim_direct_scoped() to automate lock release and simplify
  the code.
sensortek,stk3110
- Drop a likely incorrect ACPI ID. No known users of this ID and it's
  not a valid ACPI ID.
ti,ads1015
- Make use of device_for_each_child_node_scoped() to allow early release
  without manual fwnode_handle_put().

* tag 'iio-for-6.10b-take2' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (41 commits)
  iio: temperature: mcp9600: Fix temperature reading for negative values
  iio: adc: PAC1934: fix accessing out of bounds array index
  iio: invensense: fix timestamp glitches when switching frequency
  iio: invensense: fix interrupt timestamp alignment
  iio: dac: ad9739a: write complete MU_CNT1 register during lock
  iio: pressure: zpa2326: use 'time_left' variable with wait_for_completion_interruptible_timeout()
  iio: adc: twl6030-gpadc: use 'time_left' variable with wait_for_completion_interruptible_timeout()
  iio: adc: stm32-dfsdm-adc: use 'time_left' variable with wait_for_completion_interruptible_timeout()
  iio: adc: stm32-adc: use 'time_left' variable with wait_for_completion_interruptible_timeout()
  iio: adc: intel_mrfld_adc: use 'time_left' variable with wait_for_completion_interruptible_timeout()
  iio: adc: fsl-imx25-gcq: use 'time_left' variable with wait_for_completion_interruptible_timeout()
  iio: adc: exynos_adc: use 'time_left' variable with wait_for_completion_timeout()
  iio: adc: ad_sigma_delta: use 'time_left' variable with wait_for_completion_timeout()
  iio: adc: ti-ads1015: use device_for_each_child_node_scoped()
  iio: adc: ad799x: Prefer to use octal permission
  iio: adc: ad799x: add blank line to avoid warning messages
  iio: adc: ad799x: change 'unsigned' to 'unsigned int' declaration
  iio: adc: mcp3564: Use device_for_each_child_node_scoped()
  iio: adc: ad9467: support digital interface calibration
  iio: adc: adi-axi-adc: support digital interface calibration
  ...
This commit is contained in:
Greg Kroah-Hartman 2024-05-04 09:48:52 +02:00
commit 1565fce99b
46 changed files with 1282 additions and 406 deletions

View File

@ -28,6 +28,9 @@ properties:
reg:
maxItems: 1
clocks:
maxItems: 1
dmas:
maxItems: 1
@ -48,6 +51,7 @@ required:
- compatible
- dmas
- reg
- clocks
additionalProperties: false
@ -58,6 +62,7 @@ examples:
reg = <0x44a00000 0x10000>;
dmas = <&rx_dma 0>;
dma-names = "rx";
clocks = <&axi_clk>;
#io-backend-cells = <0>;
};
...

View File

@ -32,6 +32,7 @@ properties:
- invensense,icm42605
- invensense,icm42622
- invensense,icm42631
- invensense,icm42686
- invensense,icm42688
reg:

View File

@ -24,7 +24,7 @@ Supported features
SPI wiring modes
----------------
The driver currently supports two of the many possible SPI wiring configurations.
The driver currently supports three of the many possible SPI wiring configurations.
CS mode, 3-wire, without busy indicator
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -68,6 +68,27 @@ CS mode, 4-wire, without busy indicator
To select this mode in the device tree, omit the ``adi,spi-mode`` property and
provide the ``cnv-gpios`` property.
Chain mode, without busy indicator
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block::
+-------------+
+-------------------------+--------------------| CS |
v v | |
+--------------------+ +--------------------+ | HOST |
| CNV | | CNV | | |
+--->| SDI AD7944 SDO |--->| SDI AD7944 SDO |-------->| SDI |
| | SCK | | SCK | | |
GND +--------------------+ +--------------------+ | |
^ ^ | |
+-------------------------+--------------------| SCLK |
+-------------+
To select this mode in the device tree, set the ``adi,spi-mode`` property to
``"chain"``, add the ``spi-cs-high`` flag, add the ``#daisy-chained-devices``
property, and omit the ``cnv-gpios`` property.
Reference voltage
-----------------
@ -86,7 +107,6 @@ Unimplemented features
- ``BUSY`` indication
- ``TURBO`` mode
- Daisy chain mode
Device attributes
@ -108,6 +128,9 @@ AD7944 and AD7985 are pseudo-differential ADCs and have the following attributes
| ``in_voltage0_scale`` | Scale factor to convert raw value to mV. |
+---------------------------------------+--------------------------------------------------------------+
In "chain" mode, additional chips will appear as additional voltage input
channels, e.g. ``in_voltage1_raw``.
Fully-differential ADCs
-----------------------
@ -121,6 +144,9 @@ AD7986 is a fully-differential ADC and has the following attributes:
| ``in_voltage0-voltage1_scale`` | Scale factor to convert raw value to mV. |
+---------------------------------------+--------------------------------------------------------------+
In "chain" mode, additional chips will appear as additional voltage input
channels, e.g. ``in_voltage2-voltage3_raw``.
Device buffers
==============

View File

@ -66,11 +66,9 @@ specific device folder path ``/sys/bus/iio/devices/iio:deviceX``.
+-------------------------------------------+----------------------------------------------------------+
| in_accel_x_calibbias | Calibration offset for the X-axis accelerometer channel. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_calibbias_x | x-axis acceleration offset correction |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_x_raw | Raw X-axis accelerometer channel value. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_calibbias_y | y-axis acceleration offset correction |
| in_accel_y_calibbias | Calibration offset for the Y-axis accelerometer channel. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_y_raw | Raw Y-axis accelerometer channel value. |
+-------------------------------------------+----------------------------------------------------------+
@ -94,11 +92,9 @@ specific device folder path ``/sys/bus/iio/devices/iio:deviceX``.
+---------------------------------------+------------------------------------------------------+
| in_anglvel_x_calibbias | Calibration offset for the X-axis gyroscope channel. |
+---------------------------------------+------------------------------------------------------+
| in_anglvel_calibbias_x | x-axis gyroscope offset correction |
+---------------------------------------+------------------------------------------------------+
| in_anglvel_x_raw | Raw X-axis gyroscope channel value. |
+---------------------------------------+------------------------------------------------------+
| in_anglvel_calibbias_y | y-axis gyroscope offset correction |
| in_anglvel_y_calibbias | Calibration offset for the Y-axis gyroscope channel. |
+---------------------------------------+------------------------------------------------------+
| in_anglvel_y_raw | Raw Y-axis gyroscope channel value. |
+---------------------------------------+------------------------------------------------------+

View File

@ -7,6 +7,7 @@ obj-$(CONFIG_IIO) += industrialio.o
industrialio-y := industrialio-core.o industrialio-event.o inkern.o
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
industrialio-$(CONFIG_ACPI) += industrialio-acpi.o
obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o
obj-$(CONFIG_IIO_GTS_HELPER) += industrialio-gts-helper.o

View File

@ -386,13 +386,9 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
static bool bmc150_apply_bosc0200_acpi_orientation(struct device *dev,
struct iio_mount_matrix *orientation)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct acpi_device *adev = ACPI_COMPANION(dev);
char *name, *alt_name, *label, *str;
union acpi_object *obj, *elements;
acpi_status status;
int i, j, val[3];
char *name, *alt_name, *label;
if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0) {
alt_name = "ROMK";
@ -411,43 +407,7 @@ static bool bmc150_apply_bosc0200_acpi_orientation(struct device *dev,
return false;
}
status = acpi_evaluate_object(adev->handle, name, NULL, &buffer);
if (ACPI_FAILURE(status)) {
dev_warn(dev, "Failed to get ACPI mount matrix: %d\n", status);
return false;
}
obj = buffer.pointer;
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3)
goto unknown_format;
elements = obj->package.elements;
for (i = 0; i < 3; i++) {
if (elements[i].type != ACPI_TYPE_STRING)
goto unknown_format;
str = elements[i].string.pointer;
if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3)
goto unknown_format;
for (j = 0; j < 3; j++) {
switch (val[j]) {
case -1: str = "-1"; break;
case 0: str = "0"; break;
case 1: str = "1"; break;
default: goto unknown_format;
}
orientation->rotation[i * 3 + j] = str;
}
}
kfree(buffer.pointer);
return true;
unknown_format:
dev_warn(dev, "Unknown ACPI mount matrix format, ignoring\n");
kfree(buffer.pointer);
return false;
return iio_read_acpi_mount_matrix(dev, orientation, name);
}
static bool bmc150_apply_dual250e_acpi_orientation(struct device *dev,

View File

@ -636,84 +636,6 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
return 0;
}
#ifdef CONFIG_ACPI
static bool kxj_acpi_orientation(struct device *dev,
struct iio_mount_matrix *orientation)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_device *adev = ACPI_COMPANION(dev);
char *str;
union acpi_object *obj, *elements;
acpi_status status;
int i, j, val[3];
bool ret = false;
if (!acpi_has_method(adev->handle, "ROTM"))
return false;
status = acpi_evaluate_object(adev->handle, "ROTM", NULL, &buffer);
if (ACPI_FAILURE(status)) {
dev_err(dev, "Failed to get ACPI mount matrix: %d\n", status);
return false;
}
obj = buffer.pointer;
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) {
dev_err(dev, "Unknown ACPI mount matrix package format\n");
goto out_free_buffer;
}
elements = obj->package.elements;
for (i = 0; i < 3; i++) {
if (elements[i].type != ACPI_TYPE_STRING) {
dev_err(dev, "Unknown ACPI mount matrix element format\n");
goto out_free_buffer;
}
str = elements[i].string.pointer;
if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) {
dev_err(dev, "Incorrect ACPI mount matrix string format\n");
goto out_free_buffer;
}
for (j = 0; j < 3; j++) {
switch (val[j]) {
case -1: str = "-1"; break;
case 0: str = "0"; break;
case 1: str = "1"; break;
default:
dev_err(dev, "Invalid value in ACPI mount matrix: %d\n", val[j]);
goto out_free_buffer;
}
orientation->rotation[i * 3 + j] = str;
}
}
ret = true;
out_free_buffer:
kfree(buffer.pointer);
return ret;
}
static bool kxj1009_apply_acpi_orientation(struct device *dev,
struct iio_mount_matrix *orientation)
{
struct acpi_device *adev = ACPI_COMPANION(dev);
if (adev && acpi_dev_hid_uid_match(adev, "KIOX000A", NULL))
return kxj_acpi_orientation(dev, orientation);
return false;
}
#else
static bool kxj1009_apply_acpi_orientation(struct device *dev,
struct iio_mount_matrix *orientation)
{
return false;
}
#endif
static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
{
int ret;
@ -1544,7 +1466,7 @@ static int kxcjk1013_probe(struct i2c_client *client)
} else {
data->active_high_intr = true; /* default polarity */
if (!kxj1009_apply_acpi_orientation(&client->dev, &data->orientation)) {
if (!iio_read_acpi_mount_matrix(&client->dev, &data->orientation, "ROTM")) {
ret = iio_read_mount_matrix(&client->dev, &data->orientation);
if (ret)
return ret;

View File

@ -56,6 +56,7 @@ struct mxc4005_data {
struct mutex mutex;
struct regmap *regmap;
struct iio_trigger *dready_trig;
struct iio_mount_matrix orientation;
/* Ensure timestamp is naturally aligned */
struct {
__be16 chans[3];
@ -259,6 +260,20 @@ static int mxc4005_write_raw(struct iio_dev *indio_dev,
}
}
static const struct iio_mount_matrix *
mxc4005_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct mxc4005_data *data = iio_priv(indio_dev);
return &data->orientation;
}
static const struct iio_chan_spec_ext_info mxc4005_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, mxc4005_get_mount_matrix),
{ }
};
static const struct iio_info mxc4005_info = {
.read_raw = mxc4005_read_raw,
.write_raw = mxc4005_write_raw,
@ -285,6 +300,7 @@ static const unsigned long mxc4005_scan_masks[] = {
.shift = 4, \
.endianness = IIO_BE, \
}, \
.ext_info = mxc4005_ext_info, \
}
static const struct iio_chan_spec mxc4005_channels[] = {
@ -415,6 +431,12 @@ static int mxc4005_probe(struct i2c_client *client)
mutex_init(&data->mutex);
if (!iio_read_acpi_mount_matrix(&client->dev, &data->orientation, "ROTM")) {
ret = iio_read_mount_matrix(&client->dev, &data->orientation);
if (ret)
return ret;
}
indio_dev->channels = mxc4005_channels;
indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels);
indio_dev->available_scan_masks = mxc4005_scan_masks;

View File

@ -371,7 +371,6 @@ static void ad7266_init_channels(struct iio_dev *indio_dev)
indio_dev->channels = chan_info->channels;
indio_dev->num_channels = chan_info->num_channels;
indio_dev->available_scan_masks = chan_info->scan_masks;
indio_dev->masklength = chan_info->num_channels - 1;
}
static const char * const ad7266_gpio_labels[] = {

View File

@ -6,6 +6,7 @@
* Copyright 2024 BayLibre, SAS
*/
#include <linux/align.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/delay.h>
@ -53,6 +54,7 @@ struct ad7944_adc {
enum ad7944_spi_mode spi_mode;
struct spi_transfer xfers[3];
struct spi_message msg;
void *chain_mode_buf;
/* Chip-specific timing specifications. */
const struct ad7944_timing_spec *timing_spec;
/* GPIO connected to CNV pin. */
@ -214,6 +216,46 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc
return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg);
}
static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc,
const struct iio_chan_spec *chan,
u32 n_chain_dev)
{
struct spi_transfer *xfers = adc->xfers;
int ret;
/*
* NB: SCLK has to be low before we toggle CS to avoid triggering the
* busy indication.
*/
if (adc->spi->mode & SPI_CPOL)
return dev_err_probe(dev, -EINVAL,
"chain mode requires ~SPI_CPOL\n");
/*
* We only support CNV connected to CS in chain mode and we need CNV
* to be high during the transfer to trigger the conversion.
*/
if (!(adc->spi->mode & SPI_CS_HIGH))
return dev_err_probe(dev, -EINVAL,
"chain mode requires SPI_CS_HIGH\n");
/* CNV has to be high for full conversion time before reading data. */
xfers[0].delay.value = adc->timing_spec->conv_ns;
xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS;
xfers[1].rx_buf = adc->chain_mode_buf;
xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits) * n_chain_dev;
xfers[1].bits_per_word = chan->scan_type.realbits;
spi_message_init_with_transfers(&adc->msg, xfers, 2);
ret = spi_optimize_message(adc->spi, &adc->msg);
if (ret)
return ret;
return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg);
}
/**
* ad7944_convert_and_acquire - Perform a single conversion and acquisition
* @adc: The ADC device structure
@ -223,7 +265,8 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc
* Perform a conversion and acquisition of a single sample using the
* pre-optimized adc->msg.
*
* Upon successful return adc->sample.raw will contain the conversion result.
* Upon successful return adc->sample.raw will contain the conversion result
* (or adc->chain_mode_buf if the device is using chain mode).
*/
static int ad7944_convert_and_acquire(struct ad7944_adc *adc,
const struct iio_chan_spec *chan)
@ -252,10 +295,17 @@ static int ad7944_single_conversion(struct ad7944_adc *adc,
if (ret)
return ret;
if (chan->scan_type.storagebits > 16)
*val = adc->sample.raw.u32;
else
*val = adc->sample.raw.u16;
if (adc->spi_mode == AD7944_SPI_MODE_CHAIN) {
if (chan->scan_type.storagebits > 16)
*val = ((u32 *)adc->chain_mode_buf)[chan->scan_index];
else
*val = ((u16 *)adc->chain_mode_buf)[chan->scan_index];
} else {
if (chan->scan_type.storagebits > 16)
*val = adc->sample.raw.u32;
else
*val = adc->sample.raw.u16;
}
if (chan->scan_type.sign == 's')
*val = sign_extend32(*val, chan->scan_type.realbits - 1);
@ -315,8 +365,12 @@ static irqreturn_t ad7944_trigger_handler(int irq, void *p)
if (ret)
goto out;
iio_push_to_buffers_with_timestamp(indio_dev, &adc->sample.raw,
pf->timestamp);
if (adc->spi_mode == AD7944_SPI_MODE_CHAIN)
iio_push_to_buffers_with_timestamp(indio_dev, adc->chain_mode_buf,
pf->timestamp);
else
iio_push_to_buffers_with_timestamp(indio_dev, &adc->sample.raw,
pf->timestamp);
out:
iio_trigger_notify_done(indio_dev->trig);
@ -324,6 +378,90 @@ static irqreturn_t ad7944_trigger_handler(int irq, void *p)
return IRQ_HANDLED;
}
/**
* ad7944_chain_mode_alloc - allocate and initialize channel specs and buffers
* for daisy-chained devices
* @dev: The device for devm_ functions
* @chan_template: The channel template for the devices (array of 2 channels
* voltage and timestamp)
* @n_chain_dev: The number of devices in the chain
* @chain_chan: Pointer to receive the allocated channel specs
* @chain_mode_buf: Pointer to receive the allocated rx buffer
* @chain_scan_masks: Pointer to receive the allocated scan masks
* Return: 0 on success, a negative error code on failure
*/
static int ad7944_chain_mode_alloc(struct device *dev,
const struct iio_chan_spec *chan_template,
u32 n_chain_dev,
struct iio_chan_spec **chain_chan,
void **chain_mode_buf,
unsigned long **chain_scan_masks)
{
struct iio_chan_spec *chan;
size_t chain_mode_buf_size;
unsigned long *scan_masks;
void *buf;
int i;
/* 1 channel for each device in chain plus 1 for soft timestamp */
chan = devm_kcalloc(dev, n_chain_dev + 1, sizeof(*chan), GFP_KERNEL);
if (!chan)
return -ENOMEM;
for (i = 0; i < n_chain_dev; i++) {
chan[i] = chan_template[0];
if (chan_template[0].differential) {
chan[i].channel = 2 * i;
chan[i].channel2 = 2 * i + 1;
} else {
chan[i].channel = i;
}
chan[i].scan_index = i;
}
/* soft timestamp */
chan[i] = chan_template[1];
chan[i].scan_index = i;
*chain_chan = chan;
/* 1 word for each voltage channel + aligned u64 for timestamp */
chain_mode_buf_size = ALIGN(n_chain_dev *
BITS_TO_BYTES(chan[0].scan_type.storagebits), sizeof(u64))
+ sizeof(u64);
buf = devm_kzalloc(dev, chain_mode_buf_size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
*chain_mode_buf = buf;
/*
* Have to limit n_chain_dev due to current implementation of
* available_scan_masks.
*/
if (n_chain_dev > BITS_PER_LONG)
return dev_err_probe(dev, -EINVAL,
"chain is limited to 32 devices\n");
scan_masks = devm_kcalloc(dev, 2, sizeof(*scan_masks), GFP_KERNEL);
if (!scan_masks)
return -ENOMEM;
/*
* Scan mask is needed since we always have to read all devices in the
* chain in one SPI transfer.
*/
scan_masks[0] = GENMASK(n_chain_dev - 1, 0);
*chain_scan_masks = scan_masks;
return 0;
}
static const char * const ad7944_power_supplies[] = {
"avdd", "dvdd", "bvdd", "vio"
};
@ -341,6 +479,9 @@ static int ad7944_probe(struct spi_device *spi)
struct ad7944_adc *adc;
bool have_refin = false;
struct regulator *ref;
struct iio_chan_spec *chain_chan;
unsigned long *chain_scan_masks;
u32 n_chain_dev;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
@ -474,14 +615,39 @@ static int ad7944_probe(struct spi_device *spi)
break;
case AD7944_SPI_MODE_CHAIN:
return dev_err_probe(dev, -EINVAL, "chain mode is not implemented\n");
ret = device_property_read_u32(dev, "#daisy-chained-devices",
&n_chain_dev);
if (ret)
return dev_err_probe(dev, ret,
"failed to get #daisy-chained-devices\n");
ret = ad7944_chain_mode_alloc(dev, chip_info->channels,
n_chain_dev, &chain_chan,
&adc->chain_mode_buf,
&chain_scan_masks);
if (ret)
return ret;
ret = ad7944_chain_mode_init_msg(dev, adc, &chain_chan[0],
n_chain_dev);
if (ret)
return ret;
break;
}
indio_dev->name = chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ad7944_iio_info;
indio_dev->channels = chip_info->channels;
indio_dev->num_channels = ARRAY_SIZE(chip_info->channels);
if (adc->spi_mode == AD7944_SPI_MODE_CHAIN) {
indio_dev->available_scan_masks = chain_scan_masks;
indio_dev->channels = chain_chan;
indio_dev->num_channels = n_chain_dev + 1;
} else {
indio_dev->channels = chip_info->channels;
indio_dev->num_channels = ARRAY_SIZE(chip_info->channels);
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,

View File

@ -128,7 +128,7 @@ struct ad799x_state {
struct regulator *vref;
/* lock to protect against multiple access to the device */
struct mutex lock;
unsigned id;
unsigned int id;
u16 config;
u8 *rx_buf;
@ -253,7 +253,7 @@ static int ad799x_update_scan_mode(struct iio_dev *indio_dev,
}
}
static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch)
static int ad799x_scan_direct(struct ad799x_state *st, unsigned int ch)
{
u8 cmd;
@ -335,6 +335,7 @@ static ssize_t ad799x_read_frequency(struct device *dev,
struct ad799x_state *st = iio_priv(indio_dev);
int ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
if (ret < 0)
return ret;
@ -523,7 +524,7 @@ static irqreturn_t ad799x_event_handler(int irq, void *private)
return IRQ_HANDLED;
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
static IIO_DEV_ATTR_SAMP_FREQ(0644,
ad799x_read_frequency,
ad799x_write_frequency);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 244 0");

View File

@ -4,7 +4,11 @@
*
* Copyright 2012-2020 Analog Devices Inc.
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/device.h>
@ -100,6 +104,8 @@
#define AD9467_DEF_OUTPUT_MODE 0x08
#define AD9467_REG_VREF_MASK 0x0F
#define AD9647_MAX_TEST_POINTS 32
struct ad9467_chip_info {
const char *name;
unsigned int id;
@ -110,6 +116,9 @@ struct ad9467_chip_info {
unsigned long max_rate;
unsigned int default_output_mode;
unsigned int vref_mask;
unsigned int num_lanes;
/* data clock output */
bool has_dco;
};
struct ad9467_state {
@ -119,7 +128,16 @@ struct ad9467_state {
struct clk *clk;
unsigned int output_mode;
unsigned int (*scales)[2];
/*
* Times 2 because we may also invert the signal polarity and run the
* calibration again. For some reference on the test points (ad9265) see:
* https://www.analog.com/media/en/technical-documentation/data-sheets/ad9265.pdf
* at page 38 for the dco output delay. On devices as ad9467, the
* calibration is done at the backend level. For the ADI axi-adc:
* https://wiki.analog.com/resources/fpga/docs/axi_adc_ip
* at the io delay control section.
*/
DECLARE_BITMAP(calib_map, AD9647_MAX_TEST_POINTS * 2);
struct gpio_desc *pwrdown_gpio;
/* ensure consistent state obtained on multiple related accesses */
struct mutex lock;
@ -242,6 +260,7 @@ static const struct ad9467_chip_info ad9467_chip_tbl = {
.num_channels = ARRAY_SIZE(ad9467_channels),
.default_output_mode = AD9467_DEF_OUTPUT_MODE,
.vref_mask = AD9467_REG_VREF_MASK,
.num_lanes = 8,
};
static const struct ad9467_chip_info ad9434_chip_tbl = {
@ -254,6 +273,7 @@ static const struct ad9467_chip_info ad9434_chip_tbl = {
.num_channels = ARRAY_SIZE(ad9434_channels),
.default_output_mode = AD9434_DEF_OUTPUT_MODE,
.vref_mask = AD9434_REG_VREF_MASK,
.num_lanes = 6,
};
static const struct ad9467_chip_info ad9265_chip_tbl = {
@ -266,6 +286,7 @@ static const struct ad9467_chip_info ad9265_chip_tbl = {
.num_channels = ARRAY_SIZE(ad9467_channels),
.default_output_mode = AD9265_DEF_OUTPUT_MODE,
.vref_mask = AD9265_REG_VREF_MASK,
.has_dco = true,
};
static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2)
@ -321,6 +342,246 @@ static int ad9467_set_scale(struct ad9467_state *st, int val, int val2)
return -EINVAL;
}
static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
{
int ret;
ret = ad9467_spi_write(spi, AN877_ADC_REG_OUTPUT_MODE, mode);
if (ret < 0)
return ret;
return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
static int ad9647_calibrate_prepare(const struct ad9467_state *st)
{
struct iio_backend_data_fmt data = {
.enable = false,
};
unsigned int c;
int ret;
ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TEST_IO,
AN877_ADC_TESTMODE_PN9_SEQ);
if (ret)
return ret;
ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
if (ret)
return ret;
ret = ad9467_outputmode_set(st->spi, st->info->default_output_mode);
if (ret)
return ret;
for (c = 0; c < st->info->num_channels; c++) {
ret = iio_backend_data_format_set(st->back, c, &data);
if (ret)
return ret;
}
ret = iio_backend_test_pattern_set(st->back, 0,
IIO_BACKEND_ADI_PRBS_9A);
if (ret)
return ret;
return iio_backend_chan_enable(st->back, 0);
}
static int ad9647_calibrate_polarity_set(const struct ad9467_state *st,
bool invert)
{
enum iio_backend_sample_trigger trigger;
if (st->info->has_dco) {
unsigned int phase = AN877_ADC_OUTPUT_EVEN_ODD_MODE_EN;
if (invert)
phase |= AN877_ADC_INVERT_DCO_CLK;
return ad9467_spi_write(st->spi, AN877_ADC_REG_OUTPUT_PHASE,
phase);
}
if (invert)
trigger = IIO_BACKEND_SAMPLE_TRIGGER_EDGE_FALLING;
else
trigger = IIO_BACKEND_SAMPLE_TRIGGER_EDGE_RISING;
return iio_backend_data_sample_trigger(st->back, trigger);
}
/*
* The idea is pretty simple. Find the max number of successful points in a row
* and get the one in the middle.
*/
static unsigned int ad9467_find_optimal_point(const unsigned long *calib_map,
unsigned int start,
unsigned int nbits,
unsigned int *val)
{
unsigned int bit = start, end, start_cnt, cnt = 0;
for_each_clear_bitrange_from(bit, end, calib_map, nbits + start) {
if (end - bit > cnt) {
cnt = end - bit;
start_cnt = bit;
}
}
if (cnt)
*val = start_cnt + cnt / 2;
return cnt;
}
static int ad9467_calibrate_apply(const struct ad9467_state *st,
unsigned int val)
{
unsigned int lane;
int ret;
if (st->info->has_dco) {
ret = ad9467_spi_write(st->spi, AN877_ADC_REG_OUTPUT_DELAY,
val);
if (ret)
return ret;
return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
for (lane = 0; lane < st->info->num_lanes; lane++) {
ret = iio_backend_iodelay_set(st->back, lane, val);
if (ret)
return ret;
}
return 0;
}
static int ad9647_calibrate_stop(const struct ad9467_state *st)
{
struct iio_backend_data_fmt data = {
.sign_extend = true,
.enable = true,
};
unsigned int c, mode;
int ret;
ret = iio_backend_chan_disable(st->back, 0);
if (ret)
return ret;
ret = iio_backend_test_pattern_set(st->back, 0,
IIO_BACKEND_NO_TEST_PATTERN);
if (ret)
return ret;
for (c = 0; c < st->info->num_channels; c++) {
ret = iio_backend_data_format_set(st->back, c, &data);
if (ret)
return ret;
}
mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
ret = ad9467_outputmode_set(st->spi, mode);
if (ret)
return ret;
ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TEST_IO,
AN877_ADC_TESTMODE_OFF);
if (ret)
return ret;
return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
static int ad9467_calibrate(struct ad9467_state *st)
{
unsigned int point, val, inv_val, cnt, inv_cnt = 0;
/*
* Half of the bitmap is for the inverted signal. The number of test
* points is the same though...
*/
unsigned int test_points = AD9647_MAX_TEST_POINTS;
unsigned long sample_rate = clk_get_rate(st->clk);
struct device *dev = &st->spi->dev;
bool invert = false, stat;
int ret;
/* all points invalid */
bitmap_fill(st->calib_map, BITS_PER_TYPE(st->calib_map));
ret = ad9647_calibrate_prepare(st);
if (ret)
return ret;
retune:
ret = ad9647_calibrate_polarity_set(st, invert);
if (ret)
return ret;
for (point = 0; point < test_points; point++) {
ret = ad9467_calibrate_apply(st, point);
if (ret)
return ret;
ret = iio_backend_chan_status(st->back, 0, &stat);
if (ret)
return ret;
__assign_bit(point + invert * test_points, st->calib_map, stat);
}
if (!invert) {
cnt = ad9467_find_optimal_point(st->calib_map, 0, test_points,
&val);
/*
* We're happy if we find, at least, three good test points in
* a row.
*/
if (cnt < 3) {
invert = true;
goto retune;
}
} else {
inv_cnt = ad9467_find_optimal_point(st->calib_map, test_points,
test_points, &inv_val);
if (!inv_cnt && !cnt)
return -EIO;
}
if (inv_cnt < cnt) {
ret = ad9647_calibrate_polarity_set(st, false);
if (ret)
return ret;
} else {
/*
* polarity inverted is the last test to run. Hence, there's no
* need to re-do any configuration. We just need to "normalize"
* the selected value.
*/
val = inv_val - test_points;
}
if (st->info->has_dco)
dev_dbg(dev, "%sDCO 0x%X CLK %lu Hz\n", inv_cnt >= cnt ? "INVERT " : "",
val, sample_rate);
else
dev_dbg(dev, "%sIDELAY 0x%x\n", inv_cnt >= cnt ? "INVERT " : "",
val);
ret = ad9467_calibrate_apply(st, val);
if (ret)
return ret;
/* finally apply the optimal value */
return ad9647_calibrate_stop(st);
}
static int ad9467_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long m)
@ -345,7 +606,9 @@ static int ad9467_write_raw(struct iio_dev *indio_dev,
{
struct ad9467_state *st = iio_priv(indio_dev);
const struct ad9467_chip_info *info = st->info;
unsigned long sample_rate;
long r_clk;
int ret;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@ -358,7 +621,23 @@ static int ad9467_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
return clk_set_rate(st->clk, r_clk);
sample_rate = clk_get_rate(st->clk);
/*
* clk_set_rate() would also do this but since we would still
* need it for avoiding an unnecessary calibration, do it now.
*/
if (sample_rate == r_clk)
return 0;
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
ret = clk_set_rate(st->clk, r_clk);
if (ret)
return ret;
guard(mutex)(&st->lock);
ret = ad9467_calibrate(st);
}
return ret;
default:
return -EINVAL;
}
@ -411,18 +690,6 @@ static const struct iio_info ad9467_info = {
.read_avail = ad9467_read_avail,
};
static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
{
int ret;
ret = ad9467_spi_write(spi, AN877_ADC_REG_OUTPUT_MODE, mode);
if (ret < 0)
return ret;
return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
static int ad9467_scale_fill(struct ad9467_state *st)
{
const struct ad9467_chip_info *info = st->info;
@ -442,29 +709,6 @@ static int ad9467_scale_fill(struct ad9467_state *st)
return 0;
}
static int ad9467_setup(struct ad9467_state *st)
{
struct iio_backend_data_fmt data = {
.sign_extend = true,
.enable = true,
};
unsigned int c, mode;
int ret;
mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
ret = ad9467_outputmode_set(st->spi, mode);
if (ret)
return ret;
for (c = 0; c < st->info->num_channels; c++) {
ret = iio_backend_data_format_set(st->back, c, &data);
if (ret)
return ret;
}
return 0;
}
static int ad9467_reset(struct device *dev)
{
struct gpio_desc *gpio;
@ -521,6 +765,52 @@ static int ad9467_iio_backend_get(struct ad9467_state *st)
return -ENODEV;
}
static ssize_t ad9467_dump_calib_table(struct file *file,
char __user *userbuf,
size_t count, loff_t *ppos)
{
struct ad9467_state *st = file->private_data;
unsigned int bit, size = BITS_PER_TYPE(st->calib_map);
/* +2 for the newline and +1 for the string termination */
unsigned char map[AD9647_MAX_TEST_POINTS * 2 + 3];
ssize_t len = 0;
guard(mutex)(&st->lock);
if (*ppos)
goto out_read;
for (bit = 0; bit < size; bit++) {
if (bit == size / 2)
len += scnprintf(map + len, sizeof(map) - len, "\n");
len += scnprintf(map + len, sizeof(map) - len, "%c",
test_bit(bit, st->calib_map) ? 'x' : 'o');
}
len += scnprintf(map + len, sizeof(map) - len, "\n");
out_read:
return simple_read_from_buffer(userbuf, count, ppos, map, len);
}
static const struct file_operations ad9467_calib_table_fops = {
.open = simple_open,
.read = ad9467_dump_calib_table,
.llseek = default_llseek,
.owner = THIS_MODULE,
};
static void ad9467_debugfs_init(struct iio_dev *indio_dev)
{
struct dentry *d = iio_get_debugfs_dentry(indio_dev);
struct ad9467_state *st = iio_priv(indio_dev);
if (!IS_ENABLED(CONFIG_DEBUG_FS))
return;
debugfs_create_file("calibration_table_dump", 0400, d, st,
&ad9467_calib_table_fops);
}
static int ad9467_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
@ -580,11 +870,17 @@ static int ad9467_probe(struct spi_device *spi)
if (ret)
return ret;
ret = ad9467_setup(st);
ret = ad9467_calibrate(st);
if (ret)
return ret;
return devm_iio_device_register(&spi->dev, indio_dev);
ret = devm_iio_device_register(&spi->dev, indio_dev);
if (ret)
return ret;
ad9467_debugfs_init(indio_dev);
return 0;
}
static const struct of_device_id ad9467_of_match[] = {

View File

@ -206,7 +206,7 @@ int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
unsigned int mode, unsigned int channel)
{
int ret;
unsigned long timeout;
unsigned long time_left;
ret = ad_sigma_delta_set_channel(sigma_delta, channel);
if (ret)
@ -223,8 +223,8 @@ int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->irq_line);
timeout = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ);
if (timeout == 0) {
time_left = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ);
if (time_left == 0) {
sigma_delta->irq_dis = true;
disable_irq_nosync(sigma_delta->irq_line);
ret = -EIO;

View File

@ -7,11 +7,13 @@
*/
#include <linux/bitfield.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@ -37,6 +39,9 @@
#define ADI_AXI_REG_RSTN_MMCM_RSTN BIT(1)
#define ADI_AXI_REG_RSTN_RSTN BIT(0)
#define ADI_AXI_ADC_REG_CTRL 0x0044
#define ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK BIT(1)
/* ADC Channel controls */
#define ADI_AXI_REG_CHAN_CTRL(c) (0x0400 + (c) * 0x40)
@ -51,14 +56,28 @@
#define ADI_AXI_REG_CHAN_CTRL_PN_TYPE_OWR BIT(1)
#define ADI_AXI_REG_CHAN_CTRL_ENABLE BIT(0)
#define ADI_AXI_ADC_REG_CHAN_STATUS(c) (0x0404 + (c) * 0x40)
#define ADI_AXI_ADC_CHAN_STAT_PN_MASK GENMASK(2, 1)
#define ADI_AXI_ADC_REG_CHAN_CTRL_3(c) (0x0418 + (c) * 0x40)
#define ADI_AXI_ADC_CHAN_PN_SEL_MASK GENMASK(19, 16)
/* IO Delays */
#define ADI_AXI_ADC_REG_DELAY(l) (0x0800 + (l) * 0x4)
#define AXI_ADC_DELAY_CTRL_MASK GENMASK(4, 0)
#define ADI_AXI_ADC_MAX_IO_NUM_LANES 15
#define ADI_AXI_REG_CHAN_CTRL_DEFAULTS \
(ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT | \
ADI_AXI_REG_CHAN_CTRL_FMT_EN | \
ADI_AXI_REG_CHAN_CTRL_ENABLE)
struct adi_axi_adc_state {
struct regmap *regmap;
struct device *dev;
struct regmap *regmap;
struct device *dev;
/* lock to protect multiple accesses to the device registers */
struct mutex lock;
};
static int axi_adc_enable(struct iio_backend *back)
@ -104,6 +123,100 @@ static int axi_adc_data_format_set(struct iio_backend *back, unsigned int chan,
ADI_AXI_REG_CHAN_CTRL_FMT_MASK, val);
}
static int axi_adc_data_sample_trigger(struct iio_backend *back,
enum iio_backend_sample_trigger trigger)
{
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
switch (trigger) {
case IIO_BACKEND_SAMPLE_TRIGGER_EDGE_RISING:
return regmap_clear_bits(st->regmap, ADI_AXI_ADC_REG_CTRL,
ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK);
case IIO_BACKEND_SAMPLE_TRIGGER_EDGE_FALLING:
return regmap_set_bits(st->regmap, ADI_AXI_ADC_REG_CTRL,
ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK);
default:
return -EINVAL;
}
}
static int axi_adc_iodelays_set(struct iio_backend *back, unsigned int lane,
unsigned int tap)
{
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
int ret;
u32 val;
if (tap > FIELD_MAX(AXI_ADC_DELAY_CTRL_MASK))
return -EINVAL;
if (lane > ADI_AXI_ADC_MAX_IO_NUM_LANES)
return -EINVAL;
guard(mutex)(&st->lock);
ret = regmap_write(st->regmap, ADI_AXI_ADC_REG_DELAY(lane), tap);
if (ret)
return ret;
/*
* If readback is ~0, that means there are issues with the
* delay_clk.
*/
ret = regmap_read(st->regmap, ADI_AXI_ADC_REG_DELAY(lane), &val);
if (ret)
return ret;
if (val == U32_MAX)
return -EIO;
return 0;
}
static int axi_adc_test_pattern_set(struct iio_backend *back,
unsigned int chan,
enum iio_backend_test_pattern pattern)
{
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
switch (pattern) {
case IIO_BACKEND_NO_TEST_PATTERN:
/* nothing to do */
return 0;
case IIO_BACKEND_ADI_PRBS_9A:
return regmap_update_bits(st->regmap, ADI_AXI_ADC_REG_CHAN_CTRL_3(chan),
ADI_AXI_ADC_CHAN_PN_SEL_MASK,
FIELD_PREP(ADI_AXI_ADC_CHAN_PN_SEL_MASK, 0));
default:
return -EINVAL;
}
}
static int axi_adc_chan_status(struct iio_backend *back, unsigned int chan,
bool *error)
{
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
int ret;
u32 val;
guard(mutex)(&st->lock);
/* reset test bits by setting them */
ret = regmap_write(st->regmap, ADI_AXI_ADC_REG_CHAN_STATUS(chan),
ADI_AXI_ADC_CHAN_STAT_PN_MASK);
if (ret)
return ret;
/* let's give enough time to validate or erroring the incoming pattern */
fsleep(1000);
ret = regmap_read(st->regmap, ADI_AXI_ADC_REG_CHAN_STATUS(chan), &val);
if (ret)
return ret;
if (ADI_AXI_ADC_CHAN_STAT_PN_MASK & val)
*error = true;
else
*error = false;
return 0;
}
static int axi_adc_chan_enable(struct iio_backend *back, unsigned int chan)
{
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
@ -142,7 +255,6 @@ static const struct regmap_config axi_adc_regmap_config = {
.val_bits = 32,
.reg_bits = 32,
.reg_stride = 4,
.max_register = 0x0800,
};
static const struct iio_backend_ops adi_axi_adc_generic = {
@ -153,6 +265,10 @@ static const struct iio_backend_ops adi_axi_adc_generic = {
.chan_disable = axi_adc_chan_disable,
.request_buffer = axi_adc_request_buffer,
.free_buffer = axi_adc_free_buffer,
.data_sample_trigger = axi_adc_data_sample_trigger,
.iodelay_set = axi_adc_iodelays_set,
.test_pattern_set = axi_adc_test_pattern_set,
.chan_status = axi_adc_chan_status,
};
static int adi_axi_adc_probe(struct platform_device *pdev)
@ -161,6 +277,7 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
struct adi_axi_adc_state *st;
void __iomem *base;
unsigned int ver;
struct clk *clk;
int ret;
st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL);
@ -181,6 +298,10 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
if (!expected_ver)
return -ENODEV;
clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
/*
* Force disable the core. Up to the frontend to enable us. And we can
* still read/write registers...

View File

@ -538,7 +538,7 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
long mask)
{
struct exynos_adc *info = iio_priv(indio_dev);
unsigned long timeout;
unsigned long time_left;
int ret;
if (mask == IIO_CHAN_INFO_SCALE) {
@ -562,9 +562,9 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
if (info->data->start_conv)
info->data->start_conv(info, chan->address);
timeout = wait_for_completion_timeout(&info->completion,
EXYNOS_ADC_TIMEOUT);
if (timeout == 0) {
time_left = wait_for_completion_timeout(&info->completion,
EXYNOS_ADC_TIMEOUT);
if (time_left == 0) {
dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
if (info->data->init_hw)
info->data->init_hw(info);
@ -583,7 +583,7 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
static int exynos_read_s3c64xx_ts(struct iio_dev *indio_dev, int *x, int *y)
{
struct exynos_adc *info = iio_priv(indio_dev);
unsigned long timeout;
unsigned long time_left;
int ret;
mutex_lock(&info->lock);
@ -597,9 +597,9 @@ static int exynos_read_s3c64xx_ts(struct iio_dev *indio_dev, int *x, int *y)
/* Select the ts channel to be used and Trigger conversion */
info->data->start_conv(info, ADC_S3C2410_MUX_TS);
timeout = wait_for_completion_timeout(&info->completion,
EXYNOS_ADC_TIMEOUT);
if (timeout == 0) {
time_left = wait_for_completion_timeout(&info->completion,
EXYNOS_ADC_TIMEOUT);
if (time_left == 0) {
dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
if (info->data->init_hw)
info->data->init_hw(info);

View File

@ -108,7 +108,7 @@ static int mx25_gcq_get_raw_value(struct device *dev,
struct mx25_gcq_priv *priv,
int *val)
{
long timeout;
long time_left;
u32 data;
/* Setup the configuration we want to use */
@ -121,12 +121,12 @@ static int mx25_gcq_get_raw_value(struct device *dev,
regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS,
MX25_ADCQ_CR_FQS);
timeout = wait_for_completion_interruptible_timeout(
time_left = wait_for_completion_interruptible_timeout(
&priv->completed, MX25_GCQ_TIMEOUT);
if (timeout < 0) {
if (time_left < 0) {
dev_err(dev, "ADC wait for measurement failed\n");
return timeout;
} else if (timeout == 0) {
return time_left;
} else if (time_left == 0) {
dev_err(dev, "ADC timed out\n");
return -ETIMEDOUT;
}

View File

@ -75,7 +75,7 @@ static int mrfld_adc_single_conv(struct iio_dev *indio_dev,
struct mrfld_adc *adc = iio_priv(indio_dev);
struct regmap *regmap = adc->regmap;
unsigned int req;
long timeout;
long time_left;
__be16 value;
int ret;
@ -95,13 +95,13 @@ static int mrfld_adc_single_conv(struct iio_dev *indio_dev,
if (ret)
goto done;
timeout = wait_for_completion_interruptible_timeout(&adc->completion,
BCOVE_ADC_TIMEOUT);
if (timeout < 0) {
ret = timeout;
time_left = wait_for_completion_interruptible_timeout(&adc->completion,
BCOVE_ADC_TIMEOUT);
if (time_left < 0) {
ret = time_left;
goto done;
}
if (timeout == 0) {
if (time_left == 0) {
ret = -ETIMEDOUT;
goto done;
}

View File

@ -998,7 +998,6 @@ static int mcp3564_parse_fw_children(struct iio_dev *indio_dev)
struct mcp3564_state *adc = iio_priv(indio_dev);
struct device *dev = &adc->spi->dev;
struct iio_chan_spec *channels;
struct fwnode_handle *child;
struct iio_chan_spec chanspec = mcp3564_channel_template;
struct iio_chan_spec temp_chanspec = mcp3564_temp_channel_template;
struct iio_chan_spec burnout_chanspec = mcp3564_burnout_channel_template;
@ -1025,7 +1024,7 @@ static int mcp3564_parse_fw_children(struct iio_dev *indio_dev)
if (!channels)
return dev_err_probe(dev, -ENOMEM, "Can't allocate memory\n");
device_for_each_child_node(dev, child) {
device_for_each_child_node_scoped(dev, child) {
node_name = fwnode_get_name(child);
if (fwnode_property_present(child, "diff-channels")) {
@ -1033,26 +1032,25 @@ static int mcp3564_parse_fw_children(struct iio_dev *indio_dev)
"diff-channels",
inputs,
ARRAY_SIZE(inputs));
if (ret)
return ret;
chanspec.differential = 1;
} else {
ret = fwnode_property_read_u32(child, "reg", &inputs[0]);
if (ret)
return ret;
chanspec.differential = 0;
inputs[1] = MCP3564_AGND;
}
if (ret) {
fwnode_handle_put(child);
return ret;
}
if (inputs[0] > MCP3564_INTERNAL_VCM ||
inputs[1] > MCP3564_INTERNAL_VCM) {
fwnode_handle_put(child);
inputs[1] > MCP3564_INTERNAL_VCM)
return dev_err_probe(&indio_dev->dev, -EINVAL,
"Channel index > %d, for %s\n",
MCP3564_INTERNAL_VCM + 1,
node_name);
}
chanspec.address = (inputs[0] << 4) | inputs[1];
chanspec.channel = inputs[0];

View File

@ -724,7 +724,6 @@ static int mxs_lradc_adc_probe(struct platform_device *pdev)
iio->dev.of_node = dev->parent->of_node;
iio->info = &mxs_lradc_adc_iio_info;
iio->modes = INDIO_DIRECT_MODE;
iio->masklength = LRADC_MAX_TOTAL_CHANS;
if (lradc->soc == IMX23_LRADC) {
iio->channels = mx23_lradc_chan_spec;

View File

@ -787,6 +787,15 @@ static int pac1934_read_raw(struct iio_dev *indio_dev,
s64 curr_energy;
int ret, channel = chan->channel - 1;
/*
* For AVG the index should be between 5 to 8.
* To calculate PAC1934_CH_VOLTAGE_AVERAGE,
* respectively PAC1934_CH_CURRENT real index, we need
* to remove the added offset (PAC1934_MAX_NUM_CHANNELS).
*/
if (channel >= PAC1934_MAX_NUM_CHANNELS)
channel = channel - PAC1934_MAX_NUM_CHANNELS;
ret = pac1934_retrieve_data(info, PAC1934_MIN_UPDATE_WAIT_TIME_US);
if (ret < 0)
return ret;

View File

@ -520,32 +520,20 @@ static int rtq6056_adc_write_raw(struct iio_dev *indio_dev,
{
struct rtq6056_priv *priv = iio_priv(indio_dev);
const struct richtek_dev_data *devdata = priv->devdata;
int ret;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
if (devdata->fixed_samp_freq) {
ret = -EINVAL;
break;
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
if (devdata->fixed_samp_freq)
return -EINVAL;
return rtq6056_adc_set_samp_freq(priv, chan, val);
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
return devdata->set_average(priv, val);
default:
return -EINVAL;
}
ret = rtq6056_adc_set_samp_freq(priv, chan, val);
break;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
ret = devdata->set_average(priv, val);
break;
default:
ret = -EINVAL;
break;
}
iio_device_release_direct_mode(indio_dev);
return ret;
unreachable();
}
static const char *rtq6056_channel_labels[RTQ6056_MAX_CHANNEL] = {

View File

@ -1408,7 +1408,7 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
struct stm32_adc *adc = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
const struct stm32_adc_regspec *regs = adc->cfg->regs;
long timeout;
long time_left;
u32 val;
int ret;
@ -1440,12 +1440,12 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
adc->cfg->start_conv(indio_dev, false);
timeout = wait_for_completion_interruptible_timeout(
time_left = wait_for_completion_interruptible_timeout(
&adc->completion, STM32_ADC_TIMEOUT);
if (timeout == 0) {
if (time_left == 0) {
ret = -ETIMEDOUT;
} else if (timeout < 0) {
ret = timeout;
} else if (time_left < 0) {
ret = time_left;
} else {
*res = adc->buffer[0];
ret = IIO_VAL_INT;

View File

@ -1116,7 +1116,7 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *res)
{
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
long timeout;
long time_left;
int ret;
reinit_completion(&adc->completion);
@ -1141,17 +1141,17 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev,
goto stop_dfsdm;
}
timeout = wait_for_completion_interruptible_timeout(&adc->completion,
DFSDM_TIMEOUT);
time_left = wait_for_completion_interruptible_timeout(&adc->completion,
DFSDM_TIMEOUT);
/* Mask IRQ for regular conversion achievement*/
regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id),
DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0));
if (timeout == 0)
if (time_left == 0)
ret = -ETIMEDOUT;
else if (timeout < 0)
ret = timeout;
else if (time_left < 0)
ret = time_left;
else
ret = IIO_VAL_INT;

View File

@ -902,10 +902,9 @@ static int ads1015_client_get_channels_config(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ads1015_data *data = iio_priv(indio_dev);
struct device *dev = &client->dev;
struct fwnode_handle *node;
int i = -1;
device_for_each_child_node(dev, node) {
device_for_each_child_node_scoped(dev, node) {
u32 pval;
unsigned int channel;
unsigned int pga = ADS1015_DEFAULT_PGA;
@ -927,7 +926,6 @@ static int ads1015_client_get_channels_config(struct i2c_client *client)
pga = pval;
if (pga > 5) {
dev_err(dev, "invalid gain on %pfw\n", node);
fwnode_handle_put(node);
return -EINVAL;
}
}
@ -936,7 +934,6 @@ static int ads1015_client_get_channels_config(struct i2c_client *client)
data_rate = pval;
if (data_rate > 7) {
dev_err(dev, "invalid data_rate on %pfw\n", node);
fwnode_handle_put(node);
return -EINVAL;
}
}

View File

@ -519,7 +519,7 @@ static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev,
{
struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev);
int ret;
long timeout;
long time_left;
mutex_lock(&gpadc->lock);
@ -529,12 +529,12 @@ static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev,
goto err;
}
/* wait for conversion to complete */
timeout = wait_for_completion_interruptible_timeout(
time_left = wait_for_completion_interruptible_timeout(
&gpadc->irq_complete, msecs_to_jiffies(5000));
if (timeout == 0) {
if (time_left == 0) {
ret = -ETIMEDOUT;
goto err;
} else if (timeout < 0) {
} else if (time_left < 0) {
ret = -EINTR;
goto err;
}

View File

@ -70,13 +70,13 @@ int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts,
}
EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_update_odr, IIO_INV_SENSORS_TIMESTAMP);
static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period, uint32_t mult)
static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period)
{
uint32_t period_min, period_max;
/* check that period is acceptable */
period_min = ts->min_period * mult;
period_max = ts->max_period * mult;
period_min = ts->min_period * ts->mult;
period_max = ts->max_period * ts->mult;
if (period > period_min && period < period_max)
return true;
else
@ -84,15 +84,15 @@ static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t perio
}
static bool inv_update_chip_period(struct inv_sensors_timestamp *ts,
uint32_t mult, uint32_t period)
uint32_t period)
{
uint32_t new_chip_period;
if (!inv_validate_period(ts, period, mult))
if (!inv_validate_period(ts, period))
return false;
/* update chip internal period estimation */
new_chip_period = period / mult;
new_chip_period = period / ts->mult;
inv_update_acc(&ts->chip_period, new_chip_period);
ts->period = ts->mult * ts->chip_period.val;
@ -101,6 +101,9 @@ static bool inv_update_chip_period(struct inv_sensors_timestamp *ts,
static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts)
{
const int64_t period_min = ts->min_period * ts->mult;
const int64_t period_max = ts->max_period * ts->mult;
int64_t add_max, sub_max;
int64_t delta, jitter;
int64_t adjust;
@ -108,11 +111,13 @@ static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts)
delta = ts->it.lo - ts->timestamp;
/* adjust timestamp while respecting jitter */
add_max = period_max - (int64_t)ts->period;
sub_max = period_min - (int64_t)ts->period;
jitter = INV_SENSORS_TIMESTAMP_JITTER((int64_t)ts->period, ts->chip.jitter);
if (delta > jitter)
adjust = jitter;
adjust = add_max;
else if (delta < -jitter)
adjust = -jitter;
adjust = sub_max;
else
adjust = 0;
@ -120,16 +125,14 @@ static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts)
}
void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts,
uint32_t fifo_period, size_t fifo_nb,
size_t sensor_nb, int64_t timestamp)
size_t sample_nb, int64_t timestamp)
{
struct inv_sensors_timestamp_interval *it;
int64_t delta, interval;
const uint32_t fifo_mult = fifo_period / ts->chip.clock_period;
uint32_t period;
bool valid = false;
if (fifo_nb == 0)
if (sample_nb == 0)
return;
/* update interrupt timestamp and compute chip and sensor periods */
@ -139,14 +142,14 @@ void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts,
delta = it->up - it->lo;
if (it->lo != 0) {
/* compute period: delta time divided by number of samples */
period = div_s64(delta, fifo_nb);
valid = inv_update_chip_period(ts, fifo_mult, period);
period = div_s64(delta, sample_nb);
valid = inv_update_chip_period(ts, period);
}
/* no previous data, compute theoritical value from interrupt */
if (ts->timestamp == 0) {
/* elapsed time: sensor period * sensor samples number */
interval = (int64_t)ts->period * (int64_t)sensor_nb;
interval = (int64_t)ts->period * (int64_t)sample_nb;
ts->timestamp = it->up - interval;
return;
}

View File

@ -45,6 +45,7 @@
#define AD9739A_REG_MU_DUTY 0x25
#define AD9739A_REG_MU_CNT1 0x26
#define AD9739A_MU_EN_MASK BIT(0)
#define AD9739A_MU_GAIN_MASK BIT(1)
#define AD9739A_REG_MU_CNT2 0x27
#define AD9739A_REG_MU_CNT3 0x28
#define AD9739A_REG_MU_CNT4 0x29
@ -220,8 +221,8 @@ static int ad9739a_init(struct device *dev, const struct ad9739a_state *st)
return ret;
/* Enable the Mu controller search and track mode. */
ret = regmap_set_bits(st->regmap, AD9739A_REG_MU_CNT1,
AD9739A_MU_EN_MASK);
ret = regmap_write(st->regmap, AD9739A_REG_MU_CNT1,
AD9739A_MU_EN_MASK | AD9739A_MU_GAIN_MASK);
if (ret)
return ret;

View File

@ -383,15 +383,15 @@ static int axi_dac_ext_info_set(struct iio_backend *back, uintptr_t private,
case AXI_DAC_FREQ_TONE_1:
case AXI_DAC_FREQ_TONE_2:
return axi_dac_frequency_set(st, chan, buf, len,
private - AXI_DAC_FREQ_TONE_1);
private == AXI_DAC_FREQ_TONE_2);
case AXI_DAC_SCALE_TONE_1:
case AXI_DAC_SCALE_TONE_2:
return axi_dac_scale_set(st, chan, buf, len,
private - AXI_DAC_SCALE_TONE_1);
private == AXI_DAC_SCALE_TONE_2);
case AXI_DAC_PHASE_TONE_1:
case AXI_DAC_PHASE_TONE_2:
return axi_dac_phase_set(st, chan, buf, len,
private - AXI_DAC_PHASE_TONE_2);
private == AXI_DAC_PHASE_TONE_2);
default:
return -EOPNOTSUPP;
}

View File

@ -13,6 +13,7 @@
#include <linux/regulator/consumer.h>
#include <linux/pm.h>
#include <linux/iio/iio.h>
#include <linux/iio/common/inv_sensors_timestamp.h>
#include "inv_icm42600_buffer.h"
@ -21,6 +22,7 @@ enum inv_icm42600_chip {
INV_CHIP_ICM42600,
INV_CHIP_ICM42602,
INV_CHIP_ICM42605,
INV_CHIP_ICM42686,
INV_CHIP_ICM42622,
INV_CHIP_ICM42688,
INV_CHIP_ICM42631,
@ -57,6 +59,17 @@ enum inv_icm42600_gyro_fs {
INV_ICM42600_GYRO_FS_15_625DPS,
INV_ICM42600_GYRO_FS_NB,
};
enum inv_icm42686_gyro_fs {
INV_ICM42686_GYRO_FS_4000DPS,
INV_ICM42686_GYRO_FS_2000DPS,
INV_ICM42686_GYRO_FS_1000DPS,
INV_ICM42686_GYRO_FS_500DPS,
INV_ICM42686_GYRO_FS_250DPS,
INV_ICM42686_GYRO_FS_125DPS,
INV_ICM42686_GYRO_FS_62_5DPS,
INV_ICM42686_GYRO_FS_31_25DPS,
INV_ICM42686_GYRO_FS_NB,
};
/* accelerometer fullscale values */
enum inv_icm42600_accel_fs {
@ -66,6 +79,14 @@ enum inv_icm42600_accel_fs {
INV_ICM42600_ACCEL_FS_2G,
INV_ICM42600_ACCEL_FS_NB,
};
enum inv_icm42686_accel_fs {
INV_ICM42686_ACCEL_FS_32G,
INV_ICM42686_ACCEL_FS_16G,
INV_ICM42686_ACCEL_FS_8G,
INV_ICM42686_ACCEL_FS_4G,
INV_ICM42686_ACCEL_FS_2G,
INV_ICM42686_ACCEL_FS_NB,
};
/* ODR suffixed by LN or LP are Low-Noise or Low-Power mode only */
enum inv_icm42600_odr {
@ -151,6 +172,19 @@ struct inv_icm42600_state {
} timestamp;
};
/**
* struct inv_icm42600_sensor_state - sensor state variables
* @scales: table of scales.
* @scales_len: length (nb of items) of the scales table.
* @ts: timestamp module states.
*/
struct inv_icm42600_sensor_state {
const int *scales;
size_t scales_len;
struct inv_sensors_timestamp ts;
};
/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
/* Bank selection register, available in all banks */
@ -304,6 +338,7 @@ struct inv_icm42600_state {
#define INV_ICM42600_WHOAMI_ICM42600 0x40
#define INV_ICM42600_WHOAMI_ICM42602 0x41
#define INV_ICM42600_WHOAMI_ICM42605 0x42
#define INV_ICM42600_WHOAMI_ICM42686 0x44
#define INV_ICM42600_WHOAMI_ICM42622 0x46
#define INV_ICM42600_WHOAMI_ICM42688 0x47
#define INV_ICM42600_WHOAMI_ICM42631 0x5C

View File

@ -99,7 +99,8 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
struct inv_sensors_timestamp *ts = &accel_st->ts;
struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
unsigned int fifo_en = 0;
unsigned int sleep_temp = 0;
@ -210,33 +211,54 @@ static const int inv_icm42600_accel_scale[] = {
[2 * INV_ICM42600_ACCEL_FS_2G] = 0,
[2 * INV_ICM42600_ACCEL_FS_2G + 1] = 598550,
};
static const int inv_icm42686_accel_scale[] = {
/* +/- 32G => 0.009576807 m/s-2 */
[2 * INV_ICM42686_ACCEL_FS_32G] = 0,
[2 * INV_ICM42686_ACCEL_FS_32G + 1] = 9576807,
/* +/- 16G => 0.004788403 m/s-2 */
[2 * INV_ICM42686_ACCEL_FS_16G] = 0,
[2 * INV_ICM42686_ACCEL_FS_16G + 1] = 4788403,
/* +/- 8G => 0.002394202 m/s-2 */
[2 * INV_ICM42686_ACCEL_FS_8G] = 0,
[2 * INV_ICM42686_ACCEL_FS_8G + 1] = 2394202,
/* +/- 4G => 0.001197101 m/s-2 */
[2 * INV_ICM42686_ACCEL_FS_4G] = 0,
[2 * INV_ICM42686_ACCEL_FS_4G + 1] = 1197101,
/* +/- 2G => 0.000598550 m/s-2 */
[2 * INV_ICM42686_ACCEL_FS_2G] = 0,
[2 * INV_ICM42686_ACCEL_FS_2G + 1] = 598550,
};
static int inv_icm42600_accel_read_scale(struct inv_icm42600_state *st,
static int inv_icm42600_accel_read_scale(struct iio_dev *indio_dev,
int *val, int *val2)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
unsigned int idx;
idx = st->conf.accel.fs;
*val = inv_icm42600_accel_scale[2 * idx];
*val2 = inv_icm42600_accel_scale[2 * idx + 1];
*val = accel_st->scales[2 * idx];
*val2 = accel_st->scales[2 * idx + 1];
return IIO_VAL_INT_PLUS_NANO;
}
static int inv_icm42600_accel_write_scale(struct inv_icm42600_state *st,
static int inv_icm42600_accel_write_scale(struct iio_dev *indio_dev,
int val, int val2)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
struct device *dev = regmap_get_device(st->map);
unsigned int idx;
struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
int ret;
for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_accel_scale); idx += 2) {
if (val == inv_icm42600_accel_scale[idx] &&
val2 == inv_icm42600_accel_scale[idx + 1])
for (idx = 0; idx < accel_st->scales_len; idx += 2) {
if (val == accel_st->scales[idx] &&
val2 == accel_st->scales[idx + 1])
break;
}
if (idx >= ARRAY_SIZE(inv_icm42600_accel_scale))
if (idx >= accel_st->scales_len)
return -EINVAL;
conf.fs = idx / 2;
@ -309,7 +331,8 @@ static int inv_icm42600_accel_write_odr(struct iio_dev *indio_dev,
int val, int val2)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
struct inv_sensors_timestamp *ts = &accel_st->ts;
struct device *dev = regmap_get_device(st->map);
unsigned int idx;
struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
@ -565,7 +588,7 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev,
*val = data;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
return inv_icm42600_accel_read_scale(st, val, val2);
return inv_icm42600_accel_read_scale(indio_dev, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
return inv_icm42600_accel_read_odr(st, val, val2);
case IIO_CHAN_INFO_CALIBBIAS:
@ -580,14 +603,16 @@ static int inv_icm42600_accel_read_avail(struct iio_dev *indio_dev,
const int **vals,
int *type, int *length, long mask)
{
struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
if (chan->type != IIO_ACCEL)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
*vals = inv_icm42600_accel_scale;
*vals = accel_st->scales;
*type = IIO_VAL_INT_PLUS_NANO;
*length = ARRAY_SIZE(inv_icm42600_accel_scale);
*length = accel_st->scales_len;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_SAMP_FREQ:
*vals = inv_icm42600_accel_odr;
@ -618,7 +643,7 @@ static int inv_icm42600_accel_write_raw(struct iio_dev *indio_dev,
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = inv_icm42600_accel_write_scale(st, val, val2);
ret = inv_icm42600_accel_write_scale(indio_dev, val, val2);
iio_device_release_direct_mode(indio_dev);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
@ -705,8 +730,8 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
{
struct device *dev = regmap_get_device(st->map);
const char *name;
struct inv_icm42600_sensor_state *accel_st;
struct inv_sensors_timestamp_chip ts_chip;
struct inv_sensors_timestamp *ts;
struct iio_dev *indio_dev;
int ret;
@ -714,9 +739,21 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
if (!name)
return ERR_PTR(-ENOMEM);
indio_dev = devm_iio_device_alloc(dev, sizeof(*ts));
indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st));
if (!indio_dev)
return ERR_PTR(-ENOMEM);
accel_st = iio_priv(indio_dev);
switch (st->chip) {
case INV_CHIP_ICM42686:
accel_st->scales = inv_icm42686_accel_scale;
accel_st->scales_len = ARRAY_SIZE(inv_icm42686_accel_scale);
break;
default:
accel_st->scales = inv_icm42600_accel_scale;
accel_st->scales_len = ARRAY_SIZE(inv_icm42600_accel_scale);
break;
}
/*
* clock period is 32kHz (31250ns)
@ -725,8 +762,7 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
ts_chip.clock_period = 31250;
ts_chip.jitter = 20;
ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
ts = iio_priv(indio_dev);
inv_sensors_timestamp_init(ts, &ts_chip);
inv_sensors_timestamp_init(&accel_st->ts, &ts_chip);
iio_device_set_drvdata(indio_dev, st);
indio_dev->name = name;
@ -751,7 +787,8 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
struct inv_sensors_timestamp *ts = &accel_st->ts;
ssize_t i, size;
unsigned int no;
const void *accel, *gyro, *timestamp;

View File

@ -276,7 +276,8 @@ static int inv_icm42600_buffer_preenable(struct iio_dev *indio_dev)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct device *dev = regmap_get_device(st->map);
struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
struct inv_icm42600_sensor_state *sensor_st = iio_priv(indio_dev);
struct inv_sensors_timestamp *ts = &sensor_st->ts;
pm_runtime_get_sync(dev);
@ -502,6 +503,8 @@ int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st)
{
struct inv_icm42600_sensor_state *gyro_st = iio_priv(st->indio_gyro);
struct inv_icm42600_sensor_state *accel_st = iio_priv(st->indio_accel);
struct inv_sensors_timestamp *ts;
int ret;
@ -509,20 +512,20 @@ int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st)
return 0;
/* handle gyroscope timestamp and FIFO data parsing */
ts = iio_priv(st->indio_gyro);
inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total,
st->fifo.nb.gyro, st->timestamp.gyro);
if (st->fifo.nb.gyro > 0) {
ts = &gyro_st->ts;
inv_sensors_timestamp_interrupt(ts, st->fifo.nb.gyro,
st->timestamp.gyro);
ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro);
if (ret)
return ret;
}
/* handle accelerometer timestamp and FIFO data parsing */
ts = iio_priv(st->indio_accel);
inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total,
st->fifo.nb.accel, st->timestamp.accel);
if (st->fifo.nb.accel > 0) {
ts = &accel_st->ts;
inv_sensors_timestamp_interrupt(ts, st->fifo.nb.accel,
st->timestamp.accel);
ret = inv_icm42600_accel_parse_fifo(st->indio_accel);
if (ret)
return ret;
@ -534,6 +537,8 @@ int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st)
int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st,
unsigned int count)
{
struct inv_icm42600_sensor_state *gyro_st = iio_priv(st->indio_gyro);
struct inv_icm42600_sensor_state *accel_st = iio_priv(st->indio_accel);
struct inv_sensors_timestamp *ts;
int64_t gyro_ts, accel_ts;
int ret;
@ -549,20 +554,16 @@ int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st,
return 0;
if (st->fifo.nb.gyro > 0) {
ts = iio_priv(st->indio_gyro);
inv_sensors_timestamp_interrupt(ts, st->fifo.period,
st->fifo.nb.total, st->fifo.nb.gyro,
gyro_ts);
ts = &gyro_st->ts;
inv_sensors_timestamp_interrupt(ts, st->fifo.nb.gyro, gyro_ts);
ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro);
if (ret)
return ret;
}
if (st->fifo.nb.accel > 0) {
ts = iio_priv(st->indio_accel);
inv_sensors_timestamp_interrupt(ts, st->fifo.period,
st->fifo.nb.total, st->fifo.nb.accel,
accel_ts);
ts = &accel_st->ts;
inv_sensors_timestamp_interrupt(ts, st->fifo.nb.accel, accel_ts);
ret = inv_icm42600_accel_parse_fifo(st->indio_accel);
if (ret)
return ret;

View File

@ -66,6 +66,22 @@ static const struct inv_icm42600_conf inv_icm42600_default_conf = {
.temp_en = false,
};
static const struct inv_icm42600_conf inv_icm42686_default_conf = {
.gyro = {
.mode = INV_ICM42600_SENSOR_MODE_OFF,
.fs = INV_ICM42686_GYRO_FS_4000DPS,
.odr = INV_ICM42600_ODR_50HZ,
.filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
},
.accel = {
.mode = INV_ICM42600_SENSOR_MODE_OFF,
.fs = INV_ICM42686_ACCEL_FS_32G,
.odr = INV_ICM42600_ODR_50HZ,
.filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
},
.temp_en = false,
};
static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = {
[INV_CHIP_ICM42600] = {
.whoami = INV_ICM42600_WHOAMI_ICM42600,
@ -82,6 +98,11 @@ static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = {
.name = "icm42605",
.conf = &inv_icm42600_default_conf,
},
[INV_CHIP_ICM42686] = {
.whoami = INV_ICM42600_WHOAMI_ICM42686,
.name = "icm42686",
.conf = &inv_icm42686_default_conf,
},
[INV_CHIP_ICM42622] = {
.whoami = INV_ICM42600_WHOAMI_ICM42622,
.name = "icm42622",

View File

@ -99,7 +99,8 @@ static int inv_icm42600_gyro_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
struct inv_sensors_timestamp *ts = &gyro_st->ts;
struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
unsigned int fifo_en = 0;
unsigned int sleep_gyro = 0;
@ -222,33 +223,63 @@ static const int inv_icm42600_gyro_scale[] = {
[2 * INV_ICM42600_GYRO_FS_15_625DPS] = 0,
[2 * INV_ICM42600_GYRO_FS_15_625DPS + 1] = 8322,
};
static const int inv_icm42686_gyro_scale[] = {
/* +/- 4000dps => 0.002130529 rad/s */
[2 * INV_ICM42686_GYRO_FS_4000DPS] = 0,
[2 * INV_ICM42686_GYRO_FS_4000DPS + 1] = 2130529,
/* +/- 2000dps => 0.001065264 rad/s */
[2 * INV_ICM42686_GYRO_FS_2000DPS] = 0,
[2 * INV_ICM42686_GYRO_FS_2000DPS + 1] = 1065264,
/* +/- 1000dps => 0.000532632 rad/s */
[2 * INV_ICM42686_GYRO_FS_1000DPS] = 0,
[2 * INV_ICM42686_GYRO_FS_1000DPS + 1] = 532632,
/* +/- 500dps => 0.000266316 rad/s */
[2 * INV_ICM42686_GYRO_FS_500DPS] = 0,
[2 * INV_ICM42686_GYRO_FS_500DPS + 1] = 266316,
/* +/- 250dps => 0.000133158 rad/s */
[2 * INV_ICM42686_GYRO_FS_250DPS] = 0,
[2 * INV_ICM42686_GYRO_FS_250DPS + 1] = 133158,
/* +/- 125dps => 0.000066579 rad/s */
[2 * INV_ICM42686_GYRO_FS_125DPS] = 0,
[2 * INV_ICM42686_GYRO_FS_125DPS + 1] = 66579,
/* +/- 62.5dps => 0.000033290 rad/s */
[2 * INV_ICM42686_GYRO_FS_62_5DPS] = 0,
[2 * INV_ICM42686_GYRO_FS_62_5DPS + 1] = 33290,
/* +/- 31.25dps => 0.000016645 rad/s */
[2 * INV_ICM42686_GYRO_FS_31_25DPS] = 0,
[2 * INV_ICM42686_GYRO_FS_31_25DPS + 1] = 16645,
};
static int inv_icm42600_gyro_read_scale(struct inv_icm42600_state *st,
static int inv_icm42600_gyro_read_scale(struct iio_dev *indio_dev,
int *val, int *val2)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
unsigned int idx;
idx = st->conf.gyro.fs;
*val = inv_icm42600_gyro_scale[2 * idx];
*val2 = inv_icm42600_gyro_scale[2 * idx + 1];
*val = gyro_st->scales[2 * idx];
*val2 = gyro_st->scales[2 * idx + 1];
return IIO_VAL_INT_PLUS_NANO;
}
static int inv_icm42600_gyro_write_scale(struct inv_icm42600_state *st,
static int inv_icm42600_gyro_write_scale(struct iio_dev *indio_dev,
int val, int val2)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
struct device *dev = regmap_get_device(st->map);
unsigned int idx;
struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
int ret;
for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_gyro_scale); idx += 2) {
if (val == inv_icm42600_gyro_scale[idx] &&
val2 == inv_icm42600_gyro_scale[idx + 1])
for (idx = 0; idx < gyro_st->scales_len; idx += 2) {
if (val == gyro_st->scales[idx] &&
val2 == gyro_st->scales[idx + 1])
break;
}
if (idx >= ARRAY_SIZE(inv_icm42600_gyro_scale))
if (idx >= gyro_st->scales_len)
return -EINVAL;
conf.fs = idx / 2;
@ -321,7 +352,8 @@ static int inv_icm42600_gyro_write_odr(struct iio_dev *indio_dev,
int val, int val2)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
struct inv_sensors_timestamp *ts = &gyro_st->ts;
struct device *dev = regmap_get_device(st->map);
unsigned int idx;
struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
@ -576,7 +608,7 @@ static int inv_icm42600_gyro_read_raw(struct iio_dev *indio_dev,
*val = data;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
return inv_icm42600_gyro_read_scale(st, val, val2);
return inv_icm42600_gyro_read_scale(indio_dev, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
return inv_icm42600_gyro_read_odr(st, val, val2);
case IIO_CHAN_INFO_CALIBBIAS:
@ -591,14 +623,16 @@ static int inv_icm42600_gyro_read_avail(struct iio_dev *indio_dev,
const int **vals,
int *type, int *length, long mask)
{
struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
if (chan->type != IIO_ANGL_VEL)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
*vals = inv_icm42600_gyro_scale;
*vals = gyro_st->scales;
*type = IIO_VAL_INT_PLUS_NANO;
*length = ARRAY_SIZE(inv_icm42600_gyro_scale);
*length = gyro_st->scales_len;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_SAMP_FREQ:
*vals = inv_icm42600_gyro_odr;
@ -629,7 +663,7 @@ static int inv_icm42600_gyro_write_raw(struct iio_dev *indio_dev,
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = inv_icm42600_gyro_write_scale(st, val, val2);
ret = inv_icm42600_gyro_write_scale(indio_dev, val, val2);
iio_device_release_direct_mode(indio_dev);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
@ -716,8 +750,8 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
{
struct device *dev = regmap_get_device(st->map);
const char *name;
struct inv_icm42600_sensor_state *gyro_st;
struct inv_sensors_timestamp_chip ts_chip;
struct inv_sensors_timestamp *ts;
struct iio_dev *indio_dev;
int ret;
@ -725,9 +759,21 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
if (!name)
return ERR_PTR(-ENOMEM);
indio_dev = devm_iio_device_alloc(dev, sizeof(*ts));
indio_dev = devm_iio_device_alloc(dev, sizeof(*gyro_st));
if (!indio_dev)
return ERR_PTR(-ENOMEM);
gyro_st = iio_priv(indio_dev);
switch (st->chip) {
case INV_CHIP_ICM42686:
gyro_st->scales = inv_icm42686_gyro_scale;
gyro_st->scales_len = ARRAY_SIZE(inv_icm42686_gyro_scale);
break;
default:
gyro_st->scales = inv_icm42600_gyro_scale;
gyro_st->scales_len = ARRAY_SIZE(inv_icm42600_gyro_scale);
break;
}
/*
* clock period is 32kHz (31250ns)
@ -736,8 +782,7 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
ts_chip.clock_period = 31250;
ts_chip.jitter = 20;
ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
ts = iio_priv(indio_dev);
inv_sensors_timestamp_init(ts, &ts_chip);
inv_sensors_timestamp_init(&gyro_st->ts, &ts_chip);
iio_device_set_drvdata(indio_dev, st);
indio_dev->name = name;
@ -763,7 +808,8 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
struct inv_sensors_timestamp *ts = &gyro_st->ts;
ssize_t i, size;
unsigned int no;
const void *accel, *gyro, *timestamp;

View File

@ -81,6 +81,9 @@ static const struct of_device_id inv_icm42600_of_matches[] = {
}, {
.compatible = "invensense,icm42605",
.data = (void *)INV_CHIP_ICM42605,
}, {
.compatible = "invensense,icm42686",
.data = (void *)INV_CHIP_ICM42686,
}, {
.compatible = "invensense,icm42622",
.data = (void *)INV_CHIP_ICM42622,

View File

@ -77,6 +77,9 @@ static const struct of_device_id inv_icm42600_of_matches[] = {
}, {
.compatible = "invensense,icm42605",
.data = (void *)INV_CHIP_ICM42605,
}, {
.compatible = "invensense,icm42686",
.data = (void *)INV_CHIP_ICM42686,
}, {
.compatible = "invensense,icm42622",
.data = (void *)INV_CHIP_ICM42622,

View File

@ -100,7 +100,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
goto end_session;
/* Each FIFO data contains all sensors, so same number for FIFO and sensor data */
fifo_period = NSEC_PER_SEC / INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider);
inv_sensors_timestamp_interrupt(&st->timestamp, fifo_period, nb, nb, pf->timestamp);
inv_sensors_timestamp_interrupt(&st->timestamp, nb, pf->timestamp);
inv_sensors_timestamp_apply_odr(&st->timestamp, fifo_period, nb, 0);
/* clear internal data buffer for avoiding kernel data leak */

View File

@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0-only
/* IIO ACPI helper functions */
#include <linux/acpi.h>
#include <linux/dev_printk.h>
#include <linux/iio/iio.h>
#include <linux/sprintf.h>
/**
* iio_read_acpi_mount_matrix() - Read accelerometer mount matrix info from ACPI
* @dev: Device structure
* @orientation: iio_mount_matrix struct to fill
* @acpi_method: ACPI method name to read the matrix from, usually "ROTM"
*
* Try to read the mount-matrix by calling the specified method on the device's
* ACPI firmware-node. If the device has no ACPI firmware-node; or the method
* does not exist then this will fail silently. This expects the method to
* return data in the ACPI "ROTM" format defined by Microsoft:
* https://learn.microsoft.com/en-us/windows-hardware/drivers/sensors/sensors-acpi-entries
* This is a Microsoft extension and not part of the official ACPI spec.
* The method name is configurable because some dual-accel setups define 2 mount
* matrices in a single ACPI device using separate "ROMK" and "ROMS" methods.
*
* Returns: true if the matrix was successfully, false otherwise.
*/
bool iio_read_acpi_mount_matrix(struct device *dev,
struct iio_mount_matrix *orientation,
char *acpi_method)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_device *adev = ACPI_COMPANION(dev);
char *str;
union acpi_object *obj, *elements;
acpi_status status;
int i, j, val[3];
bool ret = false;
if (!adev || !acpi_has_method(adev->handle, acpi_method))
return false;
status = acpi_evaluate_object(adev->handle, acpi_method, NULL, &buffer);
if (ACPI_FAILURE(status)) {
dev_err(dev, "Failed to get ACPI mount matrix: %d\n", status);
return false;
}
obj = buffer.pointer;
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) {
dev_err(dev, "Unknown ACPI mount matrix package format\n");
goto out_free_buffer;
}
elements = obj->package.elements;
for (i = 0; i < 3; i++) {
if (elements[i].type != ACPI_TYPE_STRING) {
dev_err(dev, "Unknown ACPI mount matrix element format\n");
goto out_free_buffer;
}
str = elements[i].string.pointer;
if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) {
dev_err(dev, "Incorrect ACPI mount matrix string format\n");
goto out_free_buffer;
}
for (j = 0; j < 3; j++) {
switch (val[j]) {
case -1: str = "-1"; break;
case 0: str = "0"; break;
case 1: str = "1"; break;
default:
dev_err(dev, "Invalid value in ACPI mount matrix: %d\n", val[j]);
goto out_free_buffer;
}
orientation->rotation[i * 3 + j] = str;
}
}
ret = true;
out_free_buffer:
kfree(buffer.pointer);
return ret;
}
EXPORT_SYMBOL_GPL(iio_read_acpi_mount_matrix);

View File

@ -115,8 +115,8 @@ static DEFINE_MUTEX(iio_back_lock);
/**
* iio_backend_chan_enable - Enable a backend channel
* @back: Backend device
* @chan: Channel number
* @back: Backend device
* @chan: Channel number
*
* RETURNS:
* 0 on success, negative error number on failure.
@ -129,8 +129,8 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_chan_enable, IIO_BACKEND);
/**
* iio_backend_chan_disable - Disable a backend channel
* @back: Backend device
* @chan: Channel number
* @back: Backend device
* @chan: Channel number
*
* RETURNS:
* 0 on success, negative error number on failure.
@ -148,8 +148,8 @@ static void __iio_backend_disable(void *back)
/**
* devm_iio_backend_enable - Device managed backend enable
* @dev: Consumer device for the backend
* @back: Backend device
* @dev: Consumer device for the backend
* @back: Backend device
*
* RETURNS:
* 0 on success, negative error number on failure.
@ -168,9 +168,9 @@ EXPORT_SYMBOL_NS_GPL(devm_iio_backend_enable, IIO_BACKEND);
/**
* iio_backend_data_format_set - Configure the channel data format
* @back: Backend device
* @chan: Channel number
* @data: Data format
* @back: Backend device
* @chan: Channel number
* @data: Data format
*
* Properly configure a channel with respect to the expected data format. A
* @struct iio_backend_data_fmt must be passed with the settings.
@ -190,9 +190,9 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND);
/**
* iio_backend_data_source_set - Select data source
* @back: Backend device
* @chan: Channel number
* @data: Data source
* @back: Backend device
* @chan: Channel number
* @data: Data source
*
* A given backend may have different sources to stream/sync data. This allows
* to choose that source.
@ -212,9 +212,9 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_set, IIO_BACKEND);
/**
* iio_backend_set_sampling_freq - Set channel sampling rate
* @back: Backend device
* @chan: Channel number
* @sample_rate_hz: Sample rate
* @back: Backend device
* @chan: Channel number
* @sample_rate_hz: Sample rate
*
* RETURNS:
* 0 on success, negative error number on failure.
@ -226,6 +226,92 @@ int iio_backend_set_sampling_freq(struct iio_backend *back, unsigned int chan,
}
EXPORT_SYMBOL_NS_GPL(iio_backend_set_sampling_freq, IIO_BACKEND);
/**
* iio_backend_test_pattern_set - Configure a test pattern
* @back: Backend device
* @chan: Channel number
* @pattern: Test pattern
*
* Configure a test pattern on the backend. This is typically used for
* calibrating the timings on the data digital interface.
*
* RETURNS:
* 0 on success, negative error number on failure.
*/
int iio_backend_test_pattern_set(struct iio_backend *back,
unsigned int chan,
enum iio_backend_test_pattern pattern)
{
if (pattern >= IIO_BACKEND_TEST_PATTERN_MAX)
return -EINVAL;
return iio_backend_op_call(back, test_pattern_set, chan, pattern);
}
EXPORT_SYMBOL_NS_GPL(iio_backend_test_pattern_set, IIO_BACKEND);
/**
* iio_backend_chan_status - Get the channel status
* @back: Backend device
* @chan: Channel number
* @error: Error indication
*
* Get the current state of the backend channel. Typically used to check if
* there were any errors sending/receiving data.
*
* RETURNS:
* 0 on success, negative error number on failure.
*/
int iio_backend_chan_status(struct iio_backend *back, unsigned int chan,
bool *error)
{
return iio_backend_op_call(back, chan_status, chan, error);
}
EXPORT_SYMBOL_NS_GPL(iio_backend_chan_status, IIO_BACKEND);
/**
* iio_backend_iodelay_set - Set digital I/O delay
* @back: Backend device
* @lane: Lane number
* @taps: Number of taps
*
* Controls delays on sending/receiving data. One usecase for this is to
* calibrate the data digital interface so we get the best results when
* transferring data. Note that @taps has no unit since the actual delay per tap
* is very backend specific. Hence, frontend devices typically should go through
* an array of @taps (the size of that array should typically match the size of
* calibration points on the frontend device) and call this API.
*
* RETURNS:
* 0 on success, negative error number on failure.
*/
int iio_backend_iodelay_set(struct iio_backend *back, unsigned int lane,
unsigned int taps)
{
return iio_backend_op_call(back, iodelay_set, lane, taps);
}
EXPORT_SYMBOL_NS_GPL(iio_backend_iodelay_set, IIO_BACKEND);
/**
* iio_backend_data_sample_trigger - Control when to sample data
* @back: Backend device
* @trigger: Data trigger
*
* Mostly useful for input backends. Configures the backend for when to sample
* data (eg: rising vs falling edge).
*
* RETURNS:
* 0 on success, negative error number on failure.
*/
int iio_backend_data_sample_trigger(struct iio_backend *back,
enum iio_backend_sample_trigger trigger)
{
if (trigger >= IIO_BACKEND_SAMPLE_TRIGGER_MAX)
return -EINVAL;
return iio_backend_op_call(back, data_sample_trigger, trigger);
}
EXPORT_SYMBOL_NS_GPL(iio_backend_data_sample_trigger, IIO_BACKEND);
static void iio_backend_free_buffer(void *arg)
{
struct iio_backend_buffer_pair *pair = arg;
@ -235,9 +321,9 @@ static void iio_backend_free_buffer(void *arg)
/**
* devm_iio_backend_request_buffer - Device managed buffer request
* @dev: Consumer device for the backend
* @back: Backend device
* @indio_dev: IIO device
* @dev: Consumer device for the backend
* @back: Backend device
* @indio_dev: IIO device
*
* Request an IIO buffer from the backend. The type of the buffer (typically
* INDIO_BUFFER_HARDWARE) is up to the backend to decide. This is because,
@ -300,10 +386,10 @@ static struct iio_backend *iio_backend_from_indio_dev_parent(const struct device
/**
* iio_backend_ext_info_get - IIO ext_info read callback
* @indio_dev: IIO device
* @private: Data private to the driver
* @chan: IIO channel
* @buf: Buffer where to place the attribute data
* @indio_dev: IIO device
* @private: Data private to the driver
* @chan: IIO channel
* @buf: Buffer where to place the attribute data
*
* This helper is intended to be used by backends that extend an IIO channel
* (through iio_backend_extend_chan_spec()) with extended info. In that case,
@ -335,11 +421,11 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_get, IIO_BACKEND);
/**
* iio_backend_ext_info_set - IIO ext_info write callback
* @indio_dev: IIO device
* @private: Data private to the driver
* @chan: IIO channel
* @buf: Buffer holding the sysfs attribute
* @len: Buffer length
* @indio_dev: IIO device
* @private: Data private to the driver
* @chan: IIO channel
* @buf: Buffer holding the sysfs attribute
* @len: Buffer length
*
* This helper is intended to be used by backends that extend an IIO channel
* (trough iio_backend_extend_chan_spec()) with extended info. In that case,
@ -365,9 +451,9 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_set, IIO_BACKEND);
/**
* iio_backend_extend_chan_spec - Extend an IIO channel
* @indio_dev: IIO device
* @back: Backend device
* @chan: IIO channel
* @indio_dev: IIO device
* @back: Backend device
* @chan: IIO channel
*
* Some backends may have their own functionalities and hence capable of
* extending a frontend's channel.
@ -449,8 +535,8 @@ static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back)
/**
* devm_iio_backend_get - Device managed backend device get
* @dev: Consumer device for the backend
* @name: Backend name
* @dev: Consumer device for the backend
* @name: Backend name
*
* Get's the backend associated with @dev.
*
@ -501,8 +587,8 @@ EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, IIO_BACKEND);
/**
* __devm_iio_backend_get_from_fwnode_lookup - Device managed fwnode backend device get
* @dev: Consumer device for the backend
* @fwnode: Firmware node of the backend device
* @dev: Consumer device for the backend
* @fwnode: Firmware node of the backend device
*
* Search the backend list for a device matching @fwnode.
* This API should not be used and it's only present for preventing the first
@ -536,7 +622,7 @@ EXPORT_SYMBOL_NS_GPL(__devm_iio_backend_get_from_fwnode_lookup, IIO_BACKEND);
/**
* iio_backend_get_priv - Get driver private data
* @back: Backend device
* @back: Backend device
*/
void *iio_backend_get_priv(const struct iio_backend *back)
{
@ -554,9 +640,9 @@ static void iio_backend_unregister(void *arg)
/**
* devm_iio_backend_register - Device managed backend device register
* @dev: Backend device being registered
* @ops: Backend ops
* @priv: Device private data
* @dev: Backend device being registered
* @ops: Backend ops
* @priv: Device private data
*
* @ops is mandatory. Not providing it results in -EINVAL.
*

View File

@ -1744,7 +1744,7 @@ int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
channels = indio_dev->channels;
if (channels) {
int ml = indio_dev->masklength;
int ml = 0;
for (i = 0; i < indio_dev->num_channels; i++)
ml = max(ml, channels[i].scan_index + 1);

View File

@ -55,8 +55,8 @@
#define APDS9306_ALS_DATA_STAT_MASK BIT(3)
#define APDS9306_ALS_THRES_VAL_MAX (BIT(20) - 1)
#define APDS9306_ALS_THRES_VAR_VAL_MAX (BIT(3) - 1)
#define APDS9306_ALS_PERSIST_VAL_MAX (BIT(4) - 1)
#define APDS9306_ALS_THRES_VAR_NUM_VALS 8
#define APDS9306_ALS_PERSIST_NUM_VALS 16
#define APDS9306_ALS_READ_DATA_DELAY_US (20 * USEC_PER_MSEC)
#define APDS9306_NUM_REPEAT_RATES 7
#define APDS9306_INT_SRC_CLEAR 0
@ -726,7 +726,7 @@ static int apds9306_event_period_get(struct apds9306_data *data, int *val)
if (ret)
return ret;
if (!in_range(period, 0, APDS9306_ALS_PERSIST_VAL_MAX))
if (!in_range(period, 0, APDS9306_ALS_PERSIST_NUM_VALS))
return -EINVAL;
*val = period;
@ -738,7 +738,7 @@ static int apds9306_event_period_set(struct apds9306_data *data, int val)
{
struct apds9306_regfields *rf = &data->rf;
if (!in_range(val, 0, APDS9306_ALS_PERSIST_VAL_MAX))
if (!in_range(val, 0, APDS9306_ALS_PERSIST_NUM_VALS))
return -EINVAL;
return regmap_field_write(rf->int_persist_val, val);
@ -796,7 +796,7 @@ static int apds9306_event_thresh_adaptive_get(struct apds9306_data *data, int *v
if (ret)
return ret;
if (!in_range(thr_adpt, 0, APDS9306_ALS_THRES_VAR_VAL_MAX))
if (!in_range(thr_adpt, 0, APDS9306_ALS_THRES_VAR_NUM_VALS))
return -EINVAL;
*val = thr_adpt;
@ -808,7 +808,7 @@ static int apds9306_event_thresh_adaptive_set(struct apds9306_data *data, int va
{
struct apds9306_regfields *rf = &data->rf;
if (!in_range(val, 0, APDS9306_ALS_THRES_VAR_VAL_MAX))
if (!in_range(val, 0, APDS9306_ALS_THRES_VAR_NUM_VALS))
return -EINVAL;
return regmap_field_write(rf->int_thresh_var_val, val);

View File

@ -693,7 +693,6 @@ MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
static const struct acpi_device_id stk3310_acpi_id[] = {
{"STK3310", 0},
{"STK3311", 0},
{"STK3335", 0},
{}
};

View File

@ -861,13 +861,13 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev,
struct zpa2326_private *private)
{
unsigned int val;
long timeout;
long time_left;
zpa2326_dbg(indio_dev, "waiting for one shot completion interrupt");
timeout = wait_for_completion_interruptible_timeout(
time_left = wait_for_completion_interruptible_timeout(
&private->data_ready, ZPA2326_CONVERSION_JIFFIES);
if (timeout > 0)
if (time_left > 0)
/*
* Interrupt handler completed before timeout: return operation
* status.
@ -877,10 +877,10 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev,
/* Clear all interrupts just to be sure. */
regmap_read(private->regmap, ZPA2326_INT_SOURCE_REG, &val);
if (!timeout) {
if (!time_left) {
/* Timed out. */
zpa2326_warn(indio_dev, "no one shot interrupt occurred (%ld)",
timeout);
time_left);
return -ETIME;
}

View File

@ -52,7 +52,8 @@ static int mcp9600_read(struct mcp9600_data *data,
if (ret < 0)
return ret;
*val = ret;
*val = sign_extend32(ret, 15);
return 0;
}

View File

@ -24,9 +24,9 @@ enum iio_backend_data_source {
/**
* IIO_BACKEND_EX_INFO - Helper for an IIO extended channel attribute
* @_name: Attribute name
* @_shared: Whether the attribute is shared between all channels
* @_what: Data private to the driver
* @_name: Attribute name
* @_shared: Whether the attribute is shared between all channels
* @_what: Data private to the driver
*/
#define IIO_BACKEND_EX_INFO(_name, _shared, _what) { \
.name = (_name), \
@ -38,10 +38,10 @@ enum iio_backend_data_source {
/**
* struct iio_backend_data_fmt - Backend data format
* @type: Data type.
* @sign_extend: Bool to tell if the data is sign extended.
* @enable: Enable/Disable the data format module. If disabled,
* not formatting will happen.
* @type: Data type.
* @sign_extend: Bool to tell if the data is sign extended.
* @enable: Enable/Disable the data format module. If disabled,
* not formatting will happen.
*/
struct iio_backend_data_fmt {
enum iio_backend_data_type type;
@ -49,20 +49,38 @@ struct iio_backend_data_fmt {
bool enable;
};
/* vendor specific from 32 */
enum iio_backend_test_pattern {
IIO_BACKEND_NO_TEST_PATTERN,
/* modified prbs9 */
IIO_BACKEND_ADI_PRBS_9A = 32,
IIO_BACKEND_TEST_PATTERN_MAX
};
enum iio_backend_sample_trigger {
IIO_BACKEND_SAMPLE_TRIGGER_EDGE_FALLING,
IIO_BACKEND_SAMPLE_TRIGGER_EDGE_RISING,
IIO_BACKEND_SAMPLE_TRIGGER_MAX
};
/**
* struct iio_backend_ops - operations structure for an iio_backend
* @enable: Enable backend.
* @disable: Disable backend.
* @chan_enable: Enable one channel.
* @chan_disable: Disable one channel.
* @data_format_set: Configure the data format for a specific channel.
* @data_source_set: Configure the data source for a specific channel.
* @set_sample_rate: Configure the sampling rate for a specific channel.
* @request_buffer: Request an IIO buffer.
* @free_buffer: Free an IIO buffer.
* @extend_chan_spec: Extend an IIO channel.
* @ext_info_set: Extended info setter.
* @ext_info_get: Extended info getter.
* @enable: Enable backend.
* @disable: Disable backend.
* @chan_enable: Enable one channel.
* @chan_disable: Disable one channel.
* @data_format_set: Configure the data format for a specific channel.
* @data_source_set: Configure the data source for a specific channel.
* @set_sample_rate: Configure the sampling rate for a specific channel.
* @test_pattern_set: Configure a test pattern.
* @chan_status: Get the channel status.
* @iodelay_set: Set digital I/O delay.
* @data_sample_trigger: Control when to sample data.
* @request_buffer: Request an IIO buffer.
* @free_buffer: Free an IIO buffer.
* @extend_chan_spec: Extend an IIO channel.
* @ext_info_set: Extended info setter.
* @ext_info_get: Extended info getter.
**/
struct iio_backend_ops {
int (*enable)(struct iio_backend *back);
@ -75,6 +93,15 @@ struct iio_backend_ops {
enum iio_backend_data_source data);
int (*set_sample_rate)(struct iio_backend *back, unsigned int chan,
u64 sample_rate_hz);
int (*test_pattern_set)(struct iio_backend *back,
unsigned int chan,
enum iio_backend_test_pattern pattern);
int (*chan_status)(struct iio_backend *back, unsigned int chan,
bool *error);
int (*iodelay_set)(struct iio_backend *back, unsigned int chan,
unsigned int taps);
int (*data_sample_trigger)(struct iio_backend *back,
enum iio_backend_sample_trigger trigger);
struct iio_buffer *(*request_buffer)(struct iio_backend *back,
struct iio_dev *indio_dev);
void (*free_buffer)(struct iio_backend *back,
@ -97,6 +124,15 @@ int iio_backend_data_source_set(struct iio_backend *back, unsigned int chan,
enum iio_backend_data_source data);
int iio_backend_set_sampling_freq(struct iio_backend *back, unsigned int chan,
u64 sample_rate_hz);
int iio_backend_test_pattern_set(struct iio_backend *back,
unsigned int chan,
enum iio_backend_test_pattern pattern);
int iio_backend_chan_status(struct iio_backend *back, unsigned int chan,
bool *error);
int iio_backend_iodelay_set(struct iio_backend *back, unsigned int lane,
unsigned int taps);
int iio_backend_data_sample_trigger(struct iio_backend *back,
enum iio_backend_sample_trigger trigger);
int devm_iio_backend_request_buffer(struct device *dev,
struct iio_backend *back,
struct iio_dev *indio_dev);

View File

@ -71,8 +71,7 @@ int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts,
uint32_t period, bool fifo);
void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts,
uint32_t fifo_period, size_t fifo_nb,
size_t sensor_nb, int64_t timestamp);
size_t sample_nb, int64_t timestamp);
static inline int64_t inv_sensors_timestamp_pop(struct inv_sensors_timestamp *ts)
{

View File

@ -788,6 +788,19 @@ static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
}
#endif
#ifdef CONFIG_ACPI
bool iio_read_acpi_mount_matrix(struct device *dev,
struct iio_mount_matrix *orientation,
char *acpi_method);
#else
static inline bool iio_read_acpi_mount_matrix(struct device *dev,
struct iio_mount_matrix *orientation,
char *acpi_method)
{
return false;
}
#endif
ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals);
int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer,