diff options
Diffstat (limited to 'target/linux/generic/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch')
-rw-r--r-- | target/linux/generic/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch | 893 |
1 files changed, 0 insertions, 893 deletions
diff --git a/target/linux/generic/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch b/target/linux/generic/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch deleted file mode 100644 index b9cd276327..0000000000 --- a/target/linux/generic/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch +++ /dev/null @@ -1,893 +0,0 @@ -From 84e5ddd5c46ea3bf0cad670da32028994cad5936 Mon Sep 17 00:00:00 2001 -From: Robert Jones <rjones@gateworks.com> -Date: Mon, 14 Oct 2019 11:49:21 -0700 -Subject: [PATCH] iio: imu: Add support for the FXOS8700 IMU -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -FXOS8700CQ is a small, low-power, 3-axis linear accelerometer and 3-axis -magnetometer combined into a single package. The device features a -selectable I2C or point-to-point SPI serial interface with 14-bit -accelerometer and 16-bit magnetometer ADC resolution along with -smart-embedded functions. - -FXOS8700CQ has dynamically selectable accelerationfull-scale ranges of -±2 g/±4 g/±8 g and a fixed magnetic measurement range of ±1200 μT. -Output data rates (ODR) from 1.563 Hz to 800 Hz are selectable by the user -for each sensor. Interleaved magnetic and acceleration data is available -at ODR rates of up to 400 Hz. FXOS8700CQ is available in a plastic QFN -package and it is guaranteed to operate over the extended temperature -range of –40 °C to +85 °C. - -TODO: Trigger and IRQ configuration support - -Datasheet: - http://cache.freescale.com/files/sensors/doc/data_sheet/FXOS8700CQ.pdf - -Signed-off-by: Robert Jones <rjones@gateworks.com> -Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> ---- - drivers/iio/imu/Kconfig | 27 ++ - drivers/iio/imu/Makefile | 5 + - drivers/iio/imu/fxos8700.h | 10 + - drivers/iio/imu/fxos8700_core.c | 649 ++++++++++++++++++++++++++++++++++++++++ - drivers/iio/imu/fxos8700_i2c.c | 71 +++++ - drivers/iio/imu/fxos8700_spi.c | 59 ++++ - 6 files changed, 821 insertions(+) - create mode 100644 drivers/iio/imu/fxos8700.h - create mode 100644 drivers/iio/imu/fxos8700_core.c - create mode 100644 drivers/iio/imu/fxos8700_i2c.c - create mode 100644 drivers/iio/imu/fxos8700_spi.c - ---- a/drivers/iio/imu/Kconfig -+++ b/drivers/iio/imu/Kconfig -@@ -40,6 +40,33 @@ config ADIS16480 - - source "drivers/iio/imu/bmi160/Kconfig" - -+config FXOS8700 -+ tristate -+ -+config FXOS8700_I2C -+ tristate "NXP FXOS8700 I2C driver" -+ depends on I2C -+ select FXOS8700 -+ select REGMAP_I2C -+ help -+ Say yes here to build support for the NXP FXOS8700 m+g combo -+ sensor on I2C. -+ -+ This driver can also be built as a module. If so, the module will be -+ called fxos8700_i2c. -+ -+config FXOS8700_SPI -+ tristate "NXP FXOS8700 SPI driver" -+ depends on SPI -+ select FXOS8700 -+ select REGMAP_SPI -+ help -+ Say yes here to build support for the NXP FXOS8700 m+g combo -+ sensor on SPI. -+ -+ This driver can also be built as a module. If so, the module will be -+ called fxos8700_spi. -+ - config KMX61 - tristate "Kionix KMX61 6-axis accelerometer and magnetometer" - depends on I2C ---- a/drivers/iio/imu/Makefile -+++ b/drivers/iio/imu/Makefile -@@ -14,6 +14,11 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) + - obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o - - obj-y += bmi160/ -+ -+obj-$(CONFIG_FXOS8700) += fxos8700_core.o -+obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o -+obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o -+ - obj-y += inv_mpu6050/ - - obj-$(CONFIG_KMX61) += kmx61.o ---- /dev/null -+++ b/drivers/iio/imu/fxos8700.h -@@ -0,0 +1,10 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef FXOS8700_H_ -+#define FXOS8700_H_ -+ -+extern const struct regmap_config fxos8700_regmap_config; -+ -+int fxos8700_core_probe(struct device *dev, struct regmap *regmap, -+ const char *name, bool use_spi); -+ -+#endif /* FXOS8700_H_ */ ---- /dev/null -+++ b/drivers/iio/imu/fxos8700_core.c -@@ -0,0 +1,649 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * FXOS8700 - NXP IMU (accelerometer plus magnetometer) -+ * -+ * IIO core driver for FXOS8700, with support for I2C/SPI busses -+ * -+ * TODO: Buffer, trigger, and IRQ support -+ */ -+#include <linux/module.h> -+#include <linux/regmap.h> -+#include <linux/acpi.h> -+#include <linux/bitops.h> -+ -+#include <linux/iio/iio.h> -+#include <linux/iio/sysfs.h> -+ -+#include "fxos8700.h" -+ -+/* Register Definitions */ -+#define FXOS8700_STATUS 0x00 -+#define FXOS8700_OUT_X_MSB 0x01 -+#define FXOS8700_OUT_X_LSB 0x02 -+#define FXOS8700_OUT_Y_MSB 0x03 -+#define FXOS8700_OUT_Y_LSB 0x04 -+#define FXOS8700_OUT_Z_MSB 0x05 -+#define FXOS8700_OUT_Z_LSB 0x06 -+#define FXOS8700_F_SETUP 0x09 -+#define FXOS8700_TRIG_CFG 0x0a -+#define FXOS8700_SYSMOD 0x0b -+#define FXOS8700_INT_SOURCE 0x0c -+#define FXOS8700_WHO_AM_I 0x0d -+#define FXOS8700_XYZ_DATA_CFG 0x0e -+#define FXOS8700_HP_FILTER_CUTOFF 0x0f -+#define FXOS8700_PL_STATUS 0x10 -+#define FXOS8700_PL_CFG 0x11 -+#define FXOS8700_PL_COUNT 0x12 -+#define FXOS8700_PL_BF_ZCOMP 0x13 -+#define FXOS8700_PL_THS_REG 0x14 -+#define FXOS8700_A_FFMT_CFG 0x15 -+#define FXOS8700_A_FFMT_SRC 0x16 -+#define FXOS8700_A_FFMT_THS 0x17 -+#define FXOS8700_A_FFMT_COUNT 0x18 -+#define FXOS8700_TRANSIENT_CFG 0x1d -+#define FXOS8700_TRANSIENT_SRC 0x1e -+#define FXOS8700_TRANSIENT_THS 0x1f -+#define FXOS8700_TRANSIENT_COUNT 0x20 -+#define FXOS8700_PULSE_CFG 0x21 -+#define FXOS8700_PULSE_SRC 0x22 -+#define FXOS8700_PULSE_THSX 0x23 -+#define FXOS8700_PULSE_THSY 0x24 -+#define FXOS8700_PULSE_THSZ 0x25 -+#define FXOS8700_PULSE_TMLT 0x26 -+#define FXOS8700_PULSE_LTCY 0x27 -+#define FXOS8700_PULSE_WIND 0x28 -+#define FXOS8700_ASLP_COUNT 0x29 -+#define FXOS8700_CTRL_REG1 0x2a -+#define FXOS8700_CTRL_REG2 0x2b -+#define FXOS8700_CTRL_REG3 0x2c -+#define FXOS8700_CTRL_REG4 0x2d -+#define FXOS8700_CTRL_REG5 0x2e -+#define FXOS8700_OFF_X 0x2f -+#define FXOS8700_OFF_Y 0x30 -+#define FXOS8700_OFF_Z 0x31 -+#define FXOS8700_M_DR_STATUS 0x32 -+#define FXOS8700_M_OUT_X_MSB 0x33 -+#define FXOS8700_M_OUT_X_LSB 0x34 -+#define FXOS8700_M_OUT_Y_MSB 0x35 -+#define FXOS8700_M_OUT_Y_LSB 0x36 -+#define FXOS8700_M_OUT_Z_MSB 0x37 -+#define FXOS8700_M_OUT_Z_LSB 0x38 -+#define FXOS8700_CMP_X_MSB 0x39 -+#define FXOS8700_CMP_X_LSB 0x3a -+#define FXOS8700_CMP_Y_MSB 0x3b -+#define FXOS8700_CMP_Y_LSB 0x3c -+#define FXOS8700_CMP_Z_MSB 0x3d -+#define FXOS8700_CMP_Z_LSB 0x3e -+#define FXOS8700_M_OFF_X_MSB 0x3f -+#define FXOS8700_M_OFF_X_LSB 0x40 -+#define FXOS8700_M_OFF_Y_MSB 0x41 -+#define FXOS8700_M_OFF_Y_LSB 0x42 -+#define FXOS8700_M_OFF_Z_MSB 0x43 -+#define FXOS8700_M_OFF_Z_LSB 0x44 -+#define FXOS8700_MAX_X_MSB 0x45 -+#define FXOS8700_MAX_X_LSB 0x46 -+#define FXOS8700_MAX_Y_MSB 0x47 -+#define FXOS8700_MAX_Y_LSB 0x48 -+#define FXOS8700_MAX_Z_MSB 0x49 -+#define FXOS8700_MAX_Z_LSB 0x4a -+#define FXOS8700_MIN_X_MSB 0x4b -+#define FXOS8700_MIN_X_LSB 0x4c -+#define FXOS8700_MIN_Y_MSB 0x4d -+#define FXOS8700_MIN_Y_LSB 0x4e -+#define FXOS8700_MIN_Z_MSB 0x4f -+#define FXOS8700_MIN_Z_LSB 0x50 -+#define FXOS8700_TEMP 0x51 -+#define FXOS8700_M_THS_CFG 0x52 -+#define FXOS8700_M_THS_SRC 0x53 -+#define FXOS8700_M_THS_X_MSB 0x54 -+#define FXOS8700_M_THS_X_LSB 0x55 -+#define FXOS8700_M_THS_Y_MSB 0x56 -+#define FXOS8700_M_THS_Y_LSB 0x57 -+#define FXOS8700_M_THS_Z_MSB 0x58 -+#define FXOS8700_M_THS_Z_LSB 0x59 -+#define FXOS8700_M_THS_COUNT 0x5a -+#define FXOS8700_M_CTRL_REG1 0x5b -+#define FXOS8700_M_CTRL_REG2 0x5c -+#define FXOS8700_M_CTRL_REG3 0x5d -+#define FXOS8700_M_INT_SRC 0x5e -+#define FXOS8700_A_VECM_CFG 0x5f -+#define FXOS8700_A_VECM_THS_MSB 0x60 -+#define FXOS8700_A_VECM_THS_LSB 0x61 -+#define FXOS8700_A_VECM_CNT 0x62 -+#define FXOS8700_A_VECM_INITX_MSB 0x63 -+#define FXOS8700_A_VECM_INITX_LSB 0x64 -+#define FXOS8700_A_VECM_INITY_MSB 0x65 -+#define FXOS8700_A_VECM_INITY_LSB 0x66 -+#define FXOS8700_A_VECM_INITZ_MSB 0x67 -+#define FXOS8700_A_VECM_INITZ_LSB 0x68 -+#define FXOS8700_M_VECM_CFG 0x69 -+#define FXOS8700_M_VECM_THS_MSB 0x6a -+#define FXOS8700_M_VECM_THS_LSB 0x6b -+#define FXOS8700_M_VECM_CNT 0x6c -+#define FXOS8700_M_VECM_INITX_MSB 0x6d -+#define FXOS8700_M_VECM_INITX_LSB 0x6e -+#define FXOS8700_M_VECM_INITY_MSB 0x6f -+#define FXOS8700_M_VECM_INITY_LSB 0x70 -+#define FXOS8700_M_VECM_INITZ_MSB 0x71 -+#define FXOS8700_M_VECM_INITZ_LSB 0x72 -+#define FXOS8700_A_FFMT_THS_X_MSB 0x73 -+#define FXOS8700_A_FFMT_THS_X_LSB 0x74 -+#define FXOS8700_A_FFMT_THS_Y_MSB 0x75 -+#define FXOS8700_A_FFMT_THS_Y_LSB 0x76 -+#define FXOS8700_A_FFMT_THS_Z_MSB 0x77 -+#define FXOS8700_A_FFMT_THS_Z_LSB 0x78 -+#define FXOS8700_A_TRAN_INIT_MSB 0x79 -+#define FXOS8700_A_TRAN_INIT_LSB_X 0x7a -+#define FXOS8700_A_TRAN_INIT_LSB_Y 0x7b -+#define FXOS8700_A_TRAN_INIT_LSB_Z 0x7d -+#define FXOS8700_TM_NVM_LOCK 0x7e -+#define FXOS8700_NVM_DATA0_35 0x80 -+#define FXOS8700_NVM_DATA_BNK3 0xa4 -+#define FXOS8700_NVM_DATA_BNK2 0xa5 -+#define FXOS8700_NVM_DATA_BNK1 0xa6 -+#define FXOS8700_NVM_DATA_BNK0 0xa7 -+ -+/* Bit definitions for FXOS8700_CTRL_REG1 */ -+#define FXOS8700_CTRL_ODR_MSK 0x38 -+#define FXOS8700_CTRL_ODR_MAX 0x00 -+#define FXOS8700_CTRL_ODR_MIN GENMASK(4, 3) -+ -+/* Bit definitions for FXOS8700_M_CTRL_REG1 */ -+#define FXOS8700_HMS_MASK GENMASK(1, 0) -+#define FXOS8700_OS_MASK GENMASK(4, 2) -+ -+/* Bit definitions for FXOS8700_M_CTRL_REG2 */ -+#define FXOS8700_MAXMIN_RST BIT(2) -+#define FXOS8700_MAXMIN_DIS_THS BIT(3) -+#define FXOS8700_MAXMIN_DIS BIT(4) -+ -+#define FXOS8700_ACTIVE 0x01 -+#define FXOS8700_ACTIVE_MIN_USLEEP 4000 /* from table 6 in datasheet */ -+ -+#define FXOS8700_DEVICE_ID 0xC7 -+#define FXOS8700_PRE_DEVICE_ID 0xC4 -+#define FXOS8700_DATA_BUF_SIZE 3 -+ -+struct fxos8700_data { -+ struct regmap *regmap; -+ struct iio_trigger *trig; -+ __be16 buf[FXOS8700_DATA_BUF_SIZE] ____cacheline_aligned; -+}; -+ -+/* Regmap info */ -+static const struct regmap_range read_range[] = { -+ { -+ .range_min = FXOS8700_STATUS, -+ .range_max = FXOS8700_A_FFMT_COUNT, -+ }, { -+ .range_min = FXOS8700_TRANSIENT_CFG, -+ .range_max = FXOS8700_A_FFMT_THS_Z_LSB, -+ }, -+}; -+ -+static const struct regmap_range write_range[] = { -+ { -+ .range_min = FXOS8700_F_SETUP, -+ .range_max = FXOS8700_TRIG_CFG, -+ }, { -+ .range_min = FXOS8700_XYZ_DATA_CFG, -+ .range_max = FXOS8700_HP_FILTER_CUTOFF, -+ }, { -+ .range_min = FXOS8700_PL_CFG, -+ .range_max = FXOS8700_A_FFMT_CFG, -+ }, { -+ .range_min = FXOS8700_A_FFMT_THS, -+ .range_max = FXOS8700_TRANSIENT_CFG, -+ }, { -+ .range_min = FXOS8700_TRANSIENT_THS, -+ .range_max = FXOS8700_PULSE_CFG, -+ }, { -+ .range_min = FXOS8700_PULSE_THSX, -+ .range_max = FXOS8700_OFF_Z, -+ }, { -+ .range_min = FXOS8700_M_OFF_X_MSB, -+ .range_max = FXOS8700_M_OFF_Z_LSB, -+ }, { -+ .range_min = FXOS8700_M_THS_CFG, -+ .range_max = FXOS8700_M_THS_CFG, -+ }, { -+ .range_min = FXOS8700_M_THS_X_MSB, -+ .range_max = FXOS8700_M_CTRL_REG3, -+ }, { -+ .range_min = FXOS8700_A_VECM_CFG, -+ .range_max = FXOS8700_A_FFMT_THS_Z_LSB, -+ }, -+}; -+ -+static const struct regmap_access_table driver_read_table = { -+ .yes_ranges = read_range, -+ .n_yes_ranges = ARRAY_SIZE(read_range), -+}; -+ -+static const struct regmap_access_table driver_write_table = { -+ .yes_ranges = write_range, -+ .n_yes_ranges = ARRAY_SIZE(write_range), -+}; -+ -+const struct regmap_config fxos8700_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .max_register = FXOS8700_NVM_DATA_BNK0, -+ .rd_table = &driver_read_table, -+ .wr_table = &driver_write_table, -+}; -+EXPORT_SYMBOL(fxos8700_regmap_config); -+ -+#define FXOS8700_CHANNEL(_type, _axis) { \ -+ .type = _type, \ -+ .modified = 1, \ -+ .channel2 = IIO_MOD_##_axis, \ -+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ -+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ -+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ -+} -+ -+enum fxos8700_accel_scale_bits { -+ MODE_2G = 0, -+ MODE_4G, -+ MODE_8G, -+}; -+ -+/* scan indexes follow DATA register order */ -+enum fxos8700_scan_axis { -+ FXOS8700_SCAN_ACCEL_X = 0, -+ FXOS8700_SCAN_ACCEL_Y, -+ FXOS8700_SCAN_ACCEL_Z, -+ FXOS8700_SCAN_MAGN_X, -+ FXOS8700_SCAN_MAGN_Y, -+ FXOS8700_SCAN_MAGN_Z, -+ FXOS8700_SCAN_RHALL, -+ FXOS8700_SCAN_TIMESTAMP, -+}; -+ -+enum fxos8700_sensor { -+ FXOS8700_ACCEL = 0, -+ FXOS8700_MAGN, -+ FXOS8700_NUM_SENSORS /* must be last */ -+}; -+ -+enum fxos8700_int_pin { -+ FXOS8700_PIN_INT1, -+ FXOS8700_PIN_INT2 -+}; -+ -+struct fxos8700_scale { -+ u8 bits; -+ int uscale; -+}; -+ -+struct fxos8700_odr { -+ u8 bits; -+ int odr; -+ int uodr; -+}; -+ -+static const struct fxos8700_scale fxos8700_accel_scale[] = { -+ { MODE_2G, 244}, -+ { MODE_4G, 488}, -+ { MODE_8G, 976}, -+}; -+ -+/* -+ * Accellerometer and magnetometer have the same ODR options, set in the -+ * CTRL_REG1 register. ODR is halved when using both sensors at once in -+ * hybrid mode. -+ */ -+static const struct fxos8700_odr fxos8700_odr[] = { -+ {0x00, 800, 0}, -+ {0x01, 400, 0}, -+ {0x02, 200, 0}, -+ {0x03, 100, 0}, -+ {0x04, 50, 0}, -+ {0x05, 12, 500000}, -+ {0x06, 6, 250000}, -+ {0x07, 1, 562500}, -+}; -+ -+static const struct iio_chan_spec fxos8700_channels[] = { -+ FXOS8700_CHANNEL(IIO_ACCEL, X), -+ FXOS8700_CHANNEL(IIO_ACCEL, Y), -+ FXOS8700_CHANNEL(IIO_ACCEL, Z), -+ FXOS8700_CHANNEL(IIO_MAGN, X), -+ FXOS8700_CHANNEL(IIO_MAGN, Y), -+ FXOS8700_CHANNEL(IIO_MAGN, Z), -+ IIO_CHAN_SOFT_TIMESTAMP(FXOS8700_SCAN_TIMESTAMP), -+}; -+ -+static enum fxos8700_sensor fxos8700_to_sensor(enum iio_chan_type iio_type) -+{ -+ switch (iio_type) { -+ case IIO_ACCEL: -+ return FXOS8700_ACCEL; -+ case IIO_ANGL_VEL: -+ return FXOS8700_MAGN; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int fxos8700_set_active_mode(struct fxos8700_data *data, -+ enum fxos8700_sensor t, bool mode) -+{ -+ int ret; -+ -+ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, mode); -+ if (ret) -+ return ret; -+ -+ usleep_range(FXOS8700_ACTIVE_MIN_USLEEP, -+ FXOS8700_ACTIVE_MIN_USLEEP + 1000); -+ -+ return 0; -+} -+ -+static int fxos8700_set_scale(struct fxos8700_data *data, -+ enum fxos8700_sensor t, int uscale) -+{ -+ int i; -+ static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale); -+ struct device *dev = regmap_get_device(data->regmap); -+ -+ if (t == FXOS8700_MAGN) { -+ dev_err(dev, "Magnetometer scale is locked at 1200uT\n"); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < scale_num; i++) -+ if (fxos8700_accel_scale[i].uscale == uscale) -+ break; -+ -+ if (i == scale_num) -+ return -EINVAL; -+ -+ return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, -+ fxos8700_accel_scale[i].bits); -+} -+ -+static int fxos8700_get_scale(struct fxos8700_data *data, -+ enum fxos8700_sensor t, int *uscale) -+{ -+ int i, ret, val; -+ static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale); -+ -+ if (t == FXOS8700_MAGN) { -+ *uscale = 1200; /* Magnetometer is locked at 1200uT */ -+ return 0; -+ } -+ -+ ret = regmap_read(data->regmap, FXOS8700_XYZ_DATA_CFG, &val); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < scale_num; i++) { -+ if (fxos8700_accel_scale[i].bits == (val & 0x3)) { -+ *uscale = fxos8700_accel_scale[i].uscale; -+ return 0; -+ } -+ } -+ -+ return -EINVAL; -+} -+ -+static int fxos8700_get_data(struct fxos8700_data *data, int chan_type, -+ int axis, int *val) -+{ -+ u8 base, reg; -+ int ret; -+ enum fxos8700_sensor type = fxos8700_to_sensor(chan_type); -+ -+ base = type ? FXOS8700_OUT_X_MSB : FXOS8700_M_OUT_X_MSB; -+ -+ /* Block read 6 bytes of device output registers to avoid data loss */ -+ ret = regmap_bulk_read(data->regmap, base, data->buf, -+ FXOS8700_DATA_BUF_SIZE); -+ if (ret) -+ return ret; -+ -+ /* Convert axis to buffer index */ -+ reg = axis - IIO_MOD_X; -+ -+ /* Convert to native endianness */ -+ *val = sign_extend32(be16_to_cpu(data->buf[reg]), 15); -+ -+ return 0; -+} -+ -+static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t, -+ int odr, int uodr) -+{ -+ int i, ret, val; -+ bool active_mode; -+ static const int odr_num = ARRAY_SIZE(fxos8700_odr); -+ -+ ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val); -+ if (ret) -+ return ret; -+ -+ active_mode = val & FXOS8700_ACTIVE; -+ -+ if (active_mode) { -+ /* -+ * The device must be in standby mode to change any of the -+ * other fields within CTRL_REG1 -+ */ -+ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, -+ val & ~FXOS8700_ACTIVE); -+ if (ret) -+ return ret; -+ } -+ -+ for (i = 0; i < odr_num; i++) -+ if (fxos8700_odr[i].odr == odr && fxos8700_odr[i].uodr == uodr) -+ break; -+ -+ if (i >= odr_num) -+ return -EINVAL; -+ -+ return regmap_update_bits(data->regmap, -+ FXOS8700_CTRL_REG1, -+ FXOS8700_CTRL_ODR_MSK + FXOS8700_ACTIVE, -+ fxos8700_odr[i].bits << 3 | active_mode); -+} -+ -+static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t, -+ int *odr, int *uodr) -+{ -+ int i, val, ret; -+ static const int odr_num = ARRAY_SIZE(fxos8700_odr); -+ -+ ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val); -+ if (ret) -+ return ret; -+ -+ val &= FXOS8700_CTRL_ODR_MSK; -+ -+ for (i = 0; i < odr_num; i++) -+ if (val == fxos8700_odr[i].bits) -+ break; -+ -+ if (i >= odr_num) -+ return -EINVAL; -+ -+ *odr = fxos8700_odr[i].odr; -+ *uodr = fxos8700_odr[i].uodr; -+ -+ return 0; -+} -+ -+static int fxos8700_read_raw(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *chan, -+ int *val, int *val2, long mask) -+{ -+ int ret; -+ struct fxos8700_data *data = iio_priv(indio_dev); -+ -+ switch (mask) { -+ case IIO_CHAN_INFO_RAW: -+ ret = fxos8700_get_data(data, chan->type, chan->channel2, val); -+ if (ret) -+ return ret; -+ return IIO_VAL_INT; -+ case IIO_CHAN_INFO_SCALE: -+ *val = 0; -+ ret = fxos8700_get_scale(data, fxos8700_to_sensor(chan->type), -+ val2); -+ return ret ? ret : IIO_VAL_INT_PLUS_MICRO; -+ case IIO_CHAN_INFO_SAMP_FREQ: -+ ret = fxos8700_get_odr(data, fxos8700_to_sensor(chan->type), -+ val, val2); -+ return ret ? ret : IIO_VAL_INT_PLUS_MICRO; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int fxos8700_write_raw(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *chan, -+ int val, int val2, long mask) -+{ -+ struct fxos8700_data *data = iio_priv(indio_dev); -+ -+ switch (mask) { -+ case IIO_CHAN_INFO_SCALE: -+ return fxos8700_set_scale(data, fxos8700_to_sensor(chan->type), -+ val2); -+ case IIO_CHAN_INFO_SAMP_FREQ: -+ return fxos8700_set_odr(data, fxos8700_to_sensor(chan->type), -+ val, val2); -+ default: -+ return -EINVAL; -+ } -+} -+ -+static IIO_CONST_ATTR(in_accel_sampling_frequency_available, -+ "1.5625 6.25 12.5 50 100 200 400 800"); -+static IIO_CONST_ATTR(in_magn_sampling_frequency_available, -+ "1.5625 6.25 12.5 50 100 200 400 800"); -+static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976"); -+static IIO_CONST_ATTR(in_magn_scale_available, "0.000001200"); -+ -+static struct attribute *fxos8700_attrs[] = { -+ &iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr, -+ &iio_const_attr_in_magn_sampling_frequency_available.dev_attr.attr, -+ &iio_const_attr_in_accel_scale_available.dev_attr.attr, -+ &iio_const_attr_in_magn_scale_available.dev_attr.attr, -+ NULL, -+}; -+ -+static const struct attribute_group fxos8700_attrs_group = { -+ .attrs = fxos8700_attrs, -+}; -+ -+static const struct iio_info fxos8700_info = { -+ .read_raw = fxos8700_read_raw, -+ .write_raw = fxos8700_write_raw, -+ .attrs = &fxos8700_attrs_group, -+}; -+ -+static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi) -+{ -+ int ret; -+ unsigned int val; -+ struct device *dev = regmap_get_device(data->regmap); -+ -+ ret = regmap_read(data->regmap, FXOS8700_WHO_AM_I, &val); -+ if (ret) { -+ dev_err(dev, "Error reading chip id\n"); -+ return ret; -+ } -+ if (val != FXOS8700_DEVICE_ID && val != FXOS8700_PRE_DEVICE_ID) { -+ dev_err(dev, "Wrong chip id, got %x expected %x or %x\n", -+ val, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID); -+ return -ENODEV; -+ } -+ -+ ret = fxos8700_set_active_mode(data, FXOS8700_ACCEL, true); -+ if (ret) -+ return ret; -+ -+ ret = fxos8700_set_active_mode(data, FXOS8700_MAGN, true); -+ if (ret) -+ return ret; -+ -+ /* -+ * The device must be in standby mode to change any of the other fields -+ * within CTRL_REG1 -+ */ -+ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, 0x00); -+ if (ret) -+ return ret; -+ -+ /* Set max oversample ratio (OSR) and both devices active */ -+ ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG1, -+ FXOS8700_HMS_MASK | FXOS8700_OS_MASK); -+ if (ret) -+ return ret; -+ -+ /* Disable and rst min/max measurements & threshold */ -+ ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG2, -+ FXOS8700_MAXMIN_RST | FXOS8700_MAXMIN_DIS_THS | -+ FXOS8700_MAXMIN_DIS); -+ if (ret) -+ return ret; -+ -+ /* Max ODR (800Hz individual or 400Hz hybrid), active mode */ -+ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, -+ FXOS8700_CTRL_ODR_MAX | FXOS8700_ACTIVE); -+ if (ret) -+ return ret; -+ -+ /* Set for max full-scale range (+/-8G) */ -+ return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G); -+} -+ -+static void fxos8700_chip_uninit(void *data) -+{ -+ struct fxos8700_data *fxos8700_data = data; -+ -+ fxos8700_set_active_mode(fxos8700_data, FXOS8700_ACCEL, false); -+ fxos8700_set_active_mode(fxos8700_data, FXOS8700_MAGN, false); -+} -+ -+int fxos8700_core_probe(struct device *dev, struct regmap *regmap, -+ const char *name, bool use_spi) -+{ -+ struct iio_dev *indio_dev; -+ struct fxos8700_data *data; -+ int ret; -+ -+ 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 = fxos8700_chip_init(data, use_spi); -+ if (ret) -+ return ret; -+ -+ ret = devm_add_action_or_reset(dev, fxos8700_chip_uninit, data); -+ if (ret) -+ return ret; -+ -+ indio_dev->dev.parent = dev; -+ indio_dev->channels = fxos8700_channels; -+ indio_dev->num_channels = ARRAY_SIZE(fxos8700_channels); -+ indio_dev->name = name ? name : "fxos8700"; -+ indio_dev->modes = INDIO_DIRECT_MODE; -+ indio_dev->info = &fxos8700_info; -+ -+ return devm_iio_device_register(dev, indio_dev); -+} -+EXPORT_SYMBOL_GPL(fxos8700_core_probe); -+ -+MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>"); -+MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver"); -+MODULE_LICENSE("GPL v2"); ---- /dev/null -+++ b/drivers/iio/imu/fxos8700_i2c.c -@@ -0,0 +1,71 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * FXOS8700 - NXP IMU, I2C bits -+ * -+ * 7-bit I2C slave address determined by SA1 and SA0 logic level -+ * inputs represented in the following table: -+ * SA1 | SA0 | Slave Address -+ * 0 | 0 | 0x1E -+ * 0 | 1 | 0x1D -+ * 1 | 0 | 0x1C -+ * 1 | 1 | 0x1F -+ */ -+#include <linux/acpi.h> -+#include <linux/i2c.h> -+#include <linux/module.h> -+#include <linux/mod_devicetable.h> -+#include <linux/regmap.h> -+ -+#include "fxos8700.h" -+ -+static int fxos8700_i2c_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct regmap *regmap; -+ const char *name = NULL; -+ -+ regmap = devm_regmap_init_i2c(client, &fxos8700_regmap_config); -+ if (IS_ERR(regmap)) { -+ dev_err(&client->dev, "Failed to register i2c regmap %d\n", -+ (int)PTR_ERR(regmap)); -+ return PTR_ERR(regmap); -+ } -+ -+ if (id) -+ name = id->name; -+ -+ return fxos8700_core_probe(&client->dev, regmap, name, false); -+} -+ -+static const struct i2c_device_id fxos8700_i2c_id[] = { -+ {"fxos8700", 0}, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id); -+ -+static const struct acpi_device_id fxos8700_acpi_match[] = { -+ {"FXOS8700", 0}, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match); -+ -+static const struct of_device_id fxos8700_of_match[] = { -+ { .compatible = "nxp,fxos8700" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, fxos8700_of_match); -+ -+static struct i2c_driver fxos8700_i2c_driver = { -+ .driver = { -+ .name = "fxos8700_i2c", -+ .acpi_match_table = ACPI_PTR(fxos8700_acpi_match), -+ .of_match_table = fxos8700_of_match, -+ }, -+ .probe = fxos8700_i2c_probe, -+ .id_table = fxos8700_i2c_id, -+}; -+module_i2c_driver(fxos8700_i2c_driver); -+ -+MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>"); -+MODULE_DESCRIPTION("FXOS8700 I2C driver"); -+MODULE_LICENSE("GPL v2"); ---- /dev/null -+++ b/drivers/iio/imu/fxos8700_spi.c -@@ -0,0 +1,59 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * FXOS8700 - NXP IMU, SPI bits -+ */ -+#include <linux/acpi.h> -+#include <linux/module.h> -+#include <linux/mod_devicetable.h> -+#include <linux/regmap.h> -+#include <linux/spi/spi.h> -+ -+#include "fxos8700.h" -+ -+static int fxos8700_spi_probe(struct spi_device *spi) -+{ -+ struct regmap *regmap; -+ const struct spi_device_id *id = spi_get_device_id(spi); -+ -+ regmap = devm_regmap_init_spi(spi, &fxos8700_regmap_config); -+ if (IS_ERR(regmap)) { -+ dev_err(&spi->dev, "Failed to register spi regmap %d\n", -+ (int)PTR_ERR(regmap)); -+ return PTR_ERR(regmap); -+ } -+ -+ return fxos8700_core_probe(&spi->dev, regmap, id->name, true); -+} -+ -+static const struct spi_device_id fxos8700_spi_id[] = { -+ {"fxos8700", 0}, -+ { } -+}; -+MODULE_DEVICE_TABLE(spi, fxos8700_spi_id); -+ -+static const struct acpi_device_id fxos8700_acpi_match[] = { -+ {"FXOS8700", 0}, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match); -+ -+static const struct of_device_id fxos8700_of_match[] = { -+ { .compatible = "nxp,fxos8700" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, fxos8700_of_match); -+ -+static struct spi_driver fxos8700_spi_driver = { -+ .probe = fxos8700_spi_probe, -+ .id_table = fxos8700_spi_id, -+ .driver = { -+ .acpi_match_table = ACPI_PTR(fxos8700_acpi_match), -+ .of_match_table = fxos8700_of_match, -+ .name = "fxos8700_spi", -+ }, -+}; -+module_spi_driver(fxos8700_spi_driver); -+ -+MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>"); -+MODULE_DESCRIPTION("FXOS8700 SPI driver"); -+MODULE_LICENSE("GPL v2"); |