From patchwork Thu Apr 29 12:28:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Nyekjaer X-Patchwork-Id: 12231197 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A9CE7C433B4 for ; Thu, 29 Apr 2021 12:28:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 71C2161423 for ; Thu, 29 Apr 2021 12:28:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235662AbhD2M3H (ORCPT ); Thu, 29 Apr 2021 08:29:07 -0400 Received: from first.geanix.com ([116.203.34.67]:50648 "EHLO first.geanix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231490AbhD2M3D (ORCPT ); Thu, 29 Apr 2021 08:29:03 -0400 Received: from zen.. (unknown [185.17.218.86]) by first.geanix.com (Postfix) with ESMTPSA id 286DC466680; Thu, 29 Apr 2021 12:28:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=geanix.com; s=first; t=1619699293; bh=uuIzJZEp56M8JmKfmdMrj7MYRr58zqBCjAOF69jUomw=; h=From:To:Cc:Subject:Date; b=FpZIHPCMwlzHqYADQCEc3q9ls1kUP5kwB63ffPditP+PJKEa3HkRE7az7RY/qdQ67 ur3GBa0dDhbOEUWZNgmtKXQQemqQUoInBdwxbRqsY5l29V13ZU0V1e+P5IeC5K1YU2 X8jexxrBh14qaagpKVcLp6wmLLkOTAiYnw3UzbQeXFyauZCrk04+3uRrUHvn33127z CK+QuiokgrkHNvWl8T8o7IIWWEo+JhJDGdpruHnxN8UPJ2g6EIIwRpsVY9w8OYbM33 IW4K2TFRXtqJHPeUAUgQgD0yW7p933Hdbjy+emmRFhA4c6tf8nnuH0PYLzL4Hnxqo6 7Ueivf8pXhyxw== From: Sean Nyekjaer To: jic23@kernel.org, linux-iio@vger.kernel.org, andy.shevchenko@gmail.com, lars@metafoo.de, Nuno.Sa@analog.com, robh+dt@kernel.org, devicetree@vger.kernel.org Cc: Sean Nyekjaer Subject: [PATCH v4 1/6] iio: accel: add support for FXLS8962AF/FXLS8964AF accelerometers Date: Thu, 29 Apr 2021 14:28:01 +0200 Message-Id: <20210429122806.3814330-1-sean@geanix.com> X-Mailer: git-send-email 2.31.0 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Add basic support for NXP FXLS8962AF/FXLS8964AF Automotive accelerometers. It will allow setting up scale/gain and reading x,y,z axis. Datasheet: https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf Datasheet: https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf Signed-off-by: Sean Nyekjaer Reviewed-by: Andy Shevchenko --- Changes for v2: - Addressed Kconfig comments - Using regmap_read_poll_timeout() - Addresed comments from Andy and Jonathan Changes for v3: - fixed Kconfig ordering - read INT_STATUS after reset, to ensure the device is ready - fixed a few xmas trees - added datasheet tags Changes for v4: - reworked read_raw -> fxls8962af_get_out, so we will skip the claim part. - Removed the drdy check, worstcase data will be 1,28s/0.781Hz old. drivers/iio/accel/Kconfig | 27 ++ drivers/iio/accel/Makefile | 3 + drivers/iio/accel/fxls8962af-core.c | 563 ++++++++++++++++++++++++++++ drivers/iio/accel/fxls8962af-i2c.c | 57 +++ drivers/iio/accel/fxls8962af-spi.c | 57 +++ drivers/iio/accel/fxls8962af.h | 22 ++ 6 files changed, 729 insertions(+) create mode 100644 drivers/iio/accel/fxls8962af-core.c create mode 100644 drivers/iio/accel/fxls8962af-i2c.c create mode 100644 drivers/iio/accel/fxls8962af-spi.c create mode 100644 drivers/iio/accel/fxls8962af.h diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 2e0c62c39155..7317d839ca1a 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -208,6 +208,33 @@ config DMARD10 Choosing M will build the driver as a module. If so, the module will be called dmard10. +config FXLS8962AF + tristate + +config FXLS8962AF_I2C + tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver" + depends on I2C + select FXLS8962AF + select REGMAP_I2C + help + Say yes here to build support for the NXP 3-axis automotive + accelerometer FXLS8962AF/FXLS8964AF with I2C support. + + To compile this driver as a module, choose M here: the module + will be called fxls8962af_i2c. + +config FXLS8962AF_SPI + tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer SPI Driver" + depends on SPI + select FXLS8962AF + select REGMAP_SPI + help + Say yes here to build support for the NXP 3-axis automotive + accelerometer FXLS8962AF/FXLS8964AF with SPI support. + + To compile this driver as a module, choose M here: the module + will be called fxls8962af_spi. + config HID_SENSOR_ACCEL_3D depends on HID_SENSOR_HUB select IIO_BUFFER diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 4f6c1ebe13b0..1b8c479c6f7c 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -25,6 +25,9 @@ obj-$(CONFIG_DA311) += da311.o obj-$(CONFIG_DMARD06) += dmard06.o obj-$(CONFIG_DMARD09) += dmard09.o obj-$(CONFIG_DMARD10) += dmard10.o +obj-$(CONFIG_FXLS8962AF) += fxls8962af-core.o +obj-$(CONFIG_FXLS8962AF_I2C) += fxls8962af-i2c.o +obj-$(CONFIG_FXLS8962AF_SPI) += fxls8962af-spi.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXSD9) += kxsd9.o diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c new file mode 100644 index 000000000000..6ae47eac4490 --- /dev/null +++ b/drivers/iio/accel/fxls8962af-core.c @@ -0,0 +1,563 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NXP FXLS8962AF/FXLS8964AF Accelerometer Core Driver + * + * Copyright 2021 Connected Cars A/S + * + * Datasheet: + * https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf + * https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf + * + * Errata: + * https://www.nxp.com/docs/en/errata/ES_FXLS8962AF.pdf + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "fxls8962af.h" + +#define FXLS8962AF_INT_STATUS 0x00 +#define FXLS8962AF_INT_STATUS_SRC_BOOT BIT(0) +#define FXLS8962AF_INT_STATUS_SRC_DRDY BIT(7) +#define FXLS8962AF_TEMP_OUT 0x01 +#define FXLS8962AF_VECM_LSB 0x02 +#define FXLS8962AF_OUT_X_LSB 0x04 +#define FXLS8962AF_OUT_Y_LSB 0x06 +#define FXLS8962AF_OUT_Z_LSB 0x08 +#define FXLS8962AF_BUF_STATUS 0x0b +#define FXLS8962AF_BUF_X_LSB 0x0c +#define FXLS8962AF_BUF_Y_LSB 0x0e +#define FXLS8962AF_BUF_Z_LSB 0x10 + +#define FXLS8962AF_PROD_REV 0x12 +#define FXLS8962AF_WHO_AM_I 0x13 + +#define FXLS8962AF_SYS_MODE 0x14 +#define FXLS8962AF_SENS_CONFIG1 0x15 +#define FXLS8962AF_SENS_CONFIG1_ACTIVE BIT(0) +#define FXLS8962AF_SENS_CONFIG1_RST BIT(7) +#define FXLS8962AF_SC1_FSR_MASK GENMASK(2, 1) +#define FXLS8962AF_SC1_FSR_PREP(x) FIELD_PREP(FXLS8962AF_SC1_FSR_MASK, (x)) +#define FXLS8962AF_SC1_FSR_GET(x) FIELD_GET(FXLS8962AF_SC1_FSR_MASK, (x)) + +#define FXLS8962AF_SENS_CONFIG2 0x16 +#define FXLS8962AF_SENS_CONFIG3 0x17 +#define FXLS8962AF_SENS_CONFIG4 0x18 +#define FXLS8962AF_SENS_CONFIG5 0x19 + +#define FXLS8962AF_WAKE_IDLE_LSB 0x1b +#define FXLS8962AF_SLEEP_IDLE_LSB 0x1c +#define FXLS8962AF_ASLP_COUNT_LSB 0x1e + +#define FXLS8962AF_INT_EN 0x20 +#define FXLS8962AF_INT_PIN_SEL 0x21 + +#define FXLS8962AF_OFF_X 0x22 +#define FXLS8962AF_OFF_Y 0x23 +#define FXLS8962AF_OFF_Z 0x24 + +#define FXLS8962AF_BUF_CONFIG1 0x26 +#define FXLS8962AF_BUF_CONFIG2 0x27 + +#define FXLS8962AF_ORIENT_STATUS 0x28 +#define FXLS8962AF_ORIENT_CONFIG 0x29 +#define FXLS8962AF_ORIENT_DBCOUNT 0x2a +#define FXLS8962AF_ORIENT_BF_ZCOMP 0x2b +#define FXLS8962AF_ORIENT_THS_REG 0x2c + +#define FXLS8962AF_SDCD_INT_SRC1 0x2d +#define FXLS8962AF_SDCD_INT_SRC2 0x2e +#define FXLS8962AF_SDCD_CONFIG1 0x2f +#define FXLS8962AF_SDCD_CONFIG2 0x30 +#define FXLS8962AF_SDCD_OT_DBCNT 0x31 +#define FXLS8962AF_SDCD_WT_DBCNT 0x32 +#define FXLS8962AF_SDCD_LTHS_LSB 0x33 +#define FXLS8962AF_SDCD_UTHS_LSB 0x35 + +#define FXLS8962AF_SELF_TEST_CONFIG1 0x37 +#define FXLS8962AF_SELF_TEST_CONFIG2 0x38 + +#define FXLS8962AF_MAX_REG 0x38 + +#define FXLS8962AF_DEVICE_ID 0x62 +#define FXLS8964AF_DEVICE_ID 0x84 + +/* Raw temp channel offset */ +#define FXLS8962AF_TEMP_CENTER_VAL 25 + +#define FXLS8962AF_AUTO_SUSPEND_DELAY_MS 2000 + +#define FXLS8962AF_SCALE_TABLE_LEN 4 + +static const int fxls8962af_scale_table[FXLS8962AF_SCALE_TABLE_LEN][2] = { + {0, IIO_G_TO_M_S_2(980000)}, + {0, IIO_G_TO_M_S_2(1950000)}, + {0, IIO_G_TO_M_S_2(3910000)}, + {0, IIO_G_TO_M_S_2(7810000)}, +}; + +struct fxls8962af_chip_info { + const char *name; + const struct iio_chan_spec *channels; + int num_channels; + u8 chip_id; +}; + +struct fxls8962af_data { + struct regmap *regmap; + const struct fxls8962af_chip_info *chip_info; + struct regulator *vdd_reg; + struct iio_mount_matrix orientation; +}; + +const struct regmap_config fxls8962af_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, + .max_register = FXLS8962AF_MAX_REG, +}; +EXPORT_SYMBOL_GPL(fxls8962af_regmap_conf); + +enum { + fxls8962af_idx_x, + fxls8962af_idx_y, + fxls8962af_idx_z, + fxls8962af_idx_ts, +}; + +static int fxls8962af_power_on(struct fxls8962af_data *data) +{ + struct device *dev = regmap_get_device(data->regmap); + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) { + dev_err(dev, "failed to power on\n"); + } + + return ret; +} + +static int fxls8962af_power_off(struct fxls8962af_data *data) +{ + struct device *dev = regmap_get_device(data->regmap); + int ret; + + pm_runtime_mark_last_busy(dev); + ret = pm_runtime_put_autosuspend(dev); + + if (ret < 0) { + dev_err(dev, "failed to power off\n"); + } + + return ret; +} + +static int fxls8962af_standby(struct fxls8962af_data *data) +{ + return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_ACTIVE, 0); +} + +static int fxls8962af_active(struct fxls8962af_data *data) +{ + return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_ACTIVE, 1); +} + +static int fxls8962af_is_active(struct fxls8962af_data *data) +{ + unsigned int reg; + int ret; + + ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG1, ®); + if (ret < 0) + return ret; + + return reg & FXLS8962AF_SENS_CONFIG1_ACTIVE; +} + +static int fxls8962af_get_out(struct fxls8962af_data *data, + struct iio_chan_spec const *chan, int *val) +{ + struct device *dev = regmap_get_device(data->regmap); + __le16 raw_val; + int is_active; + int ret; + + is_active = fxls8962af_is_active(data); + if (!is_active) { + ret = fxls8962af_power_on(data); + if (ret) + return ret; + } + + ret = regmap_bulk_read(data->regmap, chan->address, + &raw_val, (chan->scan_type.storagebits / 8)); + + if (!is_active) { + fxls8962af_power_off(data); + } + + if (ret < 0) { + dev_err(dev, "failed to get out reg 0x%lx\n", chan->address); + return ret; + } + + *val = sign_extend32(le16_to_cpu(raw_val), + chan->scan_type.realbits - 1); + + return IIO_VAL_INT; +} + +static int fxls8962af_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_INT_PLUS_NANO; + *vals = (int *)fxls8962af_scale_table; + *length = ARRAY_SIZE(fxls8962af_scale_table) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int fxls8962af_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + return IIO_VAL_INT_PLUS_NANO; +} + +static int fxls8962af_update_config(struct fxls8962af_data *data, u8 reg, + u8 mask, u8 val) +{ + int ret; + int is_active; + + is_active = fxls8962af_is_active(data); + if (is_active) { + ret = fxls8962af_standby(data); + if (ret < 0) + return ret; + } + + ret = regmap_update_bits(data->regmap, reg, mask, val); + if (ret < 0) + return ret; + + if (is_active) { + ret = fxls8962af_active(data); + if (ret < 0) + return ret; + } + + return 0; +} + +static int fxls8962af_set_full_scale(struct fxls8962af_data *data, u32 scale) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fxls8962af_scale_table); i++) + if (scale == fxls8962af_scale_table[i][1]) + break; + + if (i == ARRAY_SIZE(fxls8962af_scale_table)) + return -EINVAL; + + return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SC1_FSR_MASK, + FXLS8962AF_SC1_FSR_PREP(i)); +} + +static unsigned int fxls8962af_read_full_scale(struct fxls8962af_data *data, + int *val) +{ + int ret; + unsigned int reg; + u8 range_idx; + + ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG1, ®); + if (ret < 0) + return ret; + + range_idx = FXLS8962AF_SC1_FSR_GET(reg); + + *val = fxls8962af_scale_table[range_idx][1]; + + return IIO_VAL_INT_PLUS_NANO; +} + +static int fxls8962af_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_TEMP: + case IIO_ACCEL: + return fxls8962af_get_out(data, chan, val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + if (chan->type != IIO_TEMP) + return -EINVAL; + + *val = FXLS8962AF_TEMP_CENTER_VAL; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + return fxls8962af_read_full_scale(data, val2); + default: + return -EINVAL; + } +} + +static int fxls8962af_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (val != 0) + return -EINVAL; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = fxls8962af_set_full_scale(data, val2); + + iio_device_release_direct_mode(indio_dev); + return ret; + default: + return -EINVAL; + } +} + +#define FXLS8962AF_CHANNEL(axis, reg, idx) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = idx, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 4, \ + .endianness = IIO_BE, \ + }, \ +} + +#define FXLS8962AF_TEMP_CHANNEL { \ + .type = IIO_TEMP, \ + .address = FXLS8962AF_TEMP_OUT, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET),\ + .scan_index = -1, \ + .scan_type = { \ + .realbits = 8, \ + .storagebits = 8, \ + }, \ +} + +static const struct iio_chan_spec fxls8962af_channels[] = { + FXLS8962AF_CHANNEL(X, FXLS8962AF_OUT_X_LSB, fxls8962af_idx_x), + FXLS8962AF_CHANNEL(Y, FXLS8962AF_OUT_Y_LSB, fxls8962af_idx_y), + FXLS8962AF_CHANNEL(Z, FXLS8962AF_OUT_Z_LSB, fxls8962af_idx_z), + IIO_CHAN_SOFT_TIMESTAMP(fxls8962af_idx_ts), + FXLS8962AF_TEMP_CHANNEL, +}; + +static const struct fxls8962af_chip_info fxls_chip_info_table[] = { + [fxls8962af] = { + .chip_id = FXLS8962AF_DEVICE_ID, + .name = "fxls8962af", + .channels = fxls8962af_channels, + .num_channels = ARRAY_SIZE(fxls8962af_channels), + }, + [fxls8964af] = { + .chip_id = FXLS8964AF_DEVICE_ID, + .name = "fxls8964af", + .channels = fxls8962af_channels, + .num_channels = ARRAY_SIZE(fxls8962af_channels), + }, +}; + +static const struct iio_info fxls8962af_info = { + .read_raw = &fxls8962af_read_raw, + .write_raw = &fxls8962af_write_raw, + .write_raw_get_fmt = fxls8962af_write_raw_get_fmt, + .read_avail = fxls8962af_read_avail, +}; + +static int fxls8962af_reset(struct fxls8962af_data *data) +{ + struct device *dev = regmap_get_device(data->regmap); + unsigned int reg; + int ret; + + ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_RST, + FXLS8962AF_SENS_CONFIG1_RST); + if (ret < 0) + return ret; + + /* TBOOT1, TBOOT2, specifies we have to wait between 1 - 17.7ms */ + ret = regmap_read_poll_timeout(data->regmap, FXLS8962AF_INT_STATUS, reg, + (reg & FXLS8962AF_INT_STATUS_SRC_BOOT), 1000, 18000); + if (ret) + dev_err(dev, "reset timeout, int_status = 0x%x\n", reg); + + return ret; +} + +static void fxls8962af_regulator_disable(void *data_ptr) +{ + struct fxls8962af_data *data = data_ptr; + + regulator_disable(data->vdd_reg); +} + +static void fxls8962af_pm_disable(void *dev_ptr) +{ + struct device *dev = dev_ptr; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); + + fxls8962af_standby(iio_priv(indio_dev)); +} + +int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) +{ + struct fxls8962af_data *data; + struct iio_dev *indio_dev; + unsigned int reg; + int ret, i; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + dev_set_drvdata(dev, indio_dev); + data->regmap = regmap; + + ret = iio_read_mount_matrix(dev, "mount-matrix", &data->orientation); + if (ret) + return ret; + + data->vdd_reg = devm_regulator_get(dev, "vdd"); + if (IS_ERR(data->vdd_reg)) + return dev_err_probe(dev, PTR_ERR(data->vdd_reg), + "Failed to get vdd regulator\n"); + + ret = regulator_enable(data->vdd_reg); + if (ret) { + dev_err(dev, "Failed to enable vdd regulator: %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(dev, fxls8962af_regulator_disable, data); + if (ret) + return ret; + + ret = regmap_read(data->regmap, FXLS8962AF_WHO_AM_I, ®); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(fxls_chip_info_table); i++) { + if (fxls_chip_info_table[i].chip_id == reg) { + data->chip_info = &fxls_chip_info_table[i]; + break; + } + } + if (i == ARRAY_SIZE(fxls_chip_info_table)) { + dev_err(dev, "failed to match device in table\n"); + return -ENXIO; + } + + indio_dev->channels = data->chip_info->channels; + indio_dev->num_channels = data->chip_info->num_channels; + indio_dev->name = data->chip_info->name; + indio_dev->info = &fxls8962af_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = fxls8962af_reset(data); + if (ret < 0) + return ret; + + ret = pm_runtime_set_active(dev); + if (ret < 0) + return ret; + + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, FXLS8962AF_AUTO_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + + ret = devm_add_action_or_reset(dev, fxls8962af_pm_disable, dev); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_GPL(fxls8962af_core_probe); + +static int __maybe_unused fxls8962af_runtime_suspend(struct device *dev) +{ + struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + ret = fxls8962af_standby(data); + if (ret < 0) { + dev_err(dev, "powering off device failed\n"); + return ret; + } + + return 0; +} + +static int __maybe_unused fxls8962af_runtime_resume(struct device *dev) +{ + struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev)); + + return fxls8962af_active(data); +} + +const struct dev_pm_ops fxls8962af_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(fxls8962af_runtime_suspend, + fxls8962af_runtime_resume, NULL) +}; +EXPORT_SYMBOL_GPL(fxls8962af_pm_ops); + +MODULE_AUTHOR("Sean Nyekjaer "); +MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c new file mode 100644 index 000000000000..cba12160a714 --- /dev/null +++ b/drivers/iio/accel/fxls8962af-i2c.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver + * + * Copyright 2021 Connected Cars A/S + */ + +#include +#include +#include +#include +#include +#include + +#include "fxls8962af.h" + +static int fxls8962af_probe(struct i2c_client *client) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, &fxls8962af_regmap_conf); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Failed to initialize i2c regmap\n"); + return PTR_ERR(regmap); + } + + return fxls8962af_core_probe(&client->dev, regmap, client->irq); +} + +static const struct i2c_device_id fxls8962af_id[] = { + {"fxls8962af", fxls8962af}, + {"fxls8964af", fxls8964af}, + {} +}; +MODULE_DEVICE_TABLE(i2c, fxls8962af_id); + +static const struct of_device_id fxls8962af_of_match[] = { + {.compatible = "nxp,fxls8962af"}, + {.compatible = "nxp,fxls8964af"}, + {} +}; +MODULE_DEVICE_TABLE(of, fxls8962af_of_match); + +static struct i2c_driver fxls8962af_driver = { + .driver = { + .name = "fxls8962af_i2c", + .of_match_table = fxls8962af_of_match, + .pm = &fxls8962af_pm_ops, + }, + .probe_new = fxls8962af_probe, + .id_table = fxls8962af_id, +}; +module_i2c_driver(fxls8962af_driver); + +MODULE_AUTHOR("Sean Nyekjaer "); +MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer i2c driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c new file mode 100644 index 000000000000..cb971b76d135 --- /dev/null +++ b/drivers/iio/accel/fxls8962af-spi.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NXP FXLS8962AF/FXLS8964AF Accelerometer SPI Driver + * + * Copyright 2021 Connected Cars A/S + */ + +#include +#include +#include +#include +#include +#include + +#include "fxls8962af.h" + +static int fxls8962af_probe(struct spi_device *spi) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &fxls8962af_regmap_conf); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Failed to initialize spi regmap\n"); + return PTR_ERR(regmap); + } + + return fxls8962af_core_probe(&spi->dev, regmap, spi->irq); +} + +static const struct of_device_id fxls8962af_spi_of_match[] = { + {.compatible = "nxp,fxls8962af"}, + {.compatible = "nxp,fxls8964af"}, + {} +}; +MODULE_DEVICE_TABLE(of, fxls8962af_spi_of_match); + +static const struct spi_device_id fxls8962af_spi_id_table[] = { + {"fxls8962af", fxls8962af}, + {"fxls8964af", fxls8964af}, + {} +}; +MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table); + +static struct spi_driver fxls8962af_driver = { + .driver = { + .name = "fxls8962af_spi", + .pm = &fxls8962af_pm_ops, + .of_match_table = fxls8962af_spi_of_match, + }, + .probe = fxls8962af_probe, + .id_table = fxls8962af_spi_id_table, +}; +module_spi_driver(fxls8962af_driver); + +MODULE_AUTHOR("Sean Nyekjaer "); +MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer spi driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/fxls8962af.h b/drivers/iio/accel/fxls8962af.h new file mode 100644 index 000000000000..b67572c3ef06 --- /dev/null +++ b/drivers/iio/accel/fxls8962af.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2021 Connected Cars A/S + */ +#ifndef _FXLS8962AF_H_ +#define _FXLS8962AF_H_ + +struct regmap; +struct device; + +enum { + fxls8962af, + fxls8964af, +}; + +int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq); +int fxls8962af_core_remove(struct device *dev); + +extern const struct dev_pm_ops fxls8962af_pm_ops; +extern const struct regmap_config fxls8962af_regmap_conf; + +#endif /* _FXLS8962AF_H_ */ From patchwork Thu Apr 29 12:28:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Nyekjaer X-Patchwork-Id: 12231201 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 12FFDC433ED for ; Thu, 29 Apr 2021 12:28:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D9915613F9 for ; Thu, 29 Apr 2021 12:28:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236023AbhD2M3H (ORCPT ); Thu, 29 Apr 2021 08:29:07 -0400 Received: from first.geanix.com ([116.203.34.67]:50662 "EHLO first.geanix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231921AbhD2M3E (ORCPT ); Thu, 29 Apr 2021 08:29:04 -0400 Received: from zen.. (unknown [185.17.218.86]) by first.geanix.com (Postfix) with ESMTPSA id 6FFEE466691; Thu, 29 Apr 2021 12:28:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=geanix.com; s=first; t=1619699295; bh=ymsLxXP9ghfB0wkC3srQUsvk6sfYv6cwu2Grlc3BKn4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=XnNYAYDDZHvIvoXjAWQNKFZaQ8vSzGqOG/rbe9mU0wZP+nnl325DX9k4aw0bzXBAM BEIl6Qe+W367RzJgEdFIODY0BIyammoIsJ37KI44o9jLLggLIt6ngR9ivOLVr1i493 7wbihseMH1mDA+tMtlQpY4qdqESPaY+dgk4V9cIww28r2SXrc4luHkurDslQYvGCyh 4k8DdRB2nltFMcGgnopRTwyumEZ0TZlx7fczlHb9bUEydYFihopEErA9hk+FUjcVlI BQcK5Q0OX9O8Ar2LqAjbaVvJq147dU5fOZlmbu0nqPOqlVAYCHVMe1CwzWZ/iwoCrZ YiNVuJffm2wGQ== From: Sean Nyekjaer To: jic23@kernel.org, linux-iio@vger.kernel.org, andy.shevchenko@gmail.com, lars@metafoo.de, Nuno.Sa@analog.com, robh+dt@kernel.org, devicetree@vger.kernel.org Cc: Sean Nyekjaer Subject: [PATCH v4 2/6] dt-bindings: iio: accel: fxls8962af: add bindings Date: Thu, 29 Apr 2021 14:28:02 +0200 Message-Id: <20210429122806.3814330-2-sean@geanix.com> X-Mailer: git-send-email 2.31.0 In-Reply-To: <20210429122806.3814330-1-sean@geanix.com> References: <20210429122806.3814330-1-sean@geanix.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Add devicetree binding for the NXP FXLS8962AF/FXLS8964AF accelerometer sensor. Signed-off-by: Sean Nyekjaer --- Changes for v2: - removed requirement for interrupt Changes for v3: - None Changes for v4: - Included the dt patch from the RFC .../bindings/iio/accel/nxp,fxls8962af.yaml | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/accel/nxp,fxls8962af.yaml diff --git a/Documentation/devicetree/bindings/iio/accel/nxp,fxls8962af.yaml b/Documentation/devicetree/bindings/iio/accel/nxp,fxls8962af.yaml new file mode 100644 index 000000000000..e0e5542377df --- /dev/null +++ b/Documentation/devicetree/bindings/iio/accel/nxp,fxls8962af.yaml @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/accel/nxp,fxls8962af.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP FXLS8962AF/FXLS8964AF Accelerometer driver + +maintainers: + - Sean Nyekjaer + +description: | + NXP FXLS8962AF/FXLS8964AF Accelerometer driver that supports + SPI and I2C interface. + https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf + https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf + +properties: + compatible: + enum: + - nxp,fxls8962af + - nxp,fxls8964af + + reg: + maxItems: 1 + + vdd-supply: + description: phandle to the regulator that provides power to the accelerometer + + spi-max-frequency: true + + interrupts: + maxItems: 1 + + interrupt-names: + maxItems: 1 + items: + enum: + - INT1 + - INT2 + + drive-open-drain: + type: boolean + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + /* Example for a I2C device node */ + accelerometer@62 { + compatible = "nxp,fxls8962af"; + reg = <0x62>; + interrupt-parent = <&gpio0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "INT1"; + }; + }; + - | + #include + spi0 { + #address-cells = <1>; + #size-cells = <0>; + + /* Example for a SPI device node */ + accelerometer@0 { + compatible = "nxp,fxls8962af"; + reg = <0>; + spi-max-frequency = <4000000>; + interrupt-parent = <&gpio0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "INT1"; + }; + }; From patchwork Thu Apr 29 12:28:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Nyekjaer X-Patchwork-Id: 12231199 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C85DC43600 for ; Thu, 29 Apr 2021 12:28:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 49134613F9 for ; Thu, 29 Apr 2021 12:28:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234473AbhD2M3I (ORCPT ); Thu, 29 Apr 2021 08:29:08 -0400 Received: from first.geanix.com ([116.203.34.67]:50672 "EHLO first.geanix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232657AbhD2M3F (ORCPT ); Thu, 29 Apr 2021 08:29:05 -0400 Received: from zen.. (unknown [185.17.218.86]) by first.geanix.com (Postfix) with ESMTPSA id BBB7A466693; Thu, 29 Apr 2021 12:28:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=geanix.com; s=first; t=1619699296; bh=9RFIp34R8dOCPLYSj4YJHVUXoQjw99Td2vb3UssDJec=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=EmKa7lKoZ77N+iWfoN0d6HWrCoi85XEJmBn6LeVY7kp1vPMJTy4n7liS6UpuFpB3G 5UNFOgHOkadlBZPFlWUA5hZtyp+pu4V1gahtyo7DsY0jXBZw+VhbGY2reATLKY8Obc 8DJeAgsqaaKmK6DjFr94kFNInpyYdGBmIW5Vdo9zLjAyI5rzHhfkWT+1fR8bsJOV2P hC582v5SJbp8jR1Hng4EIA/j5IhxiC0LdcMCym1qWqKO2RDJPkhmuQ5X2UNXreiCiK uVrp87dTnMD10LQBVO25mPOfQxEeFssL3+7jO1acuJz9SzYb11qo7/PB8w7FUxPrYq 7GjMenh1upJ+g== From: Sean Nyekjaer To: jic23@kernel.org, linux-iio@vger.kernel.org, andy.shevchenko@gmail.com, lars@metafoo.de, Nuno.Sa@analog.com, robh+dt@kernel.org, devicetree@vger.kernel.org Cc: Sean Nyekjaer Subject: [PATCH v4 3/6] iio: accel: fxls8962af: add set/get of samplerate Date: Thu, 29 Apr 2021 14:28:03 +0200 Message-Id: <20210429122806.3814330-3-sean@geanix.com> X-Mailer: git-send-email 2.31.0 In-Reply-To: <20210429122806.3814330-1-sean@geanix.com> References: <20210429122806.3814330-1-sean@geanix.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org This adds support for setting de accelerometers output data rate. Primarily used for hardware buffered reads. Signed-off-by: Sean Nyekjaer --- drivers/iio/accel/fxls8962af-core.c | 77 +++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 6ae47eac4490..9de30e8539b1 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -50,6 +50,9 @@ #define FXLS8962AF_SENS_CONFIG2 0x16 #define FXLS8962AF_SENS_CONFIG3 0x17 +#define FXLS8962AF_SC3_WAKE_ODR_MASK GENMASK(7, 4) +#define FXLS8962AF_SC3_WAKE_ODR_PREP(x) FIELD_PREP(FXLS8962AF_SC3_WAKE_ODR_MASK, (x)) +#define FXLS8962AF_SC3_WAKE_ODR_GET(x) FIELD_GET(FXLS8962AF_SC3_WAKE_ODR_MASK, (x)) #define FXLS8962AF_SENS_CONFIG4 0x18 #define FXLS8962AF_SENS_CONFIG5 0x19 @@ -96,6 +99,7 @@ #define FXLS8962AF_AUTO_SUSPEND_DELAY_MS 2000 #define FXLS8962AF_SCALE_TABLE_LEN 4 +#define FXLS8962AF_SAMP_FREQ_TABLE_LEN 13 static const int fxls8962af_scale_table[FXLS8962AF_SCALE_TABLE_LEN][2] = { {0, IIO_G_TO_M_S_2(980000)}, @@ -104,6 +108,12 @@ static const int fxls8962af_scale_table[FXLS8962AF_SCALE_TABLE_LEN][2] = { {0, IIO_G_TO_M_S_2(7810000)}, }; +static const int fxls8962af_samp_freq_table[FXLS8962AF_SAMP_FREQ_TABLE_LEN][2] = { + {3200, 0}, {1600, 0}, {800, 0}, {400, 0}, {200, 0}, {100, 0}, + {50, 0}, {25, 0}, {12, 500000}, {6, 250000}, {3, 125000}, + {1, 563000}, {0, 781000}, +}; + struct fxls8962af_chip_info { const char *name; const struct iio_chan_spec *channels; @@ -228,6 +238,11 @@ static int fxls8962af_read_avail(struct iio_dev *indio_dev, *vals = (int *)fxls8962af_scale_table; *length = ARRAY_SIZE(fxls8962af_scale_table) * 2; return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT_PLUS_MICRO; + *vals = (int *)fxls8962af_samp_freq_table; + *length = ARRAY_SIZE(fxls8962af_samp_freq_table) * 2; + return IIO_AVAIL_LIST; default: return -EINVAL; } @@ -237,7 +252,14 @@ static int fxls8962af_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, long mask) { - return IIO_VAL_INT_PLUS_NANO; + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT_PLUS_MICRO; + default: + return IIO_VAL_INT_PLUS_NANO; + } } static int fxls8962af_update_config(struct fxls8962af_data *data, u8 reg, @@ -300,6 +322,42 @@ static unsigned int fxls8962af_read_full_scale(struct fxls8962af_data *data, return IIO_VAL_INT_PLUS_NANO; } +static int fxls8962af_set_samp_freq(struct fxls8962af_data *data, u32 val, u32 val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fxls8962af_samp_freq_table); i++) + if (val == fxls8962af_samp_freq_table[i][0] && + val2 == fxls8962af_samp_freq_table[i][1]) + break; + + if (i == ARRAY_SIZE(fxls8962af_samp_freq_table)) + return -EINVAL; + + return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG3, + FXLS8962AF_SC3_WAKE_ODR_MASK, + FXLS8962AF_SC3_WAKE_ODR_PREP(i)); +} + +static unsigned int fxls8962af_read_samp_freq(struct fxls8962af_data *data, + int *val, int *val2) +{ + int ret; + unsigned int reg; + u8 range_idx; + + ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG3, ®); + if (ret < 0) + return ret; + + range_idx = FXLS8962AF_SC3_WAKE_ODR_GET(reg); + + *val = fxls8962af_samp_freq_table[range_idx][0]; + *val2 = fxls8962af_samp_freq_table[range_idx][1]; + + return IIO_VAL_INT_PLUS_MICRO; +} + static int fxls8962af_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -324,6 +382,8 @@ static int fxls8962af_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: *val = 0; return fxls8962af_read_full_scale(data, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + return fxls8962af_read_samp_freq(data, val, val2); default: return -EINVAL; } @@ -347,6 +407,15 @@ static int fxls8962af_write_raw(struct iio_dev *indio_dev, ret = fxls8962af_set_full_scale(data, val2); + iio_device_release_direct_mode(indio_dev); + return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = fxls8962af_set_samp_freq(data, val, val2); + iio_device_release_direct_mode(indio_dev); return ret; default: @@ -360,8 +429,10 @@ static int fxls8962af_write_raw(struct iio_dev *indio_dev, .modified = 1, \ .channel2 = IIO_MOD_##axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .scan_index = idx, \ .scan_type = { \ .sign = 's', \ From patchwork Thu Apr 29 12:28:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Nyekjaer X-Patchwork-Id: 12231203 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.9 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, UNWANTED_LANGUAGE_BODY,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 950C4C43603 for ; Thu, 29 Apr 2021 12:28:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7113E613F4 for ; Thu, 29 Apr 2021 12:28:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232657AbhD2M3I (ORCPT ); Thu, 29 Apr 2021 08:29:08 -0400 Received: from first.geanix.com ([116.203.34.67]:50676 "EHLO first.geanix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234147AbhD2M3H (ORCPT ); Thu, 29 Apr 2021 08:29:07 -0400 Received: from zen.. (unknown [185.17.218.86]) by first.geanix.com (Postfix) with ESMTPSA id 33082466694; Thu, 29 Apr 2021 12:28:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=geanix.com; s=first; t=1619699298; bh=t2nOExvUWFV6hW1+7WzgJD61WEA4HpnmlKhS9gzZprE=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=WuJjSJiooQMjWk365wKYgsbzdYOQEhWWXuKV5ndAE75j4NFnXVBYgzIP/gUDVsK/g 0xJsjPTp5B7Hr9Y/9gRZ5uRtnsLxWzn7ORK5dTlrAJROVjyzZPsJ3ge925t1kc+lCf HkAXUEiiSkFHxYXxyIugEc7Bmtx4ZCUqxM32Id3cp1ar4fbMFJFKMXLYjUI0H+iGn8 R/YU13nC1fKbiztoKR1TrvwqBPfFmFV7Uh696Jg4L+RxWevUUcn3bU5UU9pQlJBcoS hX5lF6vPeR5gjntft7NwTCArAzFR/gvYaa2mqxNT6z3VizJfwKW/iwhr6Jp538e9Tt h0oIk+Nu9keuA== From: Sean Nyekjaer To: jic23@kernel.org, linux-iio@vger.kernel.org, andy.shevchenko@gmail.com, lars@metafoo.de, Nuno.Sa@analog.com, robh+dt@kernel.org, devicetree@vger.kernel.org Cc: Sean Nyekjaer Subject: [PATCH v4 4/6] iio: accel: fxls8962af: add interrupt support Date: Thu, 29 Apr 2021 14:28:04 +0200 Message-Id: <20210429122806.3814330-4-sean@geanix.com> X-Mailer: git-send-email 2.31.0 In-Reply-To: <20210429122806.3814330-1-sean@geanix.com> References: <20210429122806.3814330-1-sean@geanix.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Preparation commit for the next that adds hw buffered sampling Signed-off-by: Sean Nyekjaer --- Changes from RFC: - Changed of_irq_get_byname -> device_property_match_string?? Lars / Andy ?? drivers/iio/accel/fxls8962af-core.c | 111 ++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 9de30e8539b1..3696546fe23a 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,10 @@ #define FXLS8962AF_SC3_WAKE_ODR_PREP(x) FIELD_PREP(FXLS8962AF_SC3_WAKE_ODR_MASK, (x)) #define FXLS8962AF_SC3_WAKE_ODR_GET(x) FIELD_GET(FXLS8962AF_SC3_WAKE_ODR_MASK, (x)) #define FXLS8962AF_SENS_CONFIG4 0x18 +#define FXLS8962AF_SC4_INT_PP_OD_MASK BIT(1) +#define FXLS8962AF_SC4_INT_PP_OD_PREP(x) FIELD_PREP(FXLS8962AF_SC4_INT_PP_OD_MASK, (x)) +#define FXLS8962AF_SC4_INT_POL_MASK BIT(0) +#define FXLS8962AF_SC4_INT_POL_PREP(x) FIELD_PREP(FXLS8962AF_SC4_INT_POL_MASK, (x)) #define FXLS8962AF_SENS_CONFIG5 0x19 #define FXLS8962AF_WAKE_IDLE_LSB 0x1b @@ -62,6 +67,9 @@ #define FXLS8962AF_INT_EN 0x20 #define FXLS8962AF_INT_PIN_SEL 0x21 +#define FXLS8962AF_INT_PIN_SEL_MASK GENMASK(7, 0) +#define FXLS8962AF_INT_PIN_SEL_INT1 0x00 +#define FXLS8962AF_INT_PIN_SEL_INT2 GENMASK(7, 0) #define FXLS8962AF_OFF_X 0x22 #define FXLS8962AF_OFF_Y 0x23 @@ -142,6 +150,11 @@ enum { fxls8962af_idx_ts, }; +enum fxls8962af_int_pin { + FXLS8962AF_PIN_INT1, + FXLS8962AF_PIN_INT2, +}; + static int fxls8962af_power_on(struct fxls8962af_data *data) { struct device *dev = regmap_get_device(data->regmap); @@ -506,6 +519,20 @@ static int fxls8962af_reset(struct fxls8962af_data *data) return ret; } +static irqreturn_t fxls8962af_interrupt(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct fxls8962af_data *data = iio_priv(indio_dev); + unsigned int reg; + int ret; + + ret = regmap_read(data->regmap, FXLS8962AF_INT_STATUS, ®); + if (ret < 0) + return IRQ_NONE; + + return IRQ_NONE; +} + static void fxls8962af_regulator_disable(void *data_ptr) { struct fxls8962af_data *data = data_ptr; @@ -525,6 +552,84 @@ static void fxls8962af_pm_disable(void *dev_ptr) fxls8962af_standby(iio_priv(indio_dev)); } +static void fxls8962af_get_irq(struct device *dev, enum fxls8962af_int_pin *pin) +{ + if (!device_property_match_string(dev, "interrupt-names", "INT2")) { + *pin = FXLS8962AF_PIN_INT2; + return; + } + + *pin = FXLS8962AF_PIN_INT1; +} + +static int fxls8962af_irq_setup(struct iio_dev *indio_dev, int irq) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + struct device *dev = regmap_get_device(data->regmap); + unsigned long irq_type; + bool irq_active_high; + enum fxls8962af_int_pin int_pin; + u8 int_pin_sel; + int ret; + + fxls8962af_get_irq(dev, &int_pin); + switch (int_pin) { + case FXLS8962AF_PIN_INT1: + int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT1; + break; + case FXLS8962AF_PIN_INT2: + int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT2; + break; + default: + dev_err(dev, "unsupported int pin selected\n"); + return -EINVAL; + } + + ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_PIN_SEL, + FXLS8962AF_INT_PIN_SEL_MASK, + int_pin_sel); + if (ret) + return ret; + + irq_type = irqd_get_trigger_type(irq_get_irq_data(irq)); + + switch (irq_type) { + case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: + irq_active_high = true; + break; + case IRQF_TRIGGER_LOW: + case IRQF_TRIGGER_FALLING: + irq_active_high = false; + break; + default: + dev_info(dev, "mode %lx unsupported\n", irq_type); + return -EINVAL; + } + + ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG4, + FXLS8962AF_SC4_INT_POL_MASK, + FXLS8962AF_SC4_INT_POL_PREP(irq_active_high)); + if (ret < 0) + return ret; + + if (device_property_read_bool(dev, "drive-open-drain")) { + ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG4, + FXLS8962AF_SC4_INT_PP_OD_MASK, + FXLS8962AF_SC4_INT_PP_OD_PREP(1)); + if (ret < 0) + return ret; + + irq_type |= IRQF_SHARED; + } + + return devm_request_threaded_irq(dev, + irq, + NULL, fxls8962af_interrupt, + irq_type | IRQF_ONESHOT, + indio_dev->name, indio_dev); +} + int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) { struct fxls8962af_data *data; @@ -584,6 +689,12 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) if (ret < 0) return ret; + if (irq) { + ret = fxls8962af_irq_setup(indio_dev, irq); + if (ret < 0) + return ret; + } + ret = pm_runtime_set_active(dev); if (ret < 0) return ret; From patchwork Thu Apr 29 12:28:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Nyekjaer X-Patchwork-Id: 12231205 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.9 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, UNWANTED_LANGUAGE_BODY,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9E340C4360C for ; Thu, 29 Apr 2021 12:28:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 88F81613E1 for ; Thu, 29 Apr 2021 12:28:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235470AbhD2M3J (ORCPT ); Thu, 29 Apr 2021 08:29:09 -0400 Received: from first.geanix.com ([116.203.34.67]:50672 "EHLO first.geanix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233731AbhD2M3I (ORCPT ); Thu, 29 Apr 2021 08:29:08 -0400 Received: from zen.. (unknown [185.17.218.86]) by first.geanix.com (Postfix) with ESMTPSA id 97F18466697; Thu, 29 Apr 2021 12:28:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=geanix.com; s=first; t=1619699299; bh=9KNwoN/9slPsT4i6pDC3pLpd9Ibh66p8L4fF3y6OuDk=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=M5cl237IskeBgudhtsPMMBGFxTAEr/48TpWY0Td6CdAEa9oBbXCiYM6FXxcYK9Byl HqGuTwQhavRBasOm5ST8VP0UFkZr1VdnzdDHCVFHYCYmfBm8nLEKZL64vjN4G7Vn8+ c6k2hwLZgzhqo3o1ccP6lNjkZ2axpMXlpXTXB6yMf2cCzugOxvpfpsiMbO0Tym1Du6 Lvs2srsolHzREbcap0gMI9/ednIZOdunbMi4bdYGPgT7WaQEFFZUOQQV12MnExOlJg 9/zZc6MrfeKPthhylRLHXFaCWmIf752g+NMhkRqjLAMl5IUS0TxQEa+t7R6oLxnBJv tkFmrQERJ85sQ== From: Sean Nyekjaer To: jic23@kernel.org, linux-iio@vger.kernel.org, andy.shevchenko@gmail.com, lars@metafoo.de, Nuno.Sa@analog.com, robh+dt@kernel.org, devicetree@vger.kernel.org Cc: Sean Nyekjaer Subject: [PATCH v4 5/6] iio: accel: fxls8962af: add hw buffered sampling Date: Thu, 29 Apr 2021 14:28:05 +0200 Message-Id: <20210429122806.3814330-5-sean@geanix.com> X-Mailer: git-send-email 2.31.0 In-Reply-To: <20210429122806.3814330-1-sean@geanix.com> References: <20210429122806.3814330-1-sean@geanix.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org When buffered sampling is enabled, the accelerometer will dump data into the internal fifo and interrupt at watermark. Then the driver flushes all data to the iio buffer. As the accelerometer doesn't have internal timestamps, they are approximated between the current and last interrupt. Signed-off-by: Sean Nyekjaer --- Changes from RFC: - Dropped the claim stuff for read_raw - Added watermark get/set - Consistent use of u16 for buffer size drivers/iio/accel/fxls8962af-core.c | 208 ++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 3696546fe23a..2e863ef71a7d 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -20,13 +20,17 @@ #include #include +#include #include +#include #include +#include #include "fxls8962af.h" #define FXLS8962AF_INT_STATUS 0x00 #define FXLS8962AF_INT_STATUS_SRC_BOOT BIT(0) +#define FXLS8962AF_INT_STATUS_SRC_BUF BIT(5) #define FXLS8962AF_INT_STATUS_SRC_DRDY BIT(7) #define FXLS8962AF_TEMP_OUT 0x01 #define FXLS8962AF_VECM_LSB 0x02 @@ -34,6 +38,9 @@ #define FXLS8962AF_OUT_Y_LSB 0x06 #define FXLS8962AF_OUT_Z_LSB 0x08 #define FXLS8962AF_BUF_STATUS 0x0b +#define FXLS8962AF_BUF_STATUS_BUF_CNT GENMASK(5, 0) +#define FXLS8962AF_BUF_STATUS_BUF_OVF BIT(6) +#define FXLS8962AF_BUF_STATUS_BUF_WMRK BIT(7) #define FXLS8962AF_BUF_X_LSB 0x0c #define FXLS8962AF_BUF_Y_LSB 0x0e #define FXLS8962AF_BUF_Z_LSB 0x10 @@ -66,6 +73,7 @@ #define FXLS8962AF_ASLP_COUNT_LSB 0x1e #define FXLS8962AF_INT_EN 0x20 +#define FXLS8962AF_INT_EN_BUF_EN BIT(6) #define FXLS8962AF_INT_PIN_SEL 0x21 #define FXLS8962AF_INT_PIN_SEL_MASK GENMASK(7, 0) #define FXLS8962AF_INT_PIN_SEL_INT1 0x00 @@ -76,7 +84,10 @@ #define FXLS8962AF_OFF_Z 0x24 #define FXLS8962AF_BUF_CONFIG1 0x26 +#define FXLS8962AF_BC1_BUF_MODE_MASK GENMASK(6, 5) +#define FXLS8962AF_BC1_BUF_MODE_PREP(x) FIELD_PREP(FXLS8962AF_BC1_BUF_MODE_MASK, (x)) #define FXLS8962AF_BUF_CONFIG2 0x27 +#define FXLS8962AF_BUF_CONFIG2_BUF_WMRK GENMASK(5, 0) #define FXLS8962AF_ORIENT_STATUS 0x28 #define FXLS8962AF_ORIENT_CONFIG 0x29 @@ -106,6 +117,7 @@ #define FXLS8962AF_AUTO_SUSPEND_DELAY_MS 2000 +#define FXLS8962AF_FIFO_LENGTH 32 #define FXLS8962AF_SCALE_TABLE_LEN 4 #define FXLS8962AF_SAMP_FREQ_TABLE_LEN 13 @@ -133,7 +145,13 @@ struct fxls8962af_data { struct regmap *regmap; const struct fxls8962af_chip_info *chip_info; struct regulator *vdd_reg; + struct { + __le16 channels[3]; + s64 ts __aligned(8); + } scan; + int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ struct iio_mount_matrix orientation; + u8 watermark; }; const struct regmap_config fxls8962af_regmap_conf = { @@ -436,6 +454,18 @@ static int fxls8962af_write_raw(struct iio_dev *indio_dev, } } +static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + + if (val > FXLS8962AF_FIFO_LENGTH) + val = FXLS8962AF_FIFO_LENGTH; + + data->watermark = val; + + return 0; +} + #define FXLS8962AF_CHANNEL(axis, reg, idx) { \ .type = IIO_ACCEL, \ .address = reg, \ @@ -496,6 +526,7 @@ static const struct iio_info fxls8962af_info = { .write_raw = &fxls8962af_write_raw, .write_raw_get_fmt = fxls8962af_write_raw_get_fmt, .read_avail = fxls8962af_read_avail, + .hwfifo_set_watermark = fxls8962af_set_watermark, }; static int fxls8962af_reset(struct fxls8962af_data *data) @@ -519,6 +550,158 @@ static int fxls8962af_reset(struct fxls8962af_data *data) return ret; } +static int __fxls8962af_fifo_set_mode(struct fxls8962af_data *data, bool onoff) +{ + int ret; + + /* Enable watermark at max fifo size*/ + ret = regmap_update_bits(data->regmap, FXLS8962AF_BUF_CONFIG2, + FXLS8962AF_BUF_CONFIG2_BUF_WMRK, + data->watermark); + if (ret < 0) + return ret; + + return regmap_update_bits(data->regmap, FXLS8962AF_BUF_CONFIG1, + FXLS8962AF_BC1_BUF_MODE_MASK, + FXLS8962AF_BC1_BUF_MODE_PREP(onoff)); +} + +static int fxls8962af_buffer_preenable(struct iio_dev *indio_dev) +{ + return fxls8962af_power_on(iio_priv(indio_dev)); +} + +static int fxls8962af_buffer_postenable(struct iio_dev *indio_dev) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + int ret; + + fxls8962af_standby(data); + + /* Enable buffer interrupt*/ + ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, + FXLS8962AF_INT_EN_BUF_EN, + FXLS8962AF_INT_EN_BUF_EN); + if (ret < 0) + return ret; + + ret = __fxls8962af_fifo_set_mode(data, true); + + fxls8962af_active(data); + + return ret; +} + +static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + int ret = 0; + + fxls8962af_standby(data); + + /* Disable buffer interrupt*/ + ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, + FXLS8962AF_INT_EN_BUF_EN, 0); + if (ret < 0) + return ret; + + ret = __fxls8962af_fifo_set_mode(data, false); + + fxls8962af_active(data); + + return ret; +} + +static int fxls8962af_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + + return fxls8962af_power_off(data); +} + +static const struct iio_buffer_setup_ops fxls8962af_buffer_ops = { + .preenable = fxls8962af_buffer_preenable, + .postenable = fxls8962af_buffer_postenable, + .predisable = fxls8962af_buffer_predisable, + .postdisable = fxls8962af_buffer_postdisable, +}; + +static int fxls8962af_fifo_transfer(struct fxls8962af_data *data, + u16 *buffer, int samples) +{ + struct device *dev = regmap_get_device(data->regmap); + int sample_length = 3 * sizeof(*buffer); + int ret; + int total_length = samples * sample_length; + + ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, buffer, + total_length); + if (ret < 0) + dev_err(dev, "Error transferring data from fifo: %d\n", ret); + + return ret; +} + +static int fxls8962af_fifo_flush(struct iio_dev *indio_dev) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + struct device *dev = regmap_get_device(data->regmap); + u16 buffer[FXLS8962AF_FIFO_LENGTH * 3]; + uint64_t sample_period; + unsigned int reg; + int64_t tstamp; + int ret, i; + u8 count; + + ret = regmap_read(data->regmap, FXLS8962AF_BUF_STATUS, ®); + if (ret < 0) + return ret; + + if (reg & FXLS8962AF_BUF_STATUS_BUF_OVF) { + dev_err(dev, "Buffer overflown"); + return -1; + } + + count = reg & FXLS8962AF_BUF_STATUS_BUF_CNT; + + if (!count) + return 0; + + data->old_timestamp = data->timestamp; + data->timestamp = iio_get_time_ns(indio_dev); + + /* + * Approximate timestamps for each of the sample based on the sampling, + * frequency, timestamp for last sample and number of samples. + */ + sample_period = (data->timestamp - data->old_timestamp); + do_div(sample_period, count); + tstamp = data->timestamp - (count - 1) * sample_period; + + ret = fxls8962af_fifo_transfer(data, buffer, count); + if (ret) + return ret; + + /* Demux hw FIFO into kfifo. */ + for (i = 0; i < count; i++) { + int j, bit; + + j = 0; + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->masklength) { + memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit], + sizeof(data->scan.channels[0])); + } + + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, + tstamp); + + tstamp += sample_period; + } + + return count; +} + static irqreturn_t fxls8962af_interrupt(int irq, void *p) { struct iio_dev *indio_dev = p; @@ -530,9 +713,32 @@ static irqreturn_t fxls8962af_interrupt(int irq, void *p) if (ret < 0) return IRQ_NONE; + if (reg & FXLS8962AF_INT_STATUS_SRC_BUF) { + ret = fxls8962af_fifo_flush(indio_dev); + if (ret < 0) + return IRQ_NONE; + + return IRQ_HANDLED; + } + return IRQ_NONE; } +static int fxls8962af_fifo_setup(struct iio_dev *indio_dev) +{ + struct iio_buffer *buffer; + + buffer = devm_iio_kfifo_allocate(&indio_dev->dev); + if (!buffer) + return -ENOMEM; + + iio_device_attach_buffer(indio_dev, buffer); + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; + indio_dev->setup_ops = &fxls8962af_buffer_ops; + + return 0; +} + static void fxls8962af_regulator_disable(void *data_ptr) { struct fxls8962af_data *data = data_ptr; @@ -693,6 +899,8 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) ret = fxls8962af_irq_setup(indio_dev, irq); if (ret < 0) return ret; + + fxls8962af_fifo_setup(indio_dev); } ret = pm_runtime_set_active(dev); From patchwork Thu Apr 29 12:28:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Nyekjaer X-Patchwork-Id: 12231207 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A4E04C43618 for ; Thu, 29 Apr 2021 12:28:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 735E5613F1 for ; Thu, 29 Apr 2021 12:28:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236133AbhD2M3K (ORCPT ); Thu, 29 Apr 2021 08:29:10 -0400 Received: from first.geanix.com ([116.203.34.67]:50676 "EHLO first.geanix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234147AbhD2M3J (ORCPT ); Thu, 29 Apr 2021 08:29:09 -0400 Received: from zen.. (unknown [185.17.218.86]) by first.geanix.com (Postfix) with ESMTPSA id 44643466699; Thu, 29 Apr 2021 12:28:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=geanix.com; s=first; t=1619699301; bh=f/d1enRQkRJtaWSp6G4i9eygpUWyG+QO1k1J0/b1mUU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=UZFkm3VZZSqlK/ZlgbwjrRGuYFYypskBV/S3n7vcWp2HEZ9B2ZUH0+MM3W+JFAb7U L5+VoEMzz8aJakD6bZUaMG9spv1QudgXYLaJXR1DAsI29Pbw0QLXqvsILRpiicvMXu uGlawLcn5Y4pgstDkJEAjraWbC3TadbCROwmsZh3Qlrwpla8yCtxZBWvdrFdGPY5pJ xhNksduUP27unN4gYbUvq9xImXlNAd60gFkhEbNDmlMU7Kn+ylauC9p8OnAe5Hc17O Llixt4Yjgvey0qBkb2oMbS30h8IkA1NgQ01d2E4nqn2rORwG4PK0++egC/NveHpYCl i6c3Tq/Eag9wg== From: Sean Nyekjaer To: jic23@kernel.org, linux-iio@vger.kernel.org, andy.shevchenko@gmail.com, lars@metafoo.de, Nuno.Sa@analog.com, robh+dt@kernel.org, devicetree@vger.kernel.org Cc: Sean Nyekjaer Subject: [PATCH v4 6/6] iio: accel: fxls8962af: fix errata bug E3 - I2C burst reads Date: Thu, 29 Apr 2021 14:28:06 +0200 Message-Id: <20210429122806.3814330-6-sean@geanix.com> X-Mailer: git-send-email 2.31.0 In-Reply-To: <20210429122806.3814330-1-sean@geanix.com> References: <20210429122806.3814330-1-sean@geanix.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org When flushing the hw fifo there is a bug in the I2C that prevents burst reads of more than one sample pair. Signed-off-by: Sean Nyekjaer --- Changes from RFC: - using i2c_verify_client() to detect if hw is connected on I2C bus drivers/iio/accel/fxls8962af-core.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 2e863ef71a7d..e45c9e88bf6e 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -631,11 +632,28 @@ static int fxls8962af_fifo_transfer(struct fxls8962af_data *data, { struct device *dev = regmap_get_device(data->regmap); int sample_length = 3 * sizeof(*buffer); - int ret; + int ret, i; int total_length = samples * sample_length; - ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, buffer, - total_length); + if (i2c_verify_client(dev)) { + /* + * Due to errata bug: + * E3: FIFO burst read operation error using I2C interface + * We have to avoid burst reads on I2C.. + */ + for (i = 0; i < samples; i++) { + ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, + &buffer[i], + sample_length); + if (ret < 0) + goto out; + } + } else { + ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, buffer, + total_length); + } + + out: if (ret < 0) dev_err(dev, "Error transferring data from fifo: %d\n", ret);