summaryrefslogtreecommitdiffstats
path: root/drivers/iio/accel
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/accel')
-rw-r--r--drivers/iio/accel/Kconfig40
-rw-r--r--drivers/iio/accel/Makefile4
-rw-r--r--drivers/iio/accel/adis16201.c3
-rw-r--r--drivers/iio/accel/adis16209.c3
-rw-r--r--drivers/iio/accel/adxl372.c4
-rw-r--r--drivers/iio/accel/bma180.c17
-rw-r--r--drivers/iio/accel/bma220_spi.c10
-rw-r--r--drivers/iio/accel/bma400_core.c2
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c13
-rw-r--r--drivers/iio/accel/bmi088-accel-core.c27
-rw-r--r--drivers/iio/accel/fxls8962af-core.c968
-rw-r--r--drivers/iio/accel/fxls8962af-i2c.c57
-rw-r--r--drivers/iio/accel/fxls8962af-spi.c57
-rw-r--r--drivers/iio/accel/fxls8962af.h22
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c13
-rw-r--r--drivers/iio/accel/kxcjk-1013.c253
-rw-r--r--drivers/iio/accel/kxsd9.c2
-rw-r--r--drivers/iio/accel/mma8452.c7
-rw-r--r--drivers/iio/accel/mma9551.c1
-rw-r--r--drivers/iio/accel/mma9551_core.c4
-rw-r--r--drivers/iio/accel/mma9553.c1
-rw-r--r--drivers/iio/accel/mxc4005.c12
-rw-r--r--drivers/iio/accel/sca3300.c472
-rw-r--r--drivers/iio/accel/st_accel.h12
-rw-r--r--drivers/iio/accel/st_accel_core.c230
-rw-r--r--drivers/iio/accel/st_accel_i2c.c17
-rw-r--r--drivers/iio/accel/st_accel_spi.c17
-rw-r--r--drivers/iio/accel/stk8312.c27
-rw-r--r--drivers/iio/accel/stk8ba50.c19
29 files changed, 2082 insertions, 232 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 8b1723635cce..17f6bdcf1db3 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -226,6 +226,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
@@ -449,6 +476,19 @@ config SCA3000
To compile this driver as a module, say M here: the module will be
called sca3000.
+config SCA3300
+ tristate "Murata SCA3300 3-Axis Accelerometer Driver"
+ depends on SPI
+ select CRC8
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Murata SCA3300 3-Axis
+ accelerometer.
+
+ To compile this driver as a module, choose M here: the module will be
+ called sca3300.
+
config STK8312
tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
depends on I2C
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 32cd1342a31a..89280e823bcd 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -27,6 +27,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
@@ -50,6 +53,7 @@ obj-$(CONFIG_MXC4005) += mxc4005.o
obj-$(CONFIG_MXC6255) += mxc6255.o
obj-$(CONFIG_SCA3000) += sca3000.o
+obj-$(CONFIG_SCA3300) += sca3300.o
obj-$(CONFIG_STK8312) += stk8312.o
obj-$(CONFIG_STK8BA50) += stk8ba50.o
diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c
index fe225990de24..7a434e2884d4 100644
--- a/drivers/iio/accel/adis16201.c
+++ b/drivers/iio/accel/adis16201.c
@@ -8,10 +8,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/imu/adis.h>
diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c
index 6c2d4a967de7..ac08e866d612 100644
--- a/drivers/iio/accel/adis16209.c
+++ b/drivers/iio/accel/adis16209.c
@@ -7,11 +7,8 @@
#include <linux/device.h>
#include <linux/kernel.h>
-#include <linux/list.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/imu/adis.h>
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
index 9c9a896a872a..fc9592407717 100644
--- a/drivers/iio/accel/adxl372.c
+++ b/drivers/iio/accel/adxl372.c
@@ -1223,14 +1223,14 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
st->dready_trig = devm_iio_trigger_alloc(dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (st->dready_trig == NULL)
return -ENOMEM;
st->peak_datardy_trig = devm_iio_trigger_alloc(dev,
"%s-dev%d-peak",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!st->peak_datardy_trig)
return -ENOMEM;
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index b8a7469cdae4..4a07e60c0e21 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -162,7 +162,11 @@ struct bma180_data {
int scale;
int bw;
bool pmode;
- u8 buff[16]; /* 3x 16-bit + 8-bit + padding + timestamp */
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ s16 chan[4];
+ s64 timestamp __aligned(8);
+ } scan;
};
enum bma180_chan {
@@ -178,7 +182,7 @@ static int bma023_scale_table[] = { 2452, 4903, 9709, };
static int bma180_bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */
static int bma180_scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 };
-static int bma25x_bw_table[] = { 8, 16, 31, 63, 125, 250 }; /* Hz */
+static int bma25x_bw_table[] = { 8, 16, 31, 63, 125, 250, 500, 1000 }; /* Hz */
static int bma25x_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0,
0, 0, 306458 };
@@ -938,12 +942,12 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)
mutex_unlock(&data->mutex);
goto err;
}
- ((s16 *)data->buff)[i++] = ret;
+ data->scan.chan[i++] = ret;
}
mutex_unlock(&data->mutex);
- iio_push_to_buffers_with_timestamp(indio_dev, data->buff, time_ns);
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -997,8 +1001,7 @@ static int bma180_probe(struct i2c_client *client,
chip = id->driver_data;
data->part_info = &bma180_part_info[chip];
- ret = iio_read_mount_matrix(dev, "mount-matrix",
- &data->orientation);
+ ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
@@ -1045,7 +1048,7 @@ static int bma180_probe(struct i2c_client *client,
if (client->irq > 0) {
data->trig = iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->trig) {
ret = -ENOMEM;
goto err_chip_disable;
diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c
index 36fc9876dbca..0622c7936499 100644
--- a/drivers/iio/accel/bma220_spi.c
+++ b/drivers/iio/accel/bma220_spi.c
@@ -63,7 +63,11 @@ static const int bma220_scale_table[][2] = {
struct bma220_data {
struct spi_device *spi_device;
struct mutex lock;
- s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 8x8 timestamp */
+ struct {
+ s8 chans[3];
+ /* Ensure timestamp is naturally aligned. */
+ s64 timestamp __aligned(8);
+ } scan;
u8 tx_buf[2] ____cacheline_aligned;
};
@@ -94,12 +98,12 @@ static irqreturn_t bma220_trigger_handler(int irq, void *p)
mutex_lock(&data->lock);
data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK;
- ret = spi_write_then_read(spi, data->tx_buf, 1, data->buffer,
+ ret = spi_write_then_read(spi, data->tx_buf, 1, &data->scan.chans,
ARRAY_SIZE(bma220_channels) - 1);
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
mutex_unlock(&data->lock);
diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
index 7eeba80e32cb..21520e022a21 100644
--- a/drivers/iio/accel/bma400_core.c
+++ b/drivers/iio/accel/bma400_core.c
@@ -811,7 +811,7 @@ int bma400_probe(struct device *dev, struct regmap *regmap, const char *name)
if (ret)
return ret;
- ret = iio_read_mount_matrix(dev, "mount-matrix", &data->orientation);
+ ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 04d85ce34e9f..46ab7675186c 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -389,7 +389,7 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
int ret;
if (on) {
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
} else {
pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
@@ -398,9 +398,6 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
if (ret < 0) {
dev_err(dev,
"Failed: %s for %d\n", __func__, on);
- if (on)
- pm_runtime_put_noidle(dev);
-
return ret;
}
@@ -1470,9 +1467,9 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
struct bmc150_accel_trigger *t = &data->triggers[i];
t->indio_trig = devm_iio_trigger_alloc(dev,
- bmc150_accel_triggers[i].name,
+ bmc150_accel_triggers[i].name,
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!t->indio_trig) {
ret = -ENOMEM;
break;
@@ -1688,8 +1685,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
data->regmap = regmap;
if (!bmc150_apply_acpi_orientation(dev, &data->orientation)) {
- ret = iio_read_mount_matrix(dev, "mount-matrix",
- &data->orientation);
+ ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
}
@@ -1836,7 +1832,6 @@ int bmc150_accel_core_remove(struct device *dev)
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
- pm_runtime_put_noidle(dev);
bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c
index 12d00658e46f..a06dae5c971d 100644
--- a/drivers/iio/accel/bmi088-accel-core.c
+++ b/drivers/iio/accel/bmi088-accel-core.c
@@ -285,11 +285,17 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_TEMP:
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
ret = bmi088_accel_get_temp(data, val);
goto out_read_raw_pm_put;
case IIO_ACCEL:
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
goto out_read_raw_pm_put;
@@ -319,7 +325,10 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
*val = BMI088_ACCEL_TEMP_UNIT;
return IIO_VAL_INT;
case IIO_ACCEL:
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
ret = regmap_read(data->regmap,
BMI088_ACCEL_REG_ACC_RANGE, val);
if (ret)
@@ -334,7 +343,10 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
ret = bmi088_accel_get_sample_freq(data, val, val2);
goto out_read_raw_pm_put;
default:
@@ -376,7 +388,10 @@ static int bmi088_accel_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
ret = bmi088_accel_set_sample_freq(data, val);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
@@ -496,7 +511,6 @@ int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap,
if (ret)
return ret;
- indio_dev->dev.parent = dev;
indio_dev->channels = data->chip_info->channels;
indio_dev->num_channels = data->chip_info->num_channels;
indio_dev->name = name ? name : data->chip_info->name;
@@ -531,7 +545,6 @@ int bmi088_accel_core_remove(struct device *dev)
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
- pm_runtime_put_noidle(dev);
bmi088_accel_power_down(data);
return 0;
diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c
new file mode 100644
index 000000000000..078d87865fde
--- /dev/null
+++ b/drivers/iio/accel/fxls8962af-core.c
@@ -0,0 +1,968 @@
+// 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 <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
+
+#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
+#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_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
+
+#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_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_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
+#define FXLS8962AF_SLEEP_IDLE_LSB 0x1c
+#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
+#define FXLS8962AF_INT_PIN_SEL_INT2 GENMASK(7, 0)
+
+#define FXLS8962AF_OFF_X 0x22
+#define FXLS8962AF_OFF_Y 0x23
+#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
+#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_FIFO_LENGTH 32
+#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)},
+ {0, IIO_G_TO_M_S_2(1950000)},
+ {0, IIO_G_TO_M_S_2(3910000)},
+ {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;
+ int num_channels;
+ u8 chip_id;
+};
+
+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 = {
+ .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,
+};
+
+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);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ 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)
+ 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, &reg);
+ if (ret)
+ 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) {
+ 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;
+ 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;
+ }
+}
+
+static int fxls8962af_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ 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,
+ u8 mask, u8 val)
+{
+ int ret;
+ int is_active;
+
+ is_active = fxls8962af_is_active(data);
+ if (is_active) {
+ ret = fxls8962af_standby(data);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_update_bits(data->regmap, reg, mask, val);
+ if (ret)
+ return ret;
+
+ if (is_active) {
+ ret = fxls8962af_active(data);
+ if (ret)
+ 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, &reg);
+ if (ret)
+ 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_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, &reg);
+ if (ret)
+ 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)
+{
+ 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);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return fxls8962af_read_samp_freq(data, val, 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;
+ 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:
+ return -EINVAL;
+ }
+}
+
+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, \
+ .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), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .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,
+ .hwfifo_set_watermark = fxls8962af_set_watermark,
+};
+
+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)
+ 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 == -ETIMEDOUT)
+ dev_err(dev, "reset timeout, int_status = 0x%x\n", reg);
+
+ 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)
+ 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)
+ 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;
+
+ fxls8962af_standby(data);
+
+ /* Disable buffer interrupt */
+ ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN,
+ FXLS8962AF_INT_EN_BUF_EN, 0);
+ if (ret)
+ 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_i2c_raw_read_errata3(struct fxls8962af_data *data,
+ u16 *buffer, int samples,
+ int sample_length)
+{
+ int i, ret;
+
+ for (i = 0; i < samples; i++) {
+ ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB,
+ &buffer[i * 3], sample_length);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+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 total_length = samples * sample_length;
+ int ret;
+
+ 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..
+ */
+ ret = fxls8962af_i2c_raw_read_errata3(data, buffer, samples,
+ sample_length);
+ else
+ ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, buffer,
+ total_length);
+
+ if (ret)
+ 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, &reg);
+ if (ret)
+ return ret;
+
+ if (reg & FXLS8962AF_BUF_STATUS_BUF_OVF) {
+ dev_err(dev, "Buffer overflow");
+ return -EOVERFLOW;
+ }
+
+ 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;
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(data->regmap, FXLS8962AF_INT_STATUS, &reg);
+ if (ret)
+ return IRQ_NONE;
+
+ if (reg & FXLS8962AF_INT_STATUS_SRC_BUF) {
+ ret = fxls8962af_fifo_flush(indio_dev);
+ if (ret)
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+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));
+}
+
+static void fxls8962af_get_irq(struct device_node *of_node,
+ enum fxls8962af_int_pin *pin)
+{
+ int irq;
+
+ irq = of_irq_get_byname(of_node, "INT2");
+ if (irq > 0) {
+ *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->of_node, &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)
+ 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)
+ 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;
+ 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, &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, &reg);
+ if (ret)
+ 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)
+ return ret;
+
+ if (irq) {
+ ret = fxls8962af_irq_setup(indio_dev, irq);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &fxls8962af_buffer_ops);
+ if (ret)
+ return ret;
+ }
+
+ ret = pm_runtime_set_active(dev);
+ if (ret)
+ 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) {
+ 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 <sean@geanix.com>");
+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..cfb004b20455
--- /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 <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#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 <sean@geanix.com>");
+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..57108d3d480b
--- /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 <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#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 <sean@geanix.com>");
+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_ */
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 2f9465cb382f..27f47e1c251e 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -28,8 +28,11 @@ struct accel_3d_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
- /* Reserve for 3 channels + padding + timestamp */
- u32 accel_val[ACCEL_3D_CHANNEL_MAX + 3];
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ u32 accel_val[3];
+ s64 timestamp __aligned(8);
+ } scan;
int scale_pre_decml;
int scale_post_decml;
int scale_precision;
@@ -245,8 +248,8 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
accel_state->timestamp = iio_get_time_ns(indio_dev);
hid_sensor_push_data(indio_dev,
- accel_state->accel_val,
- sizeof(accel_state->accel_val),
+ &accel_state->scan,
+ sizeof(accel_state->scan),
accel_state->timestamp);
accel_state->timestamp = 0;
@@ -271,7 +274,7 @@ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
case HID_USAGE_SENSOR_ACCEL_Y_AXIS:
case HID_USAGE_SENSOR_ACCEL_Z_AXIS:
offset = usage_id - HID_USAGE_SENSOR_ACCEL_X_AXIS;
- accel_state->accel_val[CHANNEL_SCAN_INDEX_X + offset] =
+ accel_state->scan.accel_val[CHANNEL_SCAN_INDEX_X + offset] =
*(u32 *)raw_data;
ret = 0;
break;
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index ff724bc17a45..a51fdd3c9b5b 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -51,13 +51,15 @@
#define KXTF9_REG_TILT_POS_CUR 0x10
#define KXTF9_REG_TILT_POS_PREV 0x11
#define KXTF9_REG_INT_SRC1 0x15
-#define KXCJK1013_REG_INT_SRC1 0x16 /* compatible, but called INT_SRC2 in KXTF9 ds */
+#define KXTF9_REG_INT_SRC2 0x16
+#define KXCJK1013_REG_INT_SRC1 0x16
#define KXCJK1013_REG_INT_SRC2 0x17
#define KXCJK1013_REG_STATUS_REG 0x18
#define KXCJK1013_REG_INT_REL 0x1A
#define KXCJK1013_REG_CTRL1 0x1B
#define KXTF9_REG_CTRL2 0x1C
-#define KXCJK1013_REG_CTRL2 0x1D /* mostly compatible, CTRL_REG3 in KTXF9 ds */
+#define KXTF9_REG_CTRL3 0x1D
+#define KXCJK1013_REG_CTRL2 0x1D
#define KXCJK1013_REG_INT_CTRL1 0x1E
#define KXCJK1013_REG_INT_CTRL2 0x1F
#define KXTF9_REG_INT_CTRL3 0x20
@@ -77,6 +79,45 @@
#define KXTF9_REG_HYST_SET 0x5F
#define KXCJK1013_REG_WAKE_THRES 0x6A
+/* Everything up to 0x11 is equal to KXCJK1013/KXTF9 above */
+#define KX023_REG_INS1 0x12
+#define KX023_REG_INS2 0x13
+#define KX023_REG_INS3 0x14
+#define KX023_REG_STAT 0x15
+#define KX023_REG_INT_REL 0x17
+#define KX023_REG_CNTL1 0x18
+#define KX023_REG_CNTL2 0x19
+#define KX023_REG_CNTL3 0x1A
+#define KX023_REG_ODCNTL 0x1B
+#define KX023_REG_INC1 0x1C
+#define KX023_REG_INC2 0x1D
+#define KX023_REG_INC3 0x1E
+#define KX023_REG_INC4 0x1F
+#define KX023_REG_INC5 0x20
+#define KX023_REG_INC6 0x21
+#define KX023_REG_TILT_TIMER 0x22
+#define KX023_REG_WUFC 0x23
+#define KX023_REG_TDTRC 0x24
+#define KX023_REG_TDTC 0x25
+#define KX023_REG_TTH 0x26
+#define KX023_REG_TTL 0x27
+#define KX023_REG_FTD 0x28
+#define KX023_REG_STD 0x29
+#define KX023_REG_TLT 0x2A
+#define KX023_REG_TWS 0x2B
+#define KX023_REG_ATH 0x30
+#define KX023_REG_TILT_ANGLE_LL 0x32
+#define KX023_REG_TILT_ANGLE_HL 0x33
+#define KX023_REG_HYST_SET 0x34
+#define KX023_REG_LP_CNTL 0x35
+#define KX023_REG_BUF_CNTL1 0x3A
+#define KX023_REG_BUF_CNTL2 0x3B
+#define KX023_REG_BUF_STATUS_1 0x3C
+#define KX023_REG_BUF_STATUS_2 0x3D
+#define KX023_REG_BUF_CLEAR 0x3E
+#define KX023_REG_BUF_READ 0x3F
+#define KX023_REG_SELF_TEST 0x60
+
#define KXCJK1013_REG_CTRL1_BIT_PC1 BIT(7)
#define KXCJK1013_REG_CTRL1_BIT_RES BIT(6)
#define KXCJK1013_REG_CTRL1_BIT_DRDY BIT(5)
@@ -117,6 +158,14 @@
#define KXCJK1013_REG_INT_SRC2_BIT_XP BIT(4)
#define KXCJK1013_REG_INT_SRC2_BIT_XN BIT(5)
+/* KX023 interrupt routing to INT1. INT2 can be configured with INC6 */
+#define KX023_REG_INC4_BFI1 BIT(6)
+#define KX023_REG_INC4_WMI1 BIT(5)
+#define KX023_REG_INC4_DRDY1 BIT(4)
+#define KX023_REG_INC4_TDTI1 BIT(2)
+#define KX023_REG_INC4_WUFI1 BIT(1)
+#define KX023_REG_INC4_TPI1 BIT(0)
+
#define KXCJK1013_DEFAULT_WAKE_THRES 1
enum kx_chipset {
@@ -124,6 +173,7 @@ enum kx_chipset {
KXCJ91008,
KXTJ21009,
KXTF9,
+ KX0231025,
KX_MAX_CHIPS /* this must be last */
};
@@ -133,6 +183,63 @@ enum kx_acpi_type {
ACPI_KIOX010A,
};
+struct kx_chipset_regs {
+ u8 int_src1;
+ u8 int_src2;
+ u8 int_rel;
+ u8 ctrl1;
+ u8 wuf_ctrl;
+ u8 int_ctrl1;
+ u8 data_ctrl;
+ u8 wake_timer;
+ u8 wake_thres;
+};
+
+static const struct kx_chipset_regs kxcjk1013_regs = {
+ .int_src1 = KXCJK1013_REG_INT_SRC1,
+ .int_src2 = KXCJK1013_REG_INT_SRC2,
+ .int_rel = KXCJK1013_REG_INT_REL,
+ .ctrl1 = KXCJK1013_REG_CTRL1,
+ .wuf_ctrl = KXCJK1013_REG_CTRL2,
+ .int_ctrl1 = KXCJK1013_REG_INT_CTRL1,
+ .data_ctrl = KXCJK1013_REG_DATA_CTRL,
+ .wake_timer = KXCJK1013_REG_WAKE_TIMER,
+ .wake_thres = KXCJK1013_REG_WAKE_THRES,
+};
+
+static const struct kx_chipset_regs kxtf9_regs = {
+ /* .int_src1 was moved to INT_SRC2 on KXTF9 */
+ .int_src1 = KXTF9_REG_INT_SRC2,
+ /* .int_src2 is not available */
+ .int_rel = KXCJK1013_REG_INT_REL,
+ .ctrl1 = KXCJK1013_REG_CTRL1,
+ .wuf_ctrl = KXTF9_REG_CTRL3,
+ .int_ctrl1 = KXCJK1013_REG_INT_CTRL1,
+ .data_ctrl = KXCJK1013_REG_DATA_CTRL,
+ .wake_timer = KXCJK1013_REG_WAKE_TIMER,
+ .wake_thres = KXTF9_REG_WAKE_THRESH,
+};
+
+/* The registers have totally different names but the bits are compatible */
+static const struct kx_chipset_regs kx0231025_regs = {
+ .int_src1 = KX023_REG_INS2,
+ .int_src2 = KX023_REG_INS3,
+ .int_rel = KX023_REG_INT_REL,
+ .ctrl1 = KX023_REG_CNTL1,
+ .wuf_ctrl = KX023_REG_CNTL3,
+ .int_ctrl1 = KX023_REG_INC1,
+ .data_ctrl = KX023_REG_ODCNTL,
+ .wake_timer = KX023_REG_WUFC,
+ .wake_thres = KX023_REG_ATH,
+};
+
+enum kxcjk1013_axis {
+ AXIS_X,
+ AXIS_Y,
+ AXIS_Z,
+ AXIS_MAX
+};
+
struct kxcjk1013_data {
struct regulator_bulk_data regulators[2];
struct i2c_client *client;
@@ -140,7 +247,11 @@ struct kxcjk1013_data {
struct iio_trigger *motion_trig;
struct iio_mount_matrix orientation;
struct mutex mutex;
- s16 buffer[8];
+ /* Ensure timestamp naturally aligned */
+ struct {
+ s16 chans[AXIS_MAX];
+ s64 timestamp __aligned(8);
+ } scan;
u8 odr_bits;
u8 range;
int wake_thres;
@@ -152,13 +263,7 @@ struct kxcjk1013_data {
int64_t timestamp;
enum kx_chipset chipset;
enum kx_acpi_type acpi_type;
-};
-
-enum kxcjk1013_axis {
- AXIS_X,
- AXIS_Y,
- AXIS_Z,
- AXIS_MAX,
+ const struct kx_chipset_regs *regs;
};
enum kxcjk1013_mode {
@@ -268,6 +373,22 @@ static const struct {
{0x05, 5100},
{0x06, 2700},
},
+ /* KX023-1025 */
+ {
+ /* First 4 are not in datasheet, taken from KXCTJ2-1009 */
+ {0x08, 1240000},
+ {0x09, 621000},
+ {0x0A, 309000},
+ {0x0B, 151000},
+ {0, 81000},
+ {0x01, 40000},
+ {0x02, 22000},
+ {0x03, 12000},
+ {0x04, 7000},
+ {0x05, 4400},
+ {0x06, 3000},
+ {0x07, 3000},
+ },
};
static const struct {
@@ -309,7 +430,7 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
{
int ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -320,8 +441,7 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
else
ret |= KXCJK1013_REG_CTRL1_BIT_PC1;
- ret = i2c_smbus_write_byte_data(data->client,
- KXCJK1013_REG_CTRL1, ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -335,7 +455,7 @@ static int kxcjk1013_get_mode(struct kxcjk1013_data *data,
{
int ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -353,7 +473,7 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index)
{
int ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -364,9 +484,7 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index)
ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3);
ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4);
- ret = i2c_smbus_write_byte_data(data->client,
- KXCJK1013_REG_CTRL1,
- ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -400,7 +518,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
if (ret < 0)
return ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -409,8 +527,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
/* Set 12 bit mode */
ret |= KXCJK1013_REG_CTRL1_BIT_RES;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL1,
- ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl\n");
return ret;
@@ -421,7 +538,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
if (ret < 0)
return ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_DATA_CTRL);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->data_ctrl);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_data_ctrl\n");
return ret;
@@ -430,7 +547,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
data->odr_bits = ret;
/* Set up INT polarity */
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
return ret;
@@ -441,13 +558,23 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
else
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEA;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
- ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
return ret;
}
+ /* On KX023, route all used interrupts to INT1 for now */
+ if (data->chipset == KX0231025 && data->client->irq > 0) {
+ ret = i2c_smbus_write_byte_data(data->client, KX023_REG_INC4,
+ KX023_REG_INC4_DRDY1 |
+ KX023_REG_INC4_WUFI1);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error writing reg_inc4\n");
+ return ret;
+ }
+ }
+
ret = kxcjk1013_set_mode(data, OPERATION);
if (ret < 0)
return ret;
@@ -478,7 +605,7 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
int ret;
if (on)
- ret = pm_runtime_get_sync(&data->client->dev);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
else {
pm_runtime_mark_last_busy(&data->client->dev);
ret = pm_runtime_put_autosuspend(&data->client->dev);
@@ -486,8 +613,6 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
if (ret < 0) {
dev_err(&data->client->dev,
"Failed: %s for %d\n", __func__, on);
- if (on)
- pm_runtime_put_noidle(&data->client->dev);
return ret;
}
#endif
@@ -497,10 +622,9 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
{
- int waketh_reg, ret;
+ int ret;
- ret = i2c_smbus_write_byte_data(data->client,
- KXCJK1013_REG_WAKE_TIMER,
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_timer,
data->wake_dur);
if (ret < 0) {
dev_err(&data->client->dev,
@@ -508,9 +632,7 @@ static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
return ret;
}
- waketh_reg = data->chipset == KXTF9 ?
- KXTF9_REG_WAKE_THRESH : KXCJK1013_REG_WAKE_THRES;
- ret = i2c_smbus_write_byte_data(data->client, waketh_reg,
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_thres,
data->wake_thres);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_wake_thres\n");
@@ -539,7 +661,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
if (ret < 0)
return ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
return ret;
@@ -550,14 +672,13 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
- ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
return ret;
}
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -568,8 +689,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE;
- ret = i2c_smbus_write_byte_data(data->client,
- KXCJK1013_REG_CTRL1, ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -599,7 +719,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
if (ret < 0)
return ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
return ret;
@@ -610,14 +730,13 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
- ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
return ret;
}
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -628,8 +747,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY;
- ret = i2c_smbus_write_byte_data(data->client,
- KXCJK1013_REG_CTRL1, ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -701,7 +819,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
if (ret < 0)
return ret;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_DATA_CTRL,
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->data_ctrl,
odr_setting->odr_bits);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing data_ctrl\n");
@@ -710,7 +828,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
data->odr_bits = odr_setting->odr_bits;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL2,
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->wuf_ctrl,
odr_setting->wuf_bits);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl2\n");
@@ -1094,12 +1212,12 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
ret = i2c_smbus_read_i2c_block_data_or_emulated(data->client,
KXCJK1013_REG_XOUT_L,
AXIS_MAX * 2,
- (u8 *)data->buffer);
+ (u8 *)data->scan.chans);
mutex_unlock(&data->mutex);
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
data->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -1113,7 +1231,7 @@ static void kxcjk1013_trig_reen(struct iio_trigger *trig)
struct kxcjk1013_data *data = iio_priv(indio_dev);
int ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel);
if (ret < 0)
dev_err(&data->client->dev, "Error reading reg_int_rel\n");
}
@@ -1166,8 +1284,7 @@ static void kxcjk1013_report_motion_event(struct iio_dev *indio_dev)
{
struct kxcjk1013_data *data = iio_priv(indio_dev);
- int ret = i2c_smbus_read_byte_data(data->client,
- KXCJK1013_REG_INT_SRC2);
+ int ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src2);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_src2\n");
return;
@@ -1234,7 +1351,7 @@ static irqreturn_t kxcjk1013_event_handler(int irq, void *private)
struct kxcjk1013_data *data = iio_priv(indio_dev);
int ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_SRC1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_src1\n");
goto ack_intr;
@@ -1257,7 +1374,7 @@ ack_intr:
if (data->dready_trigger_on)
return IRQ_HANDLED;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel);
if (ret < 0)
dev_err(&data->client->dev, "Error reading reg_int_rel\n");
@@ -1338,8 +1455,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
} else {
data->active_high_intr = true; /* default polarity */
- ret = iio_read_mount_matrix(&client->dev, "mount-matrix",
- &data->orientation);
+ ret = iio_read_mount_matrix(&client->dev, &data->orientation);
if (ret)
return ret;
}
@@ -1378,6 +1494,22 @@ static int kxcjk1013_probe(struct i2c_client *client,
} else
return -ENODEV;
+ switch (data->chipset) {
+ case KXCJK1013:
+ case KXCJ91008:
+ case KXTJ21009:
+ data->regs = &kxcjk1013_regs;
+ break;
+ case KXTF9:
+ data->regs = &kxtf9_regs;
+ break;
+ case KX0231025:
+ data->regs = &kx0231025_regs;
+ break;
+ default:
+ return -EINVAL;
+ }
+
ret = kxcjk1013_chip_init(data);
if (ret < 0)
return ret;
@@ -1404,7 +1536,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->dready_trig) {
ret = -ENOMEM;
goto err_poweroff;
@@ -1413,7 +1545,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
data->motion_trig = devm_iio_trigger_alloc(&client->dev,
"%s-any-motion-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->motion_trig) {
ret = -ENOMEM;
goto err_poweroff;
@@ -1485,7 +1617,6 @@ static int kxcjk1013_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
if (data->dready_trig) {
iio_triggered_buffer_cleanup(indio_dev);
@@ -1593,6 +1724,7 @@ static const struct i2c_device_id kxcjk1013_id[] = {
{"kxcj91008", KXCJ91008},
{"kxtj21009", KXTJ21009},
{"kxtf9", KXTF9},
+ {"kx023-1025", KX0231025},
{"SMO8500", KXCJ91008},
{}
};
@@ -1604,6 +1736,7 @@ static const struct of_device_id kxcjk1013_of_match[] = {
{ .compatible = "kionix,kxcj91008", },
{ .compatible = "kionix,kxtj21009", },
{ .compatible = "kionix,kxtf9", },
+ { .compatible = "kionix,kx023-1025", },
{ }
};
MODULE_DEVICE_TABLE(of, kxcjk1013_of_match);
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index 0e18b92e2099..bf7ed9e7d00f 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -420,7 +420,7 @@ int kxsd9_common_probe(struct device *dev,
indio_dev->available_scan_masks = kxsd9_scan_masks;
/* Read the mounting matrix, if present */
- ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation);
+ ret = iio_read_mount_matrix(dev, &st->orientation);
if (ret)
return ret;
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 4d307dfb9169..715b8138fb71 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -221,7 +221,7 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
int ret;
if (on) {
- ret = pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
} else {
pm_runtime_mark_last_busy(&client->dev);
ret = pm_runtime_put_autosuspend(&client->dev);
@@ -230,8 +230,6 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
if (ret < 0) {
dev_err(&client->dev,
"failed to change power state to %d\n", on);
- if (on)
- pm_runtime_put_noidle(&client->dev);
return ret;
}
@@ -1461,7 +1459,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev)
trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!trig)
return -ENOMEM;
@@ -1711,7 +1709,6 @@ static int mma8452_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
iio_triggered_buffer_cleanup(indio_dev);
mma8452_trigger_cleanup(indio_dev);
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index 08a2303cc9df..4c359fb05480 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -515,7 +515,6 @@ static int mma9551_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
mutex_lock(&data->mutex);
mma9551_set_device_state(data->client, false);
diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c
index 666e7a04a7d7..fbf2e2c45678 100644
--- a/drivers/iio/accel/mma9551_core.c
+++ b/drivers/iio/accel/mma9551_core.c
@@ -664,7 +664,7 @@ int mma9551_set_power_state(struct i2c_client *client, bool on)
int ret;
if (on)
- ret = pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
else {
pm_runtime_mark_last_busy(&client->dev);
ret = pm_runtime_put_autosuspend(&client->dev);
@@ -673,8 +673,6 @@ int mma9551_set_power_state(struct i2c_client *client, bool on)
if (ret < 0) {
dev_err(&client->dev,
"failed to change power state to %d\n", on);
- if (on)
- pm_runtime_put_noidle(&client->dev);
return ret;
}
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index c15908faa381..ba3ecb3b57dc 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -1154,7 +1154,6 @@ static int mma9553_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
mutex_lock(&data->mutex);
mma9551_set_device_state(data->client, false);
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index fb3cbaa62bd8..b3afbf064915 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -56,7 +56,11 @@ struct mxc4005_data {
struct mutex mutex;
struct regmap *regmap;
struct iio_trigger *dready_trig;
- __be16 buffer[8];
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ __be16 chans[3];
+ s64 timestamp __aligned(8);
+ } scan;
bool trigger_enabled;
};
@@ -135,7 +139,7 @@ static int mxc4005_read_xyz(struct mxc4005_data *data)
int ret;
ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER,
- data->buffer, sizeof(data->buffer));
+ data->scan.chans, sizeof(data->scan.chans));
if (ret < 0) {
dev_err(data->dev, "failed to read axes\n");
return ret;
@@ -301,7 +305,7 @@ static irqreturn_t mxc4005_trigger_handler(int irq, void *private)
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
@@ -433,7 +437,7 @@ static int mxc4005_probe(struct i2c_client *client,
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->dready_trig)
return -ENOMEM;
diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c
new file mode 100644
index 000000000000..f7ef8ecfd34a
--- /dev/null
+++ b/drivers/iio/accel/sca3300.c
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Murata SCA3300 3-axis industrial accelerometer
+ *
+ * Copyright (c) 2021 Vaisala Oyj. All rights reserved.
+ */
+
+#include <linux/bitops.h>
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include <asm/unaligned.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define SCA3300_ALIAS "sca3300"
+
+#define SCA3300_CRC8_POLYNOMIAL 0x1d
+
+/* Device mode register */
+#define SCA3300_REG_MODE 0xd
+#define SCA3300_MODE_SW_RESET 0x20
+
+/* Last register in map */
+#define SCA3300_REG_SELBANK 0x1f
+
+/* Device status and mask */
+#define SCA3300_REG_STATUS 0x6
+#define SCA3300_STATUS_MASK GENMASK(8, 0)
+
+/* Device ID */
+#define SCA3300_REG_WHOAMI 0x10
+#define SCA3300_WHOAMI_ID 0x51
+
+/* Device return status and mask */
+#define SCA3300_VALUE_RS_ERROR 0x3
+#define SCA3300_MASK_RS_STATUS GENMASK(1, 0)
+
+enum sca3300_scan_indexes {
+ SCA3300_ACC_X = 0,
+ SCA3300_ACC_Y,
+ SCA3300_ACC_Z,
+ SCA3300_TEMP,
+ SCA3300_TIMESTAMP,
+};
+
+#define SCA3300_ACCEL_CHANNEL(index, reg, axis) { \
+ .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) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ }, \
+}
+
+static const struct iio_chan_spec sca3300_channels[] = {
+ SCA3300_ACCEL_CHANNEL(SCA3300_ACC_X, 0x1, X),
+ SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Y, 0x2, Y),
+ SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Z, 0x3, Z),
+ {
+ .type = IIO_TEMP,
+ .address = 0x5,
+ .scan_index = SCA3300_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static const int sca3300_lp_freq[] = {70, 70, 70, 10};
+static const int sca3300_accel_scale[][2] = {{0, 370}, {0, 741}, {0, 185}, {0, 185}};
+
+static const unsigned long sca3300_scan_masks[] = {
+ BIT(SCA3300_ACC_X) | BIT(SCA3300_ACC_Y) | BIT(SCA3300_ACC_Z) |
+ BIT(SCA3300_TEMP),
+ 0
+};
+
+/**
+ * struct sca3300_data - device data
+ * @spi: SPI device structure
+ * @lock: Data buffer lock
+ * @scan: Triggered buffer. Four channel 16-bit data + 64-bit timestamp
+ * @txbuf: Transmit buffer
+ * @rxbuf: Receive buffer
+ */
+struct sca3300_data {
+ struct spi_device *spi;
+ struct mutex lock;
+ struct {
+ s16 channels[4];
+ s64 ts __aligned(sizeof(s64));
+ } scan;
+ u8 txbuf[4] ____cacheline_aligned;
+ u8 rxbuf[4];
+};
+
+DECLARE_CRC8_TABLE(sca3300_crc_table);
+
+static int sca3300_transfer(struct sca3300_data *sca_data, int *val)
+{
+ /* Consecutive requests min. 10 us delay (Datasheet section 5.1.2) */
+ struct spi_delay delay = { .value = 10, .unit = SPI_DELAY_UNIT_USECS };
+ int32_t ret;
+ int rs;
+ u8 crc;
+ struct spi_transfer xfers[2] = {
+ {
+ .tx_buf = sca_data->txbuf,
+ .len = ARRAY_SIZE(sca_data->txbuf),
+ .delay = delay,
+ .cs_change = 1,
+ },
+ {
+ .rx_buf = sca_data->rxbuf,
+ .len = ARRAY_SIZE(sca_data->rxbuf),
+ .delay = delay,
+ }
+ };
+
+ /* inverted crc value as described in device data sheet */
+ crc = ~crc8(sca3300_crc_table, &sca_data->txbuf[0], 3, CRC8_INIT_VALUE);
+ sca_data->txbuf[3] = crc;
+
+ ret = spi_sync_transfer(sca_data->spi, xfers, ARRAY_SIZE(xfers));
+ if (ret) {
+ dev_err(&sca_data->spi->dev,
+ "transfer error, error: %d\n", ret);
+ return -EIO;
+ }
+
+ crc = ~crc8(sca3300_crc_table, &sca_data->rxbuf[0], 3, CRC8_INIT_VALUE);
+ if (sca_data->rxbuf[3] != crc) {
+ dev_err(&sca_data->spi->dev, "CRC checksum mismatch");
+ return -EIO;
+ }
+
+ /* get return status */
+ rs = sca_data->rxbuf[0] & SCA3300_MASK_RS_STATUS;
+ if (rs == SCA3300_VALUE_RS_ERROR)
+ ret = -EINVAL;
+
+ *val = sign_extend32(get_unaligned_be16(&sca_data->rxbuf[1]), 15);
+
+ return ret;
+}
+
+static int sca3300_error_handler(struct sca3300_data *sca_data)
+{
+ int ret;
+ int val;
+
+ mutex_lock(&sca_data->lock);
+ sca_data->txbuf[0] = SCA3300_REG_STATUS << 2;
+ ret = sca3300_transfer(sca_data, &val);
+ mutex_unlock(&sca_data->lock);
+ /*
+ * Return status error is cleared after reading status register once,
+ * expect EINVAL here.
+ */
+ if (ret != -EINVAL) {
+ dev_err(&sca_data->spi->dev,
+ "error reading device status: %d\n", ret);
+ return ret;
+ }
+
+ dev_err(&sca_data->spi->dev, "device status: 0x%lx\n",
+ val & SCA3300_STATUS_MASK);
+
+ return 0;
+}
+
+static int sca3300_read_reg(struct sca3300_data *sca_data, u8 reg, int *val)
+{
+ int ret;
+
+ mutex_lock(&sca_data->lock);
+ sca_data->txbuf[0] = reg << 2;
+ ret = sca3300_transfer(sca_data, val);
+ mutex_unlock(&sca_data->lock);
+ if (ret != -EINVAL)
+ return ret;
+
+ return sca3300_error_handler(sca_data);
+}
+
+static int sca3300_write_reg(struct sca3300_data *sca_data, u8 reg, int val)
+{
+ int reg_val = 0;
+ int ret;
+
+ mutex_lock(&sca_data->lock);
+ /* BIT(7) for write operation */
+ sca_data->txbuf[0] = BIT(7) | (reg << 2);
+ put_unaligned_be16(val, &sca_data->txbuf[1]);
+ ret = sca3300_transfer(sca_data, &reg_val);
+ mutex_unlock(&sca_data->lock);
+ if (ret != -EINVAL)
+ return ret;
+
+ return sca3300_error_handler(sca_data);
+}
+
+static int sca3300_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct sca3300_data *data = iio_priv(indio_dev);
+ int reg_val;
+ int ret;
+ int i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (val)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(sca3300_accel_scale); i++) {
+ if (val2 == sca3300_accel_scale[i][1])
+ return sca3300_write_reg(data, SCA3300_REG_MODE, i);
+ }
+ return -EINVAL;
+
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ ret = sca3300_read_reg(data, SCA3300_REG_MODE, &reg_val);
+ if (ret)
+ return ret;
+ /* freq. change is possible only for mode 3 and 4 */
+ if (reg_val == 2 && val == sca3300_lp_freq[3])
+ return sca3300_write_reg(data, SCA3300_REG_MODE, 3);
+ if (reg_val == 3 && val == sca3300_lp_freq[2])
+ return sca3300_write_reg(data, SCA3300_REG_MODE, 2);
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sca3300_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct sca3300_data *data = iio_priv(indio_dev);
+ int ret;
+ int reg_val;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = sca3300_read_reg(data, chan->address, val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ ret = sca3300_read_reg(data, SCA3300_REG_MODE, &reg_val);
+ if (ret)
+ return ret;
+ *val = 0;
+ *val2 = sca3300_accel_scale[reg_val][1];
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ ret = sca3300_read_reg(data, SCA3300_REG_MODE, &reg_val);
+ if (ret)
+ return ret;
+ *val = sca3300_lp_freq[reg_val];
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static irqreturn_t sca3300_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct sca3300_data *data = iio_priv(indio_dev);
+ int bit, ret, val, i = 0;
+
+ for_each_set_bit(bit, indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+ ret = sca3300_read_reg(data, sca3300_channels[bit].address,
+ &val);
+ if (ret) {
+ dev_err_ratelimited(&data->spi->dev,
+ "failed to read register, error: %d\n", ret);
+ /* handled, but bailing out due to errors */
+ goto out;
+ }
+ data->scan.channels[i++] = val;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+ iio_get_time_ns(indio_dev));
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * sca3300_init - Device init sequence. See datasheet rev 2 section
+ * 4.2 Start-Up Sequence for details.
+ */
+static int sca3300_init(struct sca3300_data *sca_data,
+ struct iio_dev *indio_dev)
+{
+ int value = 0;
+ int ret;
+
+ ret = sca3300_write_reg(sca_data, SCA3300_REG_MODE,
+ SCA3300_MODE_SW_RESET);
+ if (ret)
+ return ret;
+
+ /*
+ * Wait 1ms after SW-reset command.
+ * Wait 15ms for settling of signal paths.
+ */
+ usleep_range(16e3, 50e3);
+
+ ret = sca3300_read_reg(sca_data, SCA3300_REG_WHOAMI, &value);
+ if (ret)
+ return ret;
+
+ if (value != SCA3300_WHOAMI_ID) {
+ dev_err(&sca_data->spi->dev,
+ "device id not expected value, %d != %u\n",
+ value, SCA3300_WHOAMI_ID);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int sca3300_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
+{
+ struct sca3300_data *data = iio_priv(indio_dev);
+ int value;
+ int ret;
+
+ if (reg > SCA3300_REG_SELBANK)
+ return -EINVAL;
+
+ if (!readval)
+ return sca3300_write_reg(data, reg, writeval);
+
+ ret = sca3300_read_reg(data, reg, &value);
+ if (ret)
+ return ret;
+
+ *readval = value;
+
+ return 0;
+}
+
+static int sca3300_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:
+ *vals = (const int *)sca3300_accel_scale;
+ *length = ARRAY_SIZE(sca3300_accel_scale) * 2 - 2;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ *vals = &sca3300_lp_freq[2];
+ *length = 2;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info sca3300_info = {
+ .read_raw = sca3300_read_raw,
+ .write_raw = sca3300_write_raw,
+ .debugfs_reg_access = &sca3300_debugfs_reg_access,
+ .read_avail = sca3300_read_avail,
+};
+
+static int sca3300_probe(struct spi_device *spi)
+{
+ struct sca3300_data *sca_data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*sca_data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ sca_data = iio_priv(indio_dev);
+ mutex_init(&sca_data->lock);
+ sca_data->spi = spi;
+
+ crc8_populate_msb(sca3300_crc_table, SCA3300_CRC8_POLYNOMIAL);
+
+ indio_dev->info = &sca3300_info;
+ indio_dev->name = SCA3300_ALIAS;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = sca3300_channels;
+ indio_dev->num_channels = ARRAY_SIZE(sca3300_channels);
+ indio_dev->available_scan_masks = sca3300_scan_masks;
+
+ ret = sca3300_init(sca_data, indio_dev);
+ if (ret) {
+ dev_err(&spi->dev, "failed to init device, error: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ iio_pollfunc_store_time,
+ sca3300_trigger_handler, NULL);
+ if (ret) {
+ dev_err(&spi->dev,
+ "iio triggered buffer setup failed, error: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_iio_device_register(&spi->dev, indio_dev);
+ if (ret) {
+ dev_err(&spi->dev, "iio device register failed, error: %d\n",
+ ret);
+ }
+
+ return ret;
+}
+
+static const struct of_device_id sca3300_dt_ids[] = {
+ { .compatible = "murata,sca3300"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, sca3300_dt_ids);
+
+static struct spi_driver sca3300_driver = {
+ .driver = {
+ .name = SCA3300_ALIAS,
+ .of_match_table = sca3300_dt_ids,
+ },
+ .probe = sca3300_probe,
+};
+module_spi_driver(sca3300_driver);
+
+MODULE_AUTHOR("Tomas Melin <tomas.melin@vaisala.com>");
+MODULE_DESCRIPTION("Murata SCA3300 SPI Accelerometer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
index 5d356288e001..f5b0b8bbaff7 100644
--- a/drivers/iio/accel/st_accel.h
+++ b/drivers/iio/accel/st_accel.h
@@ -62,18 +62,6 @@ enum st_accel_type {
#define LIS2DE12_ACCEL_DEV_NAME "lis2de12"
#define LIS2HH12_ACCEL_DEV_NAME "lis2hh12"
-/**
-* struct st_sensors_platform_data - default accel platform data
-* @drdy_int_pin: default accel DRDY is available on INT1 pin.
-*/
-static __maybe_unused const struct st_sensors_platform_data default_accel_pdata = {
- .drdy_int_pin = 1,
-};
-
-const struct st_sensor_settings *st_accel_get_settings(const char *name);
-int st_accel_common_probe(struct iio_dev *indio_dev);
-void st_accel_common_remove(struct iio_dev *indio_dev);
-
#ifdef CONFIG_IIO_BUFFER
int st_accel_allocate_ring(struct iio_dev *indio_dev);
void st_accel_deallocate_ring(struct iio_dev *indio_dev);
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index 43c50167d220..28fceac9f2f6 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -41,51 +41,74 @@
#define ST_ACCEL_FS_AVL_200G 200
#define ST_ACCEL_FS_AVL_400G 400
+static const struct iio_mount_matrix *
+st_accel_get_mount_matrix(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct st_sensor_data *adata = iio_priv(indio_dev);
+
+ return &adata->mount_matrix;
+}
+
+static const struct iio_chan_spec_ext_info st_accel_mount_matrix_ext_info[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_accel_get_mount_matrix),
+ { }
+};
+
static const struct iio_chan_spec st_accel_8bit_channels[] = {
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 8, 8,
- ST_ACCEL_DEFAULT_OUT_X_L_ADDR+1),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_X_L_ADDR+1,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 8, 8,
- ST_ACCEL_DEFAULT_OUT_Y_L_ADDR+1),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_Y_L_ADDR+1,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 8, 8,
- ST_ACCEL_DEFAULT_OUT_Z_L_ADDR+1),
+ ST_ACCEL_DEFAULT_OUT_Z_L_ADDR+1,
+ st_accel_mount_matrix_ext_info),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct iio_chan_spec st_accel_12bit_channels[] = {
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 12, 16,
- ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_X_L_ADDR,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 12, 16,
- ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_Y_L_ADDR,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 12, 16,
- ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
+ ST_ACCEL_DEFAULT_OUT_Z_L_ADDR,
+ st_accel_mount_matrix_ext_info),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct iio_chan_spec st_accel_16bit_channels[] = {
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
- ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_X_L_ADDR,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
- ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_Y_L_ADDR,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
- ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
+ ST_ACCEL_DEFAULT_OUT_Z_L_ADDR,
+ st_accel_mount_matrix_ext_info),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
@@ -980,7 +1003,99 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.multi_read_bit = true,
.bootime = 2,
},
+ {
+ .wai = 0x49,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+ .sensors_supported = {
+ [0] = LSM9DS0_IMU_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_accel_16bit_channels,
+ .odr = {
+ .addr = 0x20,
+ .mask = GENMASK(7, 4),
+ .odr_avl = {
+ { 3, 0x01, },
+ { 6, 0x02, },
+ { 12, 0x03, },
+ { 25, 0x04, },
+ { 50, 0x05, },
+ { 100, 0x06, },
+ { 200, 0x07, },
+ { 400, 0x08, },
+ { 800, 0x09, },
+ { 1600, 0x0a, },
+ },
+ },
+ .pw = {
+ .addr = 0x20,
+ .mask = GENMASK(7, 4),
+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+ },
+ .enable_axis = {
+ .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+ .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+ },
+ .fs = {
+ .addr = 0x21,
+ .mask = GENMASK(5, 3),
+ .fs_avl = {
+ [0] = {
+ .num = ST_ACCEL_FS_AVL_2G,
+ .value = 0x00,
+ .gain = IIO_G_TO_M_S_2(61),
+ },
+ [1] = {
+ .num = ST_ACCEL_FS_AVL_4G,
+ .value = 0x01,
+ .gain = IIO_G_TO_M_S_2(122),
+ },
+ [2] = {
+ .num = ST_ACCEL_FS_AVL_6G,
+ .value = 0x02,
+ .gain = IIO_G_TO_M_S_2(183),
+ },
+ [3] = {
+ .num = ST_ACCEL_FS_AVL_8G,
+ .value = 0x03,
+ .gain = IIO_G_TO_M_S_2(244),
+ },
+ [4] = {
+ .num = ST_ACCEL_FS_AVL_16G,
+ .value = 0x04,
+ .gain = IIO_G_TO_M_S_2(732),
+ },
+ },
+ },
+ .bdu = {
+ .addr = 0x20,
+ .mask = BIT(3),
+ },
+ .drdy_irq = {
+ .int1 = {
+ .addr = 0x22,
+ .mask = BIT(2),
+ },
+ .int2 = {
+ .addr = 0x23,
+ .mask = BIT(3),
+ },
+ .stat_drdy = {
+ .addr = ST_SENSORS_DEFAULT_STAT_ADDR,
+ .mask = GENMASK(2, 0),
+ },
+ },
+ .sim = {
+ .addr = 0x21,
+ .value = BIT(0),
+ },
+ .multi_read_bit = true,
+ .bootime = 2,
+ },
+};
+/* Default accel DRDY is available on INT1 pin */
+static const struct st_sensors_platform_data default_accel_pdata = {
+ .drdy_int_pin = 1,
};
static int st_accel_read_raw(struct iio_dev *indio_dev,
@@ -1070,25 +1185,10 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
#endif
#ifdef CONFIG_ACPI
-static const struct iio_mount_matrix *
-get_mount_matrix(const struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
-{
- struct st_sensor_data *adata = iio_priv(indio_dev);
-
- return adata->mount_matrix;
-}
-
-static const struct iio_chan_spec_ext_info mount_matrix_ext_info[] = {
- IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, get_mount_matrix),
- { },
-};
-
/* Read ST-specific _ONT orientation data from ACPI and generate an
* appropriate mount matrix.
*/
-static int apply_acpi_orientation(struct iio_dev *indio_dev,
- struct iio_chan_spec *channels)
+static int apply_acpi_orientation(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -1177,14 +1277,6 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev,
}
/* Convert our integer matrix to a string-based iio_mount_matrix */
- adata->mount_matrix = devm_kmalloc(&indio_dev->dev,
- sizeof(*adata->mount_matrix),
- GFP_KERNEL);
- if (!adata->mount_matrix) {
- ret = -ENOMEM;
- goto out;
- }
-
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
int matrix_val = final_ont[i][j];
@@ -1203,26 +1295,25 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev,
default:
goto out;
}
- adata->mount_matrix->rotation[i * 3 + j] = str_value;
+ adata->mount_matrix.rotation[i * 3 + j] = str_value;
}
}
- /* Expose the mount matrix via ext_info */
- for (i = 0; i < indio_dev->num_channels; i++)
- channels[i].ext_info = mount_matrix_ext_info;
-
ret = 0;
dev_info(&indio_dev->dev, "computed mount matrix from ACPI\n");
out:
kfree(buffer.pointer);
+ if (ret)
+ dev_dbg(&indio_dev->dev,
+ "failed to apply ACPI orientation data: %d\n", ret);
+
return ret;
}
#else /* !CONFIG_ACPI */
-static int apply_acpi_orientation(struct iio_dev *indio_dev,
- struct iio_chan_spec *channels)
+static int apply_acpi_orientation(struct iio_dev *indio_dev)
{
- return 0;
+ return -EINVAL;
}
#endif
@@ -1248,38 +1339,30 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
struct st_sensors_platform_data *pdata = dev_get_platdata(adata->dev);
- struct iio_chan_spec *channels;
- size_t channels_size;
int err;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &accel_info;
- err = st_sensors_power_enable(indio_dev);
- if (err)
- return err;
-
err = st_sensors_verify_id(indio_dev);
if (err < 0)
- goto st_accel_power_off;
+ return err;
adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
+ indio_dev->channels = adata->sensor_settings->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
- channels_size = indio_dev->num_channels * sizeof(struct iio_chan_spec);
- channels = devm_kmemdup(&indio_dev->dev,
- adata->sensor_settings->ch,
- channels_size, GFP_KERNEL);
- if (!channels) {
- err = -ENOMEM;
- goto st_accel_power_off;
+ /*
+ * First try specific ACPI methods to retrieve orientation then try the
+ * generic function.
+ */
+ err = apply_acpi_orientation(indio_dev);
+ if (err) {
+ err = iio_read_mount_matrix(adata->dev, &adata->mount_matrix);
+ if (err)
+ return err;
}
- if (apply_acpi_orientation(indio_dev, channels))
- dev_warn(&indio_dev->dev,
- "failed to apply ACPI orientation data: %d\n", err);
-
- indio_dev->channels = channels;
adata->current_fullscale = &adata->sensor_settings->fs.fs_avl[0];
adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
@@ -1288,11 +1371,11 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
err = st_sensors_init_sensor(indio_dev, pdata);
if (err < 0)
- goto st_accel_power_off;
+ return err;
err = st_accel_allocate_ring(indio_dev);
if (err < 0)
- goto st_accel_power_off;
+ return err;
if (adata->irq > 0) {
err = st_sensors_allocate_trigger(indio_dev,
@@ -1315,9 +1398,6 @@ st_accel_device_register_error:
st_sensors_deallocate_trigger(indio_dev);
st_accel_probe_trigger_error:
st_accel_deallocate_ring(indio_dev);
-st_accel_power_off:
- st_sensors_power_disable(indio_dev);
-
return err;
}
EXPORT_SYMBOL(st_accel_common_probe);
@@ -1326,8 +1406,6 @@ void st_accel_common_remove(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
- st_sensors_power_disable(indio_dev);
-
iio_device_unregister(indio_dev);
if (adata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index 360e16f2cadb..95e305b88d5e 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -174,16 +174,29 @@ static int st_accel_i2c_probe(struct i2c_client *client)
if (ret < 0)
return ret;
+ ret = st_sensors_power_enable(indio_dev);
+ if (ret)
+ return ret;
+
ret = st_accel_common_probe(indio_dev);
if (ret < 0)
- return ret;
+ goto st_accel_power_off;
return 0;
+
+st_accel_power_off:
+ st_sensors_power_disable(indio_dev);
+
+ return ret;
}
static int st_accel_i2c_remove(struct i2c_client *client)
{
- st_accel_common_remove(i2c_get_clientdata(client));
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ st_sensors_power_disable(indio_dev);
+
+ st_accel_common_remove(indio_dev);
return 0;
}
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index 568ff1bae0ee..83d3308ce5cc 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -123,16 +123,29 @@ static int st_accel_spi_probe(struct spi_device *spi)
if (err < 0)
return err;
+ err = st_sensors_power_enable(indio_dev);
+ if (err)
+ return err;
+
err = st_accel_common_probe(indio_dev);
if (err < 0)
- return err;
+ goto st_accel_power_off;
return 0;
+
+st_accel_power_off:
+ st_sensors_power_disable(indio_dev);
+
+ return err;
}
static int st_accel_spi_remove(struct spi_device *spi)
{
- st_accel_common_remove(spi_get_drvdata(spi));
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+ st_sensors_power_disable(indio_dev);
+
+ st_accel_common_remove(indio_dev);
return 0;
}
diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index 157d8faefb9e..43c621d0f11e 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -7,7 +7,6 @@
* IIO driver for STK8312; 7-bit I2C address: 0x3D.
*/
-#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -103,7 +102,11 @@ struct stk8312_data {
u8 mode;
struct iio_trigger *dready_trig;
bool dready_trigger_on;
- s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 64-bit timestamp */
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ s8 chans[3];
+ s64 timestamp __aligned(8);
+ } scan;
};
static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL);
@@ -438,7 +441,7 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
ret = i2c_smbus_read_i2c_block_data(data->client,
STK8312_REG_XOUT,
STK8312_ALL_CHANNEL_SIZE,
- data->buffer);
+ data->scan.chans);
if (ret < STK8312_ALL_CHANNEL_SIZE) {
dev_err(&data->client->dev, "register read failed\n");
mutex_unlock(&data->lock);
@@ -452,12 +455,12 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
mutex_unlock(&data->lock);
goto err;
}
- data->buffer[i++] = ret;
+ data->scan.chans[i++] = ret;
}
}
mutex_unlock(&data->lock);
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -552,7 +555,7 @@ static int stk8312_probe(struct i2c_client *client,
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->dready_trig) {
ret = -ENOMEM;
goto err_power_off;
@@ -635,23 +638,17 @@ static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume);
#endif
static const struct i2c_device_id stk8312_i2c_id[] = {
- {"STK8312", 0},
+ /* Deprecated in favour of lowercase form */
+ { "STK8312", 0 },
+ { "stk8312", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id);
-static const struct acpi_device_id stk8312_acpi_id[] = {
- {"STK8312", 0},
- {}
-};
-
-MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id);
-
static struct i2c_driver stk8312_driver = {
.driver = {
.name = STK8312_DRIVER_NAME,
.pm = STK8312_PM_OPS,
- .acpi_match_table = ACPI_PTR(stk8312_acpi_id),
},
.probe = stk8312_probe,
.remove = stk8312_remove,
diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c
index 7cf9cb7e8666..e137a34b5c9a 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -91,12 +91,11 @@ struct stk8ba50_data {
u8 sample_rate_idx;
struct iio_trigger *dready_trig;
bool dready_trigger_on;
- /*
- * 3 x 16-bit channels (10-bit data, 6-bit padding) +
- * 1 x 16 padding +
- * 4 x 16 64-bit timestamp
- */
- s16 buffer[8];
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ s16 chans[3];
+ s64 timetamp __aligned(8);
+ } scan;
};
#define STK8BA50_ACCEL_CHANNEL(index, reg, axis) { \
@@ -324,7 +323,7 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p)
ret = i2c_smbus_read_i2c_block_data(data->client,
STK8BA50_REG_XOUT,
STK8BA50_ALL_CHANNEL_SIZE,
- (u8 *)data->buffer);
+ (u8 *)data->scan.chans);
if (ret < STK8BA50_ALL_CHANNEL_SIZE) {
dev_err(&data->client->dev, "register read failed\n");
goto err;
@@ -337,10 +336,10 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p)
if (ret < 0)
goto err;
- data->buffer[i++] = ret;
+ data->scan.chans[i++] = ret;
}
}
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
mutex_unlock(&data->lock);
@@ -448,7 +447,7 @@ static int stk8ba50_probe(struct i2c_client *client,
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->dready_trig) {
ret = -ENOMEM;
goto err_power_off;