diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2024-05-02 14:50:30 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2024-05-02 14:50:30 +1000 |
commit | 25db4dbc281dfd54f631b6a4121f7655d6240b3f (patch) | |
tree | e17ab857d65f9b74c7abaa5db041e2ec3086ae74 | |
parent | 81b8760720fd004e99f0a82338480718cf6f6df5 (diff) | |
parent | 9900e7a54764998ba3a22f06ec629f7b5fe0b422 (diff) | |
download | linux-next-history-25db4dbc281dfd54f631b6a4121f7655d6240b3f.tar.gz |
Merge branch 'togreg' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
Notice: this object is not reachable from any branch.
Notice: this object is not reachable from any branch.
46 files changed, 1276 insertions, 404 deletions
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml index 3d49d21ad33df..e1f450b80db27 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml @@ -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>; }; ... diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml index 5e0bed2c45ded..3769f8e8e98ce 100644 --- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml @@ -32,6 +32,7 @@ properties: - invensense,icm42605 - invensense,icm42622 - invensense,icm42631 + - invensense,icm42686 - invensense,icm42688 reg: diff --git a/Documentation/iio/ad7944.rst b/Documentation/iio/ad7944.rst index f418ab1288ae3..0d26e56aba886 100644 --- a/Documentation/iio/ad7944.rst +++ b/Documentation/iio/ad7944.rst @@ -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 ============== diff --git a/Documentation/iio/adis16475.rst b/Documentation/iio/adis16475.rst index 91cabb7d8d057..130f9e97cc17c 100644 --- a/Documentation/iio/adis16475.rst +++ b/Documentation/iio/adis16475.rst @@ -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. | +---------------------------------------+------------------------------------------------------+ diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 0ba0e1521ba4f..cb80ef837e84f 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -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 diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 110591804b4c4..ae0cd48a3e293 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -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, diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 126e8bdd6d0ed..8280d2bef0a37 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -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; diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 63c3566a533bd..e56407b6f2045 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -65,6 +65,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]; @@ -272,6 +273,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, @@ -298,6 +313,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[] = { @@ -440,6 +456,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; diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 468c2656d2be7..353a97f9c0860 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -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[] = { diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index 4af574ffa8641..4602ab5ed2a65 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -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 @@ out: 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, diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index b757cc45c4dec..0f0dcd9ca6b60 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -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 @@ done: 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"); diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index 7475ec2a56c72..e85b763b9ffcb 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -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; + + ret = devm_iio_device_register(&spi->dev, indio_dev); if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + ad9467_debugfs_init(indio_dev); + + return 0; } static const struct of_device_id ad9467_of_match[] = { diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 97a05f325df7c..a2b87f6b7a071 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -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; diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 9444b0c5a93c6..0cf0d81358fd5 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -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... diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 614de96448003..78fada4b7b1c8 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -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); diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index 394396b916309..b680690631dbb 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -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; } diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c index 7263ad76124d7..c7f40ae6e6089 100644 --- a/drivers/iio/adc/intel_mrfld_adc.c +++ b/drivers/iio/adc/intel_mrfld_adc.c @@ -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; } diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c index 311b613b60575..e2ae13f1e842e 100644 --- a/drivers/iio/adc/mcp3564.c +++ b/drivers/iio/adc/mcp3564.c @@ -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]; diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c index 2e60c10ee4ffe..8c7b64e78dbbc 100644 --- a/drivers/iio/adc/mxs-lradc-adc.c +++ b/drivers/iio/adc/mxs-lradc-adc.c @@ -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; diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c index f751260605e4e..456f12faa3480 100644 --- a/drivers/iio/adc/pac1934.c +++ b/drivers/iio/adc/pac1934.c @@ -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; diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c index a5464737e527c..bcb1298409089 100644 --- a/drivers/iio/adc/rtq6056.c +++ b/drivers/iio/adc/rtq6056.c @@ -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] = { diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 36add95212c37..375aa7720f804 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -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; diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index ca08ae3108b22..9a47d2c87f05a 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -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; diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 6ae967e4d8fa7..d3363d02f2921 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -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; } } diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 78bf55438b2c6..6a3db2bce4609 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -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; } diff --git a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c index 3b0f9598a7c77..fa205f17bd905 100644 --- a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c +++ b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c @@ -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; } diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c index ff33120075bf6..f56eabe537235 100644 --- a/drivers/iio/dac/ad9739a.c +++ b/drivers/iio/dac/ad9739a.c @@ -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; diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c index 9047c5aec0ff9..880d83a014a1e 100644 --- a/drivers/iio/dac/adi-axi-dac.c +++ b/drivers/iio/dac/adi-axi-dac.c @@ -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; } diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 0566340b26604..c4ac91f6bafea 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -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 diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index f67bd5a39beb3..83d8504ebfff4 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -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; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index b52f328fd26ce..bce25ff57ecda 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -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); @@ -509,20 +510,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 = iio_priv(st->indio_gyro); + 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 = iio_priv(st->indio_accel); + 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; @@ -550,9 +551,7 @@ int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st, 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); + inv_sensors_timestamp_interrupt(ts, st->fifo.nb.gyro, gyro_ts); ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro); if (ret) return ret; @@ -560,9 +559,7 @@ int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st, 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); + inv_sensors_timestamp_interrupt(ts, st->fifo.nb.accel, accel_ts); ret = inv_icm42600_accel_parse_fifo(st->indio_accel); if (ret) return ret; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index 82e0a2e2ad706..96116a68ab291 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -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", diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index 3df0a715e8856..e6f8de80128c4 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -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; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index ebb28f84ba985..8d33504d770f7 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -82,6 +82,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, }, { diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c index 50217a10e0bbf..cc2bf1799a465 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -78,6 +78,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, }, { diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index 86465226f7e10..0dc0f22a55827 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -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 */ diff --git a/drivers/iio/industrialio-acpi.c b/drivers/iio/industrialio-acpi.c new file mode 100644 index 0000000000000..981b75d407802 --- /dev/null +++ b/drivers/iio/industrialio-acpi.c @@ -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); diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index f08ed6d70ae59..929aff4040edd 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -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. * diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 1d950a3e153b8..cec58a604d73a 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -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); diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c index 46c647ccd44c5..d6627b3e6000e 100644 --- a/drivers/iio/light/apds9306.c +++ b/drivers/iio/light/apds9306.c @@ -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); diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 7b71ad71d78de..08d471438175e 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -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}, {} }; diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 421e059d1f190..dcc87a9015e8b 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -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; } diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index 46845804292bf..7a3eef5d5e752 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -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; } diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h index 9d144631134db..8099759d72428 100644 --- a/include/linux/iio/backend.h +++ b/include/linux/iio/backend.h @@ -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); diff --git a/include/linux/iio/common/inv_sensors_timestamp.h b/include/linux/iio/common/inv_sensors_timestamp.h index a47d304d1ba7c..8d506f1e9df29 100644 --- a/include/linux/iio/common/inv_sensors_timestamp.h +++ b/include/linux/iio/common/inv_sensors_timestamp.h @@ -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) { diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index e370a7bb3300b..55e2b22086a1a 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -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, |