From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 42526CD4F46 for ; Fri, 15 May 2026 13:02:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=HyVznU+3ye5aUVdLjzaby8uTF6JamLhxaN2hbcbHanM=; b=Fo0OC1iteE11be 9B/6IoBxvgZZtkMp/FTf1T6K7kUnrBaX/AnSSKXeGXpPhiZDJYnzO0pPFvYTck8mhKbHZ9bqUN+QW tF7MK3QEZsmW+1HGeBRDKPG3JuqdkZgnRdHqkY1WZ0EfsWVgV7w6J+l+72VnVMi9s3HkkatL/rQuu +CN+LwC8m9fo6qIlMtzyIHgsPD0CwkLQVbxATsFjTTojVs2BAtflOLjItx8+PuTpZsgj1/I3ose87 VEL0MhtZxMV1sHhPo80CzboYJbKYxmgjkFD3jGapHCNiMUMUQ81koioxjf6Zn2oRM/pvlSyGhS5C6 AVLUUXMNtmKwxEwdx+og==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.99.1 #2 (Red Hat Linux)) id 1wNsBm-00000008OKB-2iBg; Fri, 15 May 2026 13:02:50 +0000 Received: from mail-oa1-x2b.google.com ([2001:4860:4864:20::2b]) by bombadil.infradead.org with esmtps (Exim 4.99.1 #2 (Red Hat Linux)) id 1wNsBk-00000008OH1-1LpO for linux-rockchip@lists.infradead.org; Fri, 15 May 2026 13:02:49 +0000 Received: by mail-oa1-x2b.google.com with SMTP id 586e51a60fabf-415c8a4d2e6so4332215fac.0 for ; Fri, 15 May 2026 06:02:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778850167; x=1779454967; darn=lists.infradead.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=rGjUkkZxksixHvBLlYzllO6TjHAMCKDuDS6ZoW0fEyQ=; b=QoKDXKNkSKUU4Y0ZZTMQN0agp8ZTsmHLUMUZbOsPepuEI6/sg1yzq5jISVlqiLqps6 uAg0mkuOxu/X9lcMHYdb58PAWvo9FOfPcy1Dp9iR/d6OHO1u9jeAXXANdLCsOikaW4Ot LwjiJJTh8Y7NTqN6QEzGbW1iiKenZbNORnWYrRb6ideh/Bf58YLCgak7QtcgZ5pcrO1A MJkJ2y/miNgV/IZjs+BD8aLnRCSRMgURSgBiD/nZIQUsipTqSW2l1P4iEEoPcUTHhWJz +ZPABsTSsdrm1T54rAQqyPfPl96UB8K31y1lHG0CL4rLsAlvCD9ZzwpRf/YDUeup4GCP d5WQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778850167; x=1779454967; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=rGjUkkZxksixHvBLlYzllO6TjHAMCKDuDS6ZoW0fEyQ=; b=jNYjRRGF2C74keYnidFVzY8uVD8cmzo2qV32jow8B1UIQBDNgrYC0zzafhlqvYqKOH 8mE+MfVcR2WzNrvMLxCLO36OQOFtkrlRZt1bvEHz6gTGzXN+qhzaQVCwnph6iPLzSh6Z u6pHZ19YppqL18rY6Z8hv8HyF4RopFERDWtVtLgbz0OyrXKNlCX+Ao7WDrkW8HudzFd0 9L/Tb0aGNE5UM6fIRn9XM2pVYihT5eCUqsTubGoiwYteTwurpWamB49vfrgmjUoEl104 bJKqLZaB4PizfOG16rg6gw7JP9kVBw+86M7a++tPjo6nU8k4BvH70w86EmWhxa8FKRkr 1Vjg== X-Forwarded-Encrypted: i=1; AFNElJ/0fPSFms8E9uT87Xg+4kblcRnvrrwUOYikB5DNpxKjswyeTv2lgok4NH0qpal1K6ldUaY5xTehiAdNVIbXdw==@lists.infradead.org X-Gm-Message-State: AOJu0YyASF58Xt5xQueR/fqeTuRnssR37klyCV29BBQmnRvLwiuLXDJd JNAJGb/QUzjJXpL/9JwMAmdeBeNOA0j9Lmy7uWS1NvhmS7uZZKHZf3ko X-Gm-Gg: Acq92OGbmaaAE4JMtq2yhvPOGVsLxw8husoF6PdlPf2J+wxsEzkDQtxwrGUUI228KHW N+llo5+LWb1WOAeizyHRpS96iaIdKPXYehO7cgtRP1cxdWWaGpieAM7efxh4TWI6s8MUU0pF4Wp pIpou6FJ1GZZZfljKTRi6y3V1iJGhGY0lsJQWYjpF1aarVj3iClyiHjPizIbnfrqhLIwYK+mAeo I6DoaaIjPX+IIJQJ8mtGD6N5SCyZ6wZMLqVSU2f2Jei9IoR9T1fBJadcuozWQzvtQ8k2G3uVHWh e/kFV1iQ1WBuD9Kqpfnzrk7S1M2gt+PIRr6i7xN6In76VxTPKGRbafIrjYMgSRRdhUvAGoJLZ8u jv0BfPj3i6kdflwluQdn+P4gm+CzDHHkF7t9HZjH2OX+USHRnEpcUhzTF3ZbaeBjWanzqLG5YKz p+HX0ay/o12Pwldy0p+8yAQFh4Y8oDWMRKPWr2SicUYQ== X-Received: by 2002:a05:6871:b21:b0:42f:cd67:2b84 with SMTP id 586e51a60fabf-43a2d9cb7damr2521540fac.9.1778850166801; Fri, 15 May 2026 06:02:46 -0700 (PDT) Received: from localhost.localdomain ([2600:1700:fb0:1bc0:8c2e:6a8e:445a:9169]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-439fc53f2acsm4155822fac.14.2026.05.15.06.02.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 May 2026 06:02:46 -0700 (PDT) From: Chris Morgan To: linux-iio@vger.kernel.org Cc: andy@kernel.org, nuno.sa@analog.com, dlechner@baylibre.com, jic23@kernel.org, jean-baptiste.maneyrol@tdk.com, linux-rockchip@lists.infradead.org, devicetree@vger.kernel.org, heiko@sntech.de, conor+dt@kernel.org, krzk+dt@kernel.org, robh@kernel.org, andriy.shevchenko@intel.com, Chris Morgan Subject: [PATCH V7 06/11] iio: imu: inv_icm42607: Add Buffer support for icm42607 Date: Fri, 15 May 2026 08:00:11 -0500 Message-ID: <20260515130018.237378-7-macroalpha82@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260515130018.237378-1-macroalpha82@gmail.com> References: <20260515130018.237378-1-macroalpha82@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.9.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260515_060248_433297_7955313A X-CRM114-Status: GOOD ( 27.74 ) X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+linux-rockchip=archiver.kernel.org@lists.infradead.org From: Chris Morgan Add all FIFO parsing and reading functions to support inv_icm42607 hardware. Signed-off-by: Chris Morgan --- drivers/iio/imu/inv_icm42607/Makefile | 1 + drivers/iio/imu/inv_icm42607/inv_icm42607.h | 27 + .../imu/inv_icm42607/inv_icm42607_buffer.c | 483 ++++++++++++++++++ .../imu/inv_icm42607/inv_icm42607_buffer.h | 93 ++++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 54 +- 5 files changed, 657 insertions(+), 1 deletion(-) create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile index be109102e203..3c9d08509793 100644 --- a/drivers/iio/imu/inv_icm42607/Makefile +++ b/drivers/iio/imu/inv_icm42607/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o inv-icm42607-y += inv_icm42607_core.o +inv-icm42607-y += inv_icm42607_buffer.o obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o inv-icm42607-i2c-y += inv_icm42607_i2c.o diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h index 5f37999e39a5..b00ee6a4d451 100644 --- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h @@ -14,6 +14,10 @@ #include #include +#include + +#include "inv_icm42607_buffer.h" + /* serial bus slew rates */ enum inv_icm42607_slew_rate { INV_ICM42607_SLEW_RATE_20_60NS, @@ -84,6 +88,7 @@ struct inv_icm42607_sensor_conf { int odr; int filter; }; +#define INV_ICM42607_SENSOR_CONF_INIT {-1, -1, -1, -1} struct inv_icm42607_conf { struct inv_icm42607_sensor_conf gyro; @@ -114,6 +119,10 @@ struct inv_icm42607_suspended { * @orientation: sensor chip orientation relative to main hardware. * @conf: chip sensors configurations. * @suspended: suspended sensors configuration. + * @indio_gyro: gyroscope IIO device. + * @indio_accel: accelerometer IIO device. + * @fifo: FIFO management structure. + * @buffer: data transfer buffer aligned for DMA. */ struct inv_icm42607_state { struct mutex lock; @@ -125,6 +134,22 @@ struct inv_icm42607_state { struct iio_mount_matrix orientation; struct inv_icm42607_conf conf; struct inv_icm42607_suspended suspended; + struct iio_dev *indio_gyro; + struct iio_dev *indio_accel; + struct inv_icm42607_fifo fifo; + __be16 buffer[3] __aligned(IIO_DMA_MINALIGN); +}; + +/** + * struct inv_icm42607_sensor_state - sensor state variables + * @power_mode: sensor requested power mode (for common frequencies) + * @filter: sensor filter. + * @ts: timestamp module states. + */ +struct inv_icm42607_sensor_state { + enum inv_icm42607_sensor_mode power_mode; + int filter; + struct inv_sensors_timestamp ts; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ @@ -352,6 +377,8 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data; extern const struct inv_icm42607_hw inv_icm42607p_hw_data; extern const struct dev_pm_ops inv_icm42607_pm_ops; +u32 inv_icm42607_odr_to_period(enum inv_icm42607_odr odr); + int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw *hw, inv_icm42607_bus_setup bus_setup); diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file mode 100644 index 000000000000..74e5213d9267 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c @@ -0,0 +1,483 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 InvenSense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "inv_icm42607.h" +#include "inv_icm42607_buffer.h" + +/* FIFO header: 1 byte */ +#define INV_ICM42607_FIFO_HEADER_MSG BIT(7) +#define INV_ICM42607_FIFO_HEADER_ACCEL BIT(6) +#define INV_ICM42607_FIFO_HEADER_GYRO BIT(5) +#define INV_ICM42607_FIFO_HEADER_TMST_FSYNC GENMASK(3, 2) +#define INV_ICM42607_FIFO_HEADER_ODR_ACCEL BIT(1) +#define INV_ICM42607_FIFO_HEADER_ODR_GYRO BIT(0) + +struct inv_icm42607_fifo_1sensor_packet { + u8 header; + struct inv_icm42607_fifo_sensor_data data; + s8 temp; +} __packed; + +struct inv_icm42607_fifo_2sensors_packet { + u8 header; + struct inv_icm42607_fifo_sensor_data accel; + struct inv_icm42607_fifo_sensor_data gyro; + s8 temp; + __be16 timestamp; +} __packed; + +ssize_t inv_icm42607_fifo_decode_packet(const void *packet, const void **accel, + const void **gyro, const int8_t **temp, + const void **timestamp) +{ + const struct inv_icm42607_fifo_1sensor_packet *pack1 = packet; + const struct inv_icm42607_fifo_2sensors_packet *pack2 = packet; + u8 header = *((const u8 *)packet); + + /* FIFO empty */ + if (header & INV_ICM42607_FIFO_HEADER_MSG) { + *accel = NULL; + *gyro = NULL; + *temp = NULL; + *timestamp = NULL; + return 0; + } + + /* accel + gyro */ + if ((header & INV_ICM42607_FIFO_HEADER_ACCEL) && + (header & INV_ICM42607_FIFO_HEADER_GYRO)) { + *accel = &pack2->accel; + *gyro = &pack2->gyro; + *temp = &pack2->temp; + *timestamp = &pack2->timestamp; + return INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE; + } + + /* accel only */ + if (header & INV_ICM42607_FIFO_HEADER_ACCEL) { + *accel = &pack1->data; + *gyro = NULL; + *temp = &pack1->temp; + *timestamp = NULL; + return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE; + } + + /* gyro only */ + if (header & INV_ICM42607_FIFO_HEADER_GYRO) { + *accel = NULL; + *gyro = &pack1->data; + *temp = &pack1->temp; + *timestamp = NULL; + return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE; + } + + /* invalid packet if here */ + return -EINVAL; +} + +void inv_icm42607_buffer_update_fifo_period(struct inv_icm42607_state *st) +{ + u32 period_gyro, period_accel; + + if (st->fifo.en & INV_ICM42607_SENSOR_GYRO) + period_gyro = inv_icm42607_odr_to_period(st->conf.gyro.odr); + else + period_gyro = U32_MAX; + + if (st->fifo.en & INV_ICM42607_SENSOR_ACCEL) + period_accel = inv_icm42607_odr_to_period(st->conf.accel.odr); + else + period_accel = U32_MAX; + + st->fifo.period = min(period_gyro, period_accel); +} + +int inv_icm42607_buffer_set_fifo_en(struct inv_icm42607_state *st, + unsigned int fifo_en) +{ + unsigned int val; + int ret; + + /* update FIFO EN bits for accel and gyro */ + val = 0; + if (fifo_en & INV_ICM42607_SENSOR_GYRO) + val |= INV_ICM42607_FIFO_CONFIG1_MODE; + if (fifo_en & INV_ICM42607_SENSOR_ACCEL) + val |= INV_ICM42607_FIFO_CONFIG1_MODE; + if (fifo_en & INV_ICM42607_SENSOR_TEMP) + val |= INV_ICM42607_FIFO_CONFIG1_MODE; + + ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1, val); + if (ret) + return ret; + + st->fifo.en = fifo_en; + inv_icm42607_buffer_update_fifo_period(st); + + return 0; +} + +static size_t inv_icm42607_get_packet_size(unsigned int fifo_en) +{ + size_t packet_size; + + if ((fifo_en & INV_ICM42607_SENSOR_GYRO) && + (fifo_en & INV_ICM42607_SENSOR_ACCEL)) + packet_size = INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE; + else + packet_size = INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE; + + return packet_size; +} + +static unsigned int inv_icm42607_wm_truncate(unsigned int watermark, + size_t packet_size) +{ + size_t wm_size; + + wm_size = watermark * packet_size; + wm_size = min(wm_size, INV_ICM42607_FIFO_WATERMARK_MAX); + + return wm_size / packet_size; +} + +/** + * inv_icm42607_buffer_update_watermark - update watermark FIFO threshold + * @st: driver internal state + * + * Returns 0 on success, a negative error code otherwise. + */ +int inv_icm42607_buffer_update_watermark(struct inv_icm42607_state *st) +{ + const struct device *dev = regmap_get_device(st->map); + unsigned int wm_gyro, wm_accel, watermark; + u32 latency_gyro, latency_accel, latency; + u32 period_gyro, period_accel; + size_t packet_size, wm_size; + __le16 raw_wm; + bool restore; + int ret; + + packet_size = inv_icm42607_get_packet_size(st->fifo.en); + + /* compute sensors latency, depending on sensor watermark and odr */ + wm_gyro = inv_icm42607_wm_truncate(st->fifo.watermark.gyro, packet_size); + wm_accel = inv_icm42607_wm_truncate(st->fifo.watermark.accel, packet_size); + /* use us for odr to avoid overflow using 32 bits values */ + period_gyro = inv_icm42607_odr_to_period(st->conf.gyro.odr) / 1000UL; + period_accel = inv_icm42607_odr_to_period(st->conf.accel.odr) / 1000UL; + latency_gyro = period_gyro * wm_gyro; + latency_accel = period_accel * wm_accel; + + /* 0 value for watermark means that the sensor is turned off */ + if (wm_gyro == 0 && wm_accel == 0) + return 0; + + if (latency_gyro == 0) { + watermark = wm_accel; + st->fifo.watermark.eff_accel = wm_accel; + } else if (latency_accel == 0) { + watermark = wm_gyro; + st->fifo.watermark.eff_gyro = wm_gyro; + } else { + /* compute the smallest latency that is a multiple of both */ + if (latency_gyro <= latency_accel) + latency = latency_gyro - (latency_accel % latency_gyro); + else + latency = latency_accel - (latency_gyro % latency_accel); + /* all this works because periods are multiple of each others */ + watermark = latency / min(period_gyro, period_accel); + watermark = max(watermark, 1); + /* update effective watermark */ + st->fifo.watermark.eff_gyro = max(latency / period_gyro, 1); + st->fifo.watermark.eff_accel = max(latency / period_accel, 1); + } + + /* changing FIFO watermark requires to turn off watermark interrupt */ + ret = regmap_update_bits_check(st->map, INV_ICM42607_REG_INT_SOURCE0, + INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN, + 0, &restore); + if (ret) + return ret; + + /* compute watermark value in bytes */ + wm_size = watermark * packet_size; + raw_wm = INV_ICM42607_FIFO_WATERMARK_VAL(wm_size); + memcpy(st->buffer, &raw_wm, sizeof(raw_wm)); + ret = regmap_bulk_write(st->map, INV_ICM42607_REG_FIFO_CONFIG2, + st->buffer, sizeof(raw_wm)); + if (ret) { + dev_err(dev, "Unable to change watermark value: %d\n", ret); + if (restore) + regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0, + INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN, + INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN); + return ret; + } + + /* restore watermark interrupt */ + if (restore) { + ret = regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0, + INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN, + INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN); + if (ret) + return ret; + } + + return 0; +} + +static int inv_icm42607_buffer_preenable(struct iio_dev *indio_dev) +{ + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42607_sensor_state *sensor_st = iio_priv(indio_dev); + struct inv_sensors_timestamp *ts = &sensor_st->ts; + struct device *dev = regmap_get_device(st->map); + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + guard(mutex)(&st->lock); + inv_sensors_timestamp_reset(ts); + + return 0; +} + +/* + * update_scan_mode callback is turning sensors on and setting data FIFO enable + * bits. + */ +static int inv_icm42607_buffer_postenable(struct iio_dev *indio_dev) +{ + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + int ret; + + guard(mutex)(&st->lock); + + /* exit if FIFO is already on */ + if (st->fifo.on) { + st->fifo.on++; + return 0; + } + + /* set FIFO threshold interrupt */ + ret = regmap_set_bits(st->map, INV_ICM42607_REG_INT_SOURCE0, + INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN); + if (ret) + return ret; + + /* flush FIFO data */ + ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET, + INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH); + if (ret) + return ret; + + /* set FIFO in streaming mode */ + ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1, + INV_ICM42607_FIFO_CONFIG1_MODE); + if (ret) + return ret; + + /* workaround: first read of FIFO count after reset is always 0 */ + ret = regmap_bulk_read(st->map, INV_ICM42607_REG_FIFO_COUNTH, + st->buffer, sizeof(__be16)); + if (ret) + return ret; + + st->fifo.on++; + + return 0; +} + +static int inv_icm42607_buffer_predisable(struct iio_dev *indio_dev) +{ + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + int ret; + + guard(mutex)(&st->lock); + + if (st->fifo.on > 1) { + st->fifo.on--; + return 0; + } + + /* set FIFO in bypass mode */ + ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1, + INV_ICM42607_FIFO_CONFIG1_BYPASS); + if (ret) + return ret; + + /* flush FIFO data */ + ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET, + INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH); + if (ret) + return ret; + + /* disable FIFO threshold interrupt */ + ret = regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0, + INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN, 0); + if (ret) + return ret; + + /* + * FIFO should only be 1 at this point, so explicitly set it to 0 + * instead of decrementing it. + */ + st->fifo.on = 0; + + return 0; +} + +static int inv_icm42607_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + struct device *dev = regmap_get_device(st->map); + unsigned int sensor; + unsigned int *watermark; + unsigned int sleep_temp = 0; + unsigned int sleep_sensor = 0; + unsigned int sleep; + int ret; + + if (indio_dev == st->indio_gyro) { + sensor = INV_ICM42607_SENSOR_GYRO; + watermark = &st->fifo.watermark.gyro; + } else if (indio_dev == st->indio_accel) { + sensor = INV_ICM42607_SENSOR_ACCEL; + watermark = &st->fifo.watermark.accel; + } else { + return -EINVAL; + } + + mutex_lock(&st->lock); + + ret = inv_icm42607_buffer_set_fifo_en(st, st->fifo.en & ~sensor); + if (ret) + goto out_unlock; + + *watermark = 0; + ret = inv_icm42607_buffer_update_watermark(st); + if (ret) + goto out_unlock; + +out_unlock: + mutex_unlock(&st->lock); + + /* sleep maximum required time */ + sleep = max(sleep_sensor, sleep_temp); + if (sleep) + msleep(sleep); + + pm_runtime_put_autosuspend(dev); + + return ret; +} + +const struct iio_buffer_setup_ops inv_icm42607_buffer_ops = { + .preenable = inv_icm42607_buffer_preenable, + .postenable = inv_icm42607_buffer_postenable, + .predisable = inv_icm42607_buffer_predisable, + .postdisable = inv_icm42607_buffer_postdisable, +}; + +int inv_icm42607_buffer_fifo_read(struct inv_icm42607_state *st, + unsigned int max) +{ + const void *accel, *gyro, *timestamp; + size_t i, max_count; + const s8 *temp; + ssize_t size; + int ret; + + guard(mutex)(&st->lock); + + /* reset all samples counters */ + st->fifo.count = 0; + st->fifo.nb.gyro = 0; + st->fifo.nb.accel = 0; + st->fifo.nb.total = 0; + + /* compute maximum FIFO read size */ + if (max == 0) + max_count = sizeof(st->fifo.data); + else + max_count = min((max * inv_icm42607_get_packet_size(st->fifo.en)), + sizeof(st->fifo.data)); + + /* read FIFO count value */ + ret = regmap_bulk_read(st->map, INV_ICM42607_REG_FIFO_COUNTH, + st->buffer, sizeof(u8) * 2); + if (ret) + return ret; + st->fifo.count = be16_to_cpup(st->buffer); + + /* check and clamp FIFO count value */ + if (st->fifo.count == 0) + return 0; + + st->fifo.count = min(st->fifo.count, max_count); + + /* read all FIFO data in internal buffer */ + ret = regmap_noinc_read(st->map, INV_ICM42607_REG_FIFO_DATA, + st->fifo.data, st->fifo.count); + if (ret) + return ret; + + /* compute number of samples for each sensor */ + for (i = 0; i < st->fifo.count; i += size) { + size = inv_icm42607_fifo_decode_packet(&st->fifo.data[i], + &accel, &gyro, &temp, ×tamp); + /* Make sure the size is at least 1 valid packet. */ + if (size < INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE) + break; + if (gyro != NULL && inv_icm42607_fifo_is_data_valid(gyro)) + st->fifo.nb.gyro++; + if (accel != NULL && inv_icm42607_fifo_is_data_valid(accel)) + st->fifo.nb.accel++; + st->fifo.nb.total++; + } + + return 0; +} + +int inv_icm42607_buffer_hwfifo_flush(struct inv_icm42607_state *st, + unsigned int count) +{ + int ret; + + ret = inv_icm42607_buffer_fifo_read(st, count); + + return ret; +} + +int inv_icm42607_buffer_init(struct inv_icm42607_state *st) +{ + int ret; + + st->fifo.watermark.eff_gyro = 1; + st->fifo.watermark.eff_accel = 1; + + /* Configure FIFO_COUNT format in bytes and big endian */ + ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0, + INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN); + if (ret) + return ret; + + /* Initialize FIFO in bypass mode */ + return regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1, + INV_ICM42607_FIFO_CONFIG1_BYPASS); +} diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file mode 100644 index 000000000000..b77deb66f8bd --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2026 InvenSense, Inc. + */ + +#ifndef INV_ICM42607_BUFFER_H_ +#define INV_ICM42607_BUFFER_H_ + +#include + +struct inv_icm42607_state; + +#define INV_ICM42607_SENSOR_GYRO BIT(0) +#define INV_ICM42607_SENSOR_ACCEL BIT(1) +#define INV_ICM42607_SENSOR_TEMP BIT(2) + +/** + * struct inv_icm42607_fifo - FIFO state variables + * @on: reference counter for FIFO on. + * @en: bits field of INV_ICM42607_SENSOR_* for FIFO EN bits. + * @period: FIFO internal period. + * @watermark: watermark configuration values for accel and gyro. + * @count: number of bytes in the FIFO data buffer. + * @nb: gyro, accel and total samples in the FIFO data buffer. + * @data: FIFO data buffer aligned for DMA (2kB + 32 bytes of read cache). + */ +struct inv_icm42607_fifo { + unsigned int on; + unsigned int en; + u32 period; + struct { + unsigned int gyro; + unsigned int accel; + unsigned int eff_gyro; + unsigned int eff_accel; + } watermark; + size_t count; + struct { + size_t gyro; + size_t accel; + size_t total; + } nb; + u8 data[2080] __aligned(IIO_DMA_MINALIGN); +}; + +/* FIFO data packet */ +struct inv_icm42607_fifo_sensor_data { + __be16 x; + __be16 y; + __be16 z; +}; + +#define INV_ICM42607_FIFO_DATA_INVALID -32768 + +static inline bool +inv_icm42607_fifo_is_data_valid(const struct inv_icm42607_fifo_sensor_data *s) +{ + s16 x, y, z; + + x = be16_to_cpu(s->x); + y = be16_to_cpu(s->y); + z = be16_to_cpu(s->z); + + if (x == INV_ICM42607_FIFO_DATA_INVALID && + y == INV_ICM42607_FIFO_DATA_INVALID && + z == INV_ICM42607_FIFO_DATA_INVALID) + return false; + + return true; +} + +ssize_t inv_icm42607_fifo_decode_packet(const void *packet, const void **accel, + const void **gyro, const s8 **temp, + const void **timestamp); + +extern const struct iio_buffer_setup_ops inv_icm42607_buffer_ops; + +int inv_icm42607_buffer_init(struct inv_icm42607_state *st); + +void inv_icm42607_buffer_update_fifo_period(struct inv_icm42607_state *st); + +int inv_icm42607_buffer_set_fifo_en(struct inv_icm42607_state *st, + unsigned int fifo_en); + +int inv_icm42607_buffer_update_watermark(struct inv_icm42607_state *st); + +int inv_icm42607_buffer_fifo_read(struct inv_icm42607_state *st, + unsigned int max); + +int inv_icm42607_buffer_hwfifo_flush(struct inv_icm42607_state *st, + unsigned int count); + +#endif diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c index e27ad0319a12..d5885fc3f7da 100644 --- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c @@ -15,6 +15,7 @@ #include #include "inv_icm42607.h" +#include "inv_icm42607_buffer.h" static bool inv_icm42607_is_volatile_reg(struct device *dev, unsigned int reg) { @@ -73,6 +74,40 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = { }; EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607"); +u32 inv_icm42607_odr_to_period(enum inv_icm42607_odr odr) +{ + static const u32 odr_periods[INV_ICM42607_ODR_NB] = { + /* Reserved values */ + 0, 0, 0, 0, 0, + /* 1600Hz */ + 625000, + /* 800Hz */ + 1250000, + /* 400Hz */ + 2500000, + /* 200Hz */ + 5000000, + /* 100 Hz */ + 10000000, + /* 50Hz */ + 20000000, + /* 25Hz */ + 40000000, + /* 12.5Hz */ + 80000000, + /* 6.25Hz */ + 160000000, + /* 3.125Hz */ + 320000000, + /* 1.5625Hz */ + 640000000, + }; + + odr = clamp(odr, INV_ICM42607_ODR_1600HZ, INV_ICM42607_ODR_1_5625HZ_LP); + + return odr_periods[odr]; +} + static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st, enum inv_icm42607_sensor_mode gyro, enum inv_icm42607_sensor_mode accel, @@ -333,6 +368,11 @@ int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw if (ret) return ret; + /* Initialize buffer/FIFO handling */ + ret = inv_icm42607_buffer_init(st); + if (ret) + return ret; + ret = devm_pm_runtime_set_active_enabled(dev); if (ret) return ret; @@ -354,6 +394,13 @@ static int inv_icm42607_suspend(struct device *dev) if (pm_runtime_suspended(dev)) return 0; + if (st->fifo.on) { + ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1, + INV_ICM42607_FIFO_CONFIG1_BYPASS); + if (ret) + return ret; + } + ret = inv_icm42607_set_pwr_mgmt0(st, INV_ICM42607_SENSOR_MODE_OFF, INV_ICM42607_SENSOR_MODE_OFF, false, NULL); @@ -378,7 +425,12 @@ static int inv_icm42607_resume(struct device *dev) if (ret) return ret; - /* Nothing else to restore at this time. */ + if (st->fifo.on) { + ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1, + INV_ICM42607_FIFO_CONFIG1_MODE); + if (ret) + return ret; + } return 0; } -- 2.43.0 _______________________________________________ Linux-rockchip mailing list Linux-rockchip@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip