* Keep in mind the data is buffered but the NVS HAL will display the data and
* scale/offset parameters in the log. See calibration steps below.
*/
-
+/* This module automatically handles on-change sensors by testing for allowed
+ * report rate and whether data has changed. This allows sensors that are
+ * on-change in name only that normally stream data to behave as on-change.
+ */
+/* This module automatically handles one-shot sensors by disabling the sensor
+ * after an event.
+ */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/iio/trigger.h>
#include <linux/nvs.h>
-#define NVS_IIO_DRIVER_VERSION (214)
+#define NVS_IIO_DRIVER_VERSION (215)
enum NVS_ATTR {
NVS_ATTR_ENABLE,
bool shutdown;
bool suspend;
bool flush;
+ bool first_push;
+ bool one_shot;
+ bool on_change;
int enabled;
int batch_flags;
unsigned int batch_period_us;
return 0;
}
+static int nvs_disable(struct nvs_state *st)
+{
+ int ret;
+
+ ret = st->fn_dev->enable(st->client, st->cfg->snsr_id, 0);
+ if (!ret) {
+ st->enabled = 0;
+ st->dbg_data_lock = 0;
+ }
+ return ret;
+}
+
static unsigned int nvs_buf_index(unsigned int size, unsigned int *bytes)
{
unsigned int index;
static int nvs_buf_push(struct iio_dev *indio_dev, unsigned char *data, s64 ts)
{
struct nvs_state *st = iio_priv(indio_dev);
+ bool push = true;
+ bool buf_data = false;
char char_buf[128];
unsigned int n;
unsigned int i;
* In this case, just the timestamp is sent.
*/
if (data_chan_n) {
+ if (st->on_change)
+ /* on-change needs data change for push */
+ push = false;
for (i = 0; i < data_chan_n; i++) {
if (iio_scan_mask_query(indio_dev,
indio_dev->buffer, i)) {
n = indio_dev->channels[i].
scan_type.storagebits / 8;
dst_i = nvs_buf_index(n, &bytes);
- if (data && !(st->dbg_data_lock & (1 << i)))
+ if (!data) {
+ /* buffer calculations only */
+ src_i += n;
+ continue;
+ }
+
+ buf_data = true;
+ if (st->on_change) {
+ /* wasted cycles when st->first_push
+ * but saved cycles in the long run.
+ */
+ ret = memcmp(&st->buf[dst_i],
+ &data[src_i], n);
+ if (ret)
+ /* data changed */
+ push = true;
+ }
+ if (!(st->dbg_data_lock & (1 << i)))
memcpy(&st->buf[dst_i],
&data[src_i], n);
src_i += n;
}
}
}
+
+ if (st->first_push || !buf_data)
+ /* first push || pushing just timestamp */
+ push = true;
if (ts) {
st->ts_diff = ts - st->ts;
- st->ts = ts;
if (st->ts_diff < 0)
dev_err(st->dev, "%s %s ts_diff=%lld\n",
__func__, st->cfg->name, st->ts_diff);
+ else if (st->on_change && (st->ts_diff <
+ (s64)st->batch_period_us * 1000)) {
+ /* data rate faster than requested */
+ if (!st->first_push)
+ push = false;
+ }
} else {
st->flush = false;
if (*st->fn_dev->sts & (NVS_STS_SPEW_MSG | NVS_STS_SPEW_DATA))
dst_i = nvs_buf_index(n, &bytes);
memcpy(&st->buf[dst_i], &ts, n);
}
- if (iio_buffer_enabled(indio_dev)) {
+ if (push && iio_buffer_enabled(indio_dev)) {
ret = iio_push_to_buffers(indio_dev, st->buf);
- i = st->cfg->flags & SENSOR_FLAG_READONLY_MASK;
- if (i == SENSOR_FLAG_ONE_SHOT_MODE && ts && !ret) {
- /* one-shot sensor sent sensor data so disable */
- ret = st->fn_dev->enable(st->client,
- st->cfg->snsr_id, 0);
- if (!ret)
- st->enabled = 0;
- }
- if (*st->fn_dev->sts & NVS_STS_SPEW_BUF) {
- for (i = 0; i < bytes; i++)
- dev_info(st->dev, "%s buf[%u]=%x\n",
- st->cfg->name, i, st->buf[i]);
- dev_info(st->dev, "%s ts=%lld diff=%lld\n",
- st->cfg->name, ts, st->ts_diff);
+ if (!ret) {
+ if (ts) {
+ st->first_push = false;
+ st->ts = ts; /* log ts push */
+ if (st->one_shot)
+ /* disable one-shot after event */
+ nvs_disable(st);
+ }
+ if (*st->fn_dev->sts & NVS_STS_SPEW_BUF) {
+ for (i = 0; i < bytes; i++)
+ dev_info(st->dev, "%s buf[%u]=%x\n",
+ st->cfg->name, i, st->buf[i]);
+ dev_info(st->dev, "%s ts=%lld diff=%lld\n",
+ st->cfg->name, ts, st->ts_diff);
+ }
}
}
if ((*st->fn_dev->sts & NVS_STS_SPEW_DATA) && ts) {
} else {
enable = 1;
}
+ st->first_push = true;
+ ret = st->fn_dev->enable(st->client, st->cfg->snsr_id, enable);
+ if (!ret)
+ st->enabled = enable;
} else {
- st->dbg_data_lock = 0;
+ ret = nvs_disable(st);
}
-
- ret = st->fn_dev->enable(st->client, st->cfg->snsr_id, enable);
- if (!ret)
- st->enabled = enable;
if (*st->fn_dev->sts & NVS_STS_SPEW_MSG)
dev_info(st->dev, "%s %s enable=%x ret=%d",
__func__, st->cfg->name, enable, ret);
return ret;
}
+static void nvs_report_mode(struct nvs_state *st)
+{
+ /* Currently this is called once during initialization. However, there
+ * may be mechanisms where this is allowed to change at runtime, hence
+ * this function above nvs_attr_store for st->cfg->flags.
+ */
+ st->on_change = false;
+ st->one_shot = false;
+ switch (st->cfg->flags & REPORTING_MODE_MASK) {
+ case SENSOR_FLAG_ON_CHANGE_MODE:
+ st->on_change = true;
+ break;
+
+ case SENSOR_FLAG_ONE_SHOT_MODE:
+ st->one_shot = true;
+ break;
+ }
+}
+
static ssize_t nvs_attr_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
if (st->fn_dev->flush) {
ret = st->fn_dev->flush(st->client, st->cfg->snsr_id);
if (ret) {
- nvs_buf_push(indio_dev, st->buf, 0);
+ nvs_buf_push(indio_dev, NULL, 0);
ret = 0;
}
} else {
- nvs_buf_push(indio_dev, st->buf, 0);
+ nvs_buf_push(indio_dev, NULL, 0);
}
break;
case IIO_CHAN_INFO_BATCH_PERIOD:
msg = "IIO_CHAN_INFO_BATCH_PERIOD";
old = st->batch_period_us;
- if (SENSOR_FLAG_ONE_SHOT_MODE != (st->cfg->flags &
- REPORTING_MODE_MASK)) {
+ if (!st->one_shot) {
if (val < st->cfg->delay_us_min)
val = st->cfg->delay_us_min;
if (st->cfg->delay_us_max && (val >
} else {
if (st->batch_timeout_us)
ret = -EINVAL;
+ else
+ st->batch_period_us = val;
}
break;
memcpy(&st->buf[ret], &val,
chan->scan_type.storagebits / 8);
st->dbg_data_lock |= (1 << ch);
- st->ts++;
ret = nvs_buf_push(indio_dev, st->buf, st->ts);
if (ret > 0)
ret = 0;
if (st->ch == NULL)
return -ENOMEM;
- if (SENSOR_FLAG_ONE_SHOT_MODE == (st->cfg->flags &
- SENSOR_FLAG_SPECIAL_REPORTING_MODE))
+ if (st->one_shot)
info_mask_msk = BIT(IIO_CHAN_INFO_BATCH_FLAGS) |
BIT(IIO_CHAN_INFO_BATCH_PERIOD) |
BIT(IIO_CHAN_INFO_BATCH_TIMEOUT) |
{
int ret;
+ nvs_report_mode(st);
ret = nvs_attr(indio_dev);
if (ret) {
dev_err(st->dev, "%s nvs_attr ERR=%d\n", __func__, ret);
int ret;
dev_info(dev, "%s\n", __func__);
+ if (!snsr_cfg)
+ return -ENODEV;
+
if (snsr_cfg->snsr_id < 0) {
/* device has been disabled */
if (snsr_cfg->name)
#include "nvi.h"
-#define NVI_DRIVER_VERSION (334)
+#define NVI_DRIVER_VERSION (336)
#define NVI_VENDOR "Invensense"
#define NVI_NAME "mpu6xxx"
#define NVI_NAME_MPU6050 "mpu6050"
else
ret = nvi_wr_fifo_cfg(st, -1);
}
+ if (st->icm_fifo_off) {
+ ret |= nvi_i2c_wr(st, &st->hal->reg->fifo_rst,
+ 0x1F, __func__);
+ ret |= nvi_i2c_wr(st, &st->hal->reg->fifo_rst,
+ 0, __func__);
+ st->icm_fifo_off = false;
+ }
if (st->en_msk & (1 << DEV_DMP))
fifo_rst = 0x1E;
else
for (i = 0; i < AUX_PORT_IO; i++) {
ap = &st->aux.port[i];
if (st->snsr[DEV_AUX].enable & (1 << i) &&
- (ap->nmp.addr & BIT_I2C_READ) &&
- ap->nmp.handler) {
+ ap->nmp.addr & BIT_I2C_READ)
val |= (1 <<
st->hal->bit->slv_fifo_en[i]);
- }
}
}
st->aux.port[i].period_us, n->shutdown_bypass);
p = &st->aux.port[i];
/* PS = port structure */
- pr_info("PS: P%d OFFSET=%u DMP_CTRL=%x EN=%x HWDOUT=%x\n",
- i, p->ext_data_offset, !!(a->dmp_ctrl_msk & (1 << i)),
+ pr_info("PS: P%d EDO=%u ODR=%u DMP_CTRL=%x EN=%x HWDOUT=%x\n",
+ i, p->ext_data_offset, p->odr,
+ !!(a->dmp_ctrl_msk & (1 << i)),
!!(st->snsr[DEV_AUX].enable & (1 << i)), p->hw_do);
}
{
struct aux_port *ap;
u8 slv_ctrl;
- u8 val;
+ u8 ctrl;
+ u8 reg;
unsigned int dmp_ctrl_msk;
int ret = 0;
ap = &st->aux.port[port];
- if (en && !st->rc.i2c_slv_addr[port]) {
+ if (en && ap->nmp.addr != st->rc.i2c_slv_addr[port]) {
ret = nvi_aux_port_wr(st, port);
if (!ret)
ap->hw_do = true;
slv_ctrl = st->rc.i2c_slv_ctrl[port];
if (en) {
dmp_ctrl_msk = st->aux.dmp_ctrl_msk;
- if (st->en_msk & (1 << DEV_DMP)) {
- val = ap->nmp.dmp_ctrl | BIT_SLV_EN;
- st->aux.dmp_ctrl_msk |= (1 << port);
+ reg = ap->nmp.reg;
+ ctrl = ap->nmp.ctrl;
+ if (ap->dd && st->en_msk & (1 << DEV_DMP)) {
+ reg = ap->dd->dmp_rd_reg;
+ if (ctrl != ap->dd->dmp_rd_ctrl) {
+ ctrl = ap->dd->dmp_rd_ctrl;
+ st->aux.dmp_ctrl_msk |= (1 << port);
+ }
} else {
- val = ap->nmp.ctrl | BIT_SLV_EN;
st->aux.dmp_ctrl_msk &= ~(1 << port);
}
- if (ap->nmp.dmp_ctrl != ap->nmp.ctrl && dmp_ctrl_msk !=
- st->aux.dmp_ctrl_msk)
+ if (dmp_ctrl_msk != st->aux.dmp_ctrl_msk)
/* AUX HW needs to be reset if slv_ctrl values
* change other than enable bit.
*/
st->aux.reset_i2c = true;
+ ret = nvi_i2c_wr_rc(st,
+ &st->hal->reg->i2c_slv_reg[port],
+ reg, __func__,
+ &st->rc.i2c_slv_reg[port]);
+ ctrl |= BIT_SLV_EN;
} else {
- val = 0;
+ ctrl = 0;
st->aux.dmp_ctrl_msk &= ~(1 << port);
}
- ret = nvi_i2c_wr_rc(st, &st->hal->reg->i2c_slv_ctrl[port], val,
- __func__, &st->rc.i2c_slv_ctrl[port]);
+ ret |= nvi_i2c_wr_rc(st, &st->hal->reg->i2c_slv_ctrl[port],
+ ctrl, __func__, &st->rc.i2c_slv_ctrl[port]);
if (slv_ctrl != st->rc.i2c_slv_ctrl[port])
nvi_aux_ext_data_offset(st);
}
static int nvi_aux_port_alloc(struct nvi_state *st,
struct nvi_mpu_port *nmp, int port)
{
- int i;
+ struct nvi_aux_port_dmp_dev *dd = NULL;
+ struct nvi_dmp_aux_port *ap;
+ unsigned int i;
+ unsigned int j;
if (st->aux.reset_i2c)
nvi_reset(st, __func__, false, true, true);
if (port < 0) {
for (i = 0; i < AUX_PORT_IO; i++) {
- if (st->aux.port[i].nmp.addr == 0)
+ if (!st->aux.port[i].nmp.addr)
+ /* port available */
break;
}
- if (i == AUX_PORT_IO)
+ if (i < AUX_PORT_IO)
+ port = i;
+ else
return -ENODEV;
} else {
- if (st->aux.port[port].nmp.addr == 0)
- i = port;
+ if (st->aux.port[port].nmp.addr)
+ /* already taken */
+ return -ENODEV;
+ }
+
+ /* override port setting if DMP used */
+ if (st->hal->dmp && port < AUX_PORT_IO) {
+ for (i = 0; i < st->hal->dmp->ap_n; i++) {
+ ap = &st->hal->dmp->ap[i];
+ if (nmp->type == ap->type && ap->port_rd ==
+ (bool)(nmp->addr & BIT_I2C_READ)) {
+ if (ap->dd) {
+ for (j = 0; j < ap->dd_n; j++) {
+ if (nmp->id == ap->dd[j].dev) {
+ dd = &ap->dd[j];
+ break;
+ }
+ }
+ if (j >= ap->dd_n)
+ /* device not supported */
+ return -ENODEV;
+ }
+
+ break;
+ }
+ }
+ if (i < st->hal->dmp->ap_n && !st->aux.port[ap->port].nmp.addr)
+ port = ap->port;
else
return -ENODEV;
}
- memset(&st->aux.port[i], 0, sizeof(struct aux_port));
- memcpy(&st->aux.port[i].nmp, nmp, sizeof(struct nvi_mpu_port));
- if (!st->aux.port[i].nmp.dmp_ctrl)
- st->aux.port[i].nmp.dmp_ctrl = st->aux.port[i].nmp.ctrl;
- st->aux.port[i].period_us = st->aux.port[i].nmp.delay_us;
- return i;
+ memset(&st->aux.port[port], 0, sizeof(struct aux_port));
+ memcpy(&st->aux.port[port].nmp, nmp, sizeof(struct nvi_mpu_port));
+ st->aux.port[port].dd = dd;
+ st->aux.port[port].nmp.ctrl &= ~BIT_SLV_EN;
+ st->aux.port[port].period_us = st->aux.port[port].nmp.period_us;
+ return port;
}
static int nvi_aux_bypass_enable(struct nvi_state *st, bool en)
}
EXPORT_SYMBOL(nvi_mpu_dev_valid);
-int nvi_mpu_port_alloc(struct nvi_mpu_port *nmp, int port)
+int nvi_mpu_port_alloc(struct nvi_mpu_port *nmp)
{
struct nvi_state *st = nvi_state_local;
int ret = -EPERM;
if (nmp == NULL || !(nmp->ctrl & BITS_I2C_SLV_CTRL_LEN))
return -EINVAL;
- if (port >= AUX_PORT_IO)
+ if (nmp->addr & BIT_I2C_READ && !nmp->handler)
return -EINVAL;
nvi_mutex_lock(st);
if (!(st->sts & (NVS_STS_SHUTDOWN | NVS_STS_SUSPEND))) {
nvi_pm(st, __func__, NVI_PM_ON);
- ret = nvi_aux_port_alloc(st, nmp, port);
+ ret = nvi_aux_port_alloc(st, nmp, -1);
if (ret >= 0 && st->hal->dmp)
/* need to reinitialize DMP for new device */
st->hal->dmp->fn_init(st);
if (st != NULL) {
if (st->sts & NVI_DBG_SPEW_AUX)
- pr_info("%s port_mask %x: %x\n",
+ pr_info("%s port_mask 0x%x: %x\n",
__func__, port_mask, enable);
} else {
- pr_debug("%s port_mask %x: %x ERR -EAGAIN\n",
+ pr_debug("%s port_mask 0x%x: %x ERR -EAGAIN\n",
__func__, port_mask, enable);
return -EAGAIN;
}
}
EXPORT_SYMBOL(nvi_mpu_flush);
-int nvi_mpu_fifo(int port, unsigned int *reserve, unsigned int *max)
+int nvi_mpu_info(int read_port, struct nvi_mpu_inf *inf)
{
struct nvi_state *st = nvi_state_local;
+ struct nvi_aux_port_dmp_dev *dd;
+ unsigned int i;
int ret;
if (st != NULL) {
if (st->sts & NVI_DBG_SPEW_AUX)
- pr_info("%s port %d\n", __func__, port);
+ pr_info("%s port %d\n", __func__, read_port);
} else {
- pr_debug("%s port %d ERR -EAGAIN\n", __func__, port);
+ pr_debug("%s port %d ERR -EAGAIN\n", __func__, read_port);
return -EAGAIN;
}
+ if (!inf)
+ return -EINVAL;
+
nvi_mutex_lock(st);
- ret = nvi_aux_mpu_call_pre(st, port);
+ ret = nvi_aux_mpu_call_pre(st, read_port);
if (!ret) {
- if ((st->aux.port[port].nmp.id != ID_INVALID) &&
- (st->aux.port[port].nmp.id < ID_INVALID_END)) {
- if (reserve)
- /* batch not supported at this time */
- *reserve = 0;
- if (max)
- /* batch not supported at this time */
- *max = 0;
- ret = nvi_aux_mpu_call_post(st, "nvi_mpu_fifo=", 0);
+ i = st->hal->dev[DEV_AUX]->src;
+ inf->period_us_min = st->src[i].period_us_min;
+ inf->period_us_max = st->src[i].period_us_max;
+ /* batch not supported at this time */
+ inf->fifo_reserve = 0;
+ inf->fifo_max = 0;
+ dd = st->aux.port[read_port].dd;
+ if (dd) {
+ inf->dmp_rd_len_sts = dd->dmp_rd_len_sts;
+ inf->dmp_rd_len_data = dd->dmp_rd_len_data;
+ inf->dmp_rd_be_sts = dd->dmp_rd_be_sts;
+ inf->dmp_rd_be_data = dd->dmp_rd_be_data;
} else {
- ret = -EINVAL;
+ inf->dmp_rd_len_sts = 0;
+ inf->dmp_rd_len_data = 0;
+ inf->dmp_rd_be_sts = false;
+ inf->dmp_rd_be_data = false;
}
+ ret = nvi_aux_mpu_call_post(st, "nvi_mpu_info=", 0);
}
nvi_mutex_unlock(st);
return ret;
}
-EXPORT_SYMBOL(nvi_mpu_fifo);
+EXPORT_SYMBOL(nvi_mpu_info);
int nvi_mpu_bypass_request(bool enable)
{
for (i = 0; i < AUX_PORT_IO; i++) {
ap = &st->aux.port[i];
if ((st->rc.i2c_slv_ctrl[i] & BIT_SLV_EN) &&
- (ap->nmp.addr & BIT_I2C_READ) &&
- (ap->nmp.handler != NULL)) {
+ ap->nmp.addr & BIT_I2C_READ) {
p = &st->aux.ext_data[ap->ext_data_offset];
len = ap->nmp.ctrl & BITS_I2C_SLV_CTRL_LEN;
ap->nmp.handler(p, len, ts, ap->nmp.ext_driver);
};
};
+struct nvi_aux_port_dmp_dev {
+ enum ext_slave_id dev;
+ unsigned int dmp_rd_len_sts;
+ unsigned int dmp_rd_len_data;
+ bool dmp_rd_be_sts;
+ bool dmp_rd_be_data;
+ u8 dmp_rd_ctrl;
+ u8 dmp_rd_reg;
+};
+
+struct nvi_dmp_aux_port {
+ enum secondary_slave_type type;
+ bool port_rd;
+ int port;
+ unsigned int dd_n;
+ struct nvi_aux_port_dmp_dev *dd;
+};
+
+struct aux_port {
+ struct nvi_mpu_port nmp;
+ struct nvi_aux_port_dmp_dev *dd;
+ unsigned int ext_data_offset;
+ unsigned int period_us;
+ unsigned int timeout_us;
+ unsigned int odr;
+ s64 ts_last;
+ bool ts_reset;
+ bool flush;
+ bool hw_valid;
+ bool hw_en;
+ bool hw_do;
+};
+
+struct aux_ports {
+ struct aux_port port[AUX_PORT_MAX];
+ s64 bypass_timeout_ns;
+ unsigned int bypass_lock;
+ unsigned int dmp_en_msk;
+ unsigned int dmp_ctrl_msk;
+ unsigned int ext_data_n;
+ u8 delay_hw;
+ unsigned char ext_data[AUX_EXT_DATA_REG_MAX];
+ unsigned char clock_i2c;
+ bool reset_i2c;
+ bool reset_fifo;
+};
+
struct nvi_dmp {
const u8 const *fw;
unsigned int fw_ver;
unsigned int en_msk;
unsigned int dd_n;
const struct nvi_dmp_dev *dd;
+ struct nvi_dmp_aux_port *ap;
+ int ap_n;
int (*fn_rd)(struct nvi_state *st, s64 ts, unsigned int n);
int (*fn_clk_n)(struct nvi_state *st, u32 *clk_n);
int (*fn_init)(struct nvi_state *st);
bool matrix;
};
-struct aux_port {
- struct nvi_mpu_port nmp;
- unsigned int ext_data_offset;
- unsigned int period_us;
- unsigned int timeout_us;
- unsigned int odr;
- s64 ts_last;
- bool ts_reset;
- bool flush;
- bool hw_valid;
- bool hw_en;
- bool hw_do;
-};
-
-struct aux_ports {
- struct aux_port port[AUX_PORT_MAX];
- s64 bypass_timeout_ns;
- unsigned int bypass_lock;
- unsigned int dmp_en_msk;
- unsigned int dmp_ctrl_msk;
- unsigned int ext_data_n;
- u8 delay_hw;
- unsigned char ext_data[AUX_EXT_DATA_REG_MAX];
- unsigned char clock_i2c;
- bool reset_i2c;
- bool reset_fifo;
-};
-
/**
* struct inv_chip_info_s - Chip related information.
* @product_id: Product id.
bool irq_dis;
bool irq_set_irq_wake;
bool icm_dmp_war;
+ bool icm_fifo_off;
int pm;
u32 dmp_clk_n;
s64 ts_now;
*/
#include <linux/delay.h>
-#include <linux/kernel.h>
#include "nvi.h"
#include "nvi_dmp_icm.h"
(1 << DEV_QTN) | \
(1 << DEV_GMR) | \
(1 << DEV_GYU))
+
#define AUX_PORT_DEV_GMF (0)
#define MSK_AUX_PORTS_DEV_GMF (0x3)
#define AUX_PORT_DEV_PRS (3)
-#define MSK_AUX_PORTS_DEV_PRS (0x8)
+/* all ports enabled when pressure enabled
+ * see nvi_dmp_aux_war
+ */
+#define MSK_AUX_PORTS_DEV_PRS (0xF)
+/* redefine the port to the HW */
+#define DMP_AUX_PORT_0 (AUX_PORT_DEV_GMF)
+#define DMP_AUX_PORT_0_MSK (MSK_AUX_PORTS_DEV_GMF)
+#define DMP_AUX_PORT_2 (-1)
+#define DMP_AUX_PORT_2_MSK (0)
+#define DMP_AUX_PORT_3 (AUX_PORT_DEV_PRS)
+#define DMP_AUX_PORT_3_MSK (MSK_AUX_PORTS_DEV_PRS)
+
#define MSK_EN_AUX_PORTS (((1 << (AUX_PORT_IO + DEV_N_AUX)) - \
1) & ~MSK_DEV_SNSR)
-
-#define DEFAULT_ACCEL_GAIN (0x02000000)
-#define PED_ACCEL_GAIN (0x04000000)
-#define DMP_ACC_PERIOD_US_PED (19608)
-#define DMP_MULTI_SHIFT (30)
-
#define DMP_HDR_LEN_MAX (4)
#define DMP_HDR1_HDR2_MSK (0x0008)
#define DMP_HDR1_PUSH_MSK (0xFEF0)
#define DMP_DATA_OUT_CTL_HDR2_MSK (0x0000FFFF)
+/* INV defines */
+#define DEFAULT_ACCEL_GAIN (0x02000000)
+#define PED_ACCEL_GAIN (0x04000000)
+#define DMP_ACC_PERIOD_US_PED (19608)
+static struct nvi_aux_port_dmp_dev ap_dd_gmf[] = {
+ {
+ .dev = COMPASS_ID_AK8963,
+ .dmp_rd_len_sts = 2,
+ .dmp_rd_len_data = 6,
+ .dmp_rd_be_sts = true,
+ .dmp_rd_be_data = true,
+ .dmp_rd_ctrl = 0x59,
+ .dmp_rd_reg = 0x01,
+ },
+ {
+ .dev = COMPASS_ID_AK8975,
+ .dmp_rd_len_sts = 2,
+ .dmp_rd_len_data = 6,
+ .dmp_rd_be_sts = true,
+ .dmp_rd_be_data = true,
+ .dmp_rd_ctrl = 0x59,
+ .dmp_rd_reg = 0x01,
+ },
+ {
+ .dev = COMPASS_ID_AK09911,
+ .dmp_rd_len_sts = 2,
+ .dmp_rd_len_data = 6,
+ .dmp_rd_be_sts = true,
+ .dmp_rd_be_data = true,
+ .dmp_rd_ctrl = 0x5A,
+ .dmp_rd_reg = 0x10,
+ },
+};
+
+static struct nvi_aux_port_dmp_dev ap_dd_prs[] = {
+ {
+ .dev = PRESSURE_ID_BMP280,
+ .dmp_rd_len_sts = 0,
+ .dmp_rd_len_data = 6,
+ .dmp_rd_be_sts = true,
+ .dmp_rd_be_data = true,
+ .dmp_rd_ctrl = 0x06,
+ .dmp_rd_reg = 0xF7,
+ },
+};
+
+static struct nvi_dmp_aux_port nvi_dmp_ap[] = {
+ /* ICM DMP FW supports only this configuration */
+ /* port 0 */
+ {
+ .type = SECONDARY_SLAVE_TYPE_COMPASS,
+ .port_rd = true,
+ .port = AUX_PORT_DEV_GMF,
+ .dd_n = ARRAY_SIZE(ap_dd_gmf),
+ .dd = ap_dd_gmf,
+ },
+ /* port 1 */
+ {
+ .type = SECONDARY_SLAVE_TYPE_COMPASS,
+ .port_rd = false,
+ .port = AUX_PORT_DEV_GMF + 1,
+ },
+ /* port 2 not supported */
+ /* port 3 */
+ {
+ .type = SECONDARY_SLAVE_TYPE_PRESSURE,
+ .port_rd = true,
+ .port = AUX_PORT_DEV_PRS,
+ .dd_n = ARRAY_SIZE(ap_dd_prs),
+ .dd = ap_dd_prs,
+ },
+};
+
struct nvi_dmp_dev {
unsigned int dev;
unsigned int aux_port;
static int nvi_dmp_gmf_init(struct nvi_state *st, u32 *out_ctl,
unsigned int en_msk, unsigned int irq_msk)
{
- if (st->aux.port[AUX_PORT_DEV_GMF].nmp.type !=
- SECONDARY_SLAVE_TYPE_COMPASS)
- /* disable without error if no compass */
- return 1;
-
- if (!st->aux.port[AUX_PORT_DEV_GMF].nmp.handler)
- /* no handler */
- return 1;
-
st->src[SRC_AUX].period_us_max =
st->hal->src[SRC_AUX].period_us_min * 8;
if (irq_msk & (1 << (AUX_PORT_DEV_GMF + DEV_N_AUX)) ||
return ret;
}
-/* prs = pressure */
-static int nvi_dmp_prs_init(struct nvi_state *st, u32 *out_ctl,
- unsigned int en_msk, unsigned int irq_msk)
-{
- if (st->aux.port[AUX_PORT_DEV_PRS].nmp.type !=
- SECONDARY_SLAVE_TYPE_PRESSURE)
- /* disable without error if no pressure */
- return 1;
-
- return 0;
-}
-
static int nvi_dmp_gyr_init(struct nvi_state *st, u32 *out_ctl,
unsigned int en_msk, unsigned int irq_msk)
{
},
{
.dev = DEV_AUX,
- .aux_port = AUX_PORT_DEV_GMF,
- .depend_msk = (MSK_AUX_PORTS_DEV_GMF << DEV_N_AUX),
+ .aux_port = DMP_AUX_PORT_0,
+ .depend_msk = (DMP_AUX_PORT_0_MSK << DEV_N_AUX),
.buf_n = 6,
.int_ctl = CPASS_SET,
.odr_cfg = ODR_CPASS,
},
{
.dev = DEV_AUX,
- .aux_port = AUX_PORT_DEV_PRS,
+ .aux_port = DMP_AUX_PORT_2,
+ .depend_msk = (DMP_AUX_PORT_2_MSK << DEV_N_AUX),
+ .buf_n = 8,
+ .int_ctl = ALS_SET,
+ .odr_cfg = ODR_ALS,
+ .odr_cntr = ODR_CNTR_ALS,
+ .odr_src = SRC_AUX,
+ },
+ {
+ .dev = DEV_AUX,
+ .aux_port = DMP_AUX_PORT_3,
+ .depend_msk = (DMP_AUX_PORT_3_MSK << DEV_N_AUX),
.buf_n = 6,
.int_ctl = PRESSURE_SET,
.odr_cfg = ODR_PRESSURE,
.odr_cntr = ODR_CNTR_PRESSURE,
.odr_src = SRC_AUX,
- .fn_init = &nvi_dmp_prs_init,
},
};
},
{
.dev = DEV_AUX,
- .aux_port = AUX_PORT_DEV_GMF,
+ .aux_port = DMP_AUX_PORT_0,
.data_n = 2,
.hdr_msk = CPASS_ACCURACY_SET,
},
},
{
.dev = DEV_AUX,
- .aux_port = AUX_PORT_DEV_GMF,
+ .aux_port = DMP_AUX_PORT_0,
.data_n = 6,
.hdr_msk = CPASS_SET,
},
{
.dev = DEV_AUX,
- .aux_port = -1, /* ALS */
+ .aux_port = DMP_AUX_PORT_2,
.data_n = 8,
.hdr_msk = ALS_SET,
},
},
{
.dev = DEV_AUX,
- .aux_port = AUX_PORT_DEV_PRS,
+ .aux_port = DMP_AUX_PORT_3,
.data_n = 6,
.hdr_msk = PRESSURE_SET,
},
return;
ap = &st->aux.port[dh->aux_port];
- if (!ap->nmp.ext_driver)
- return;
-
ap->nmp.handler(&st->buf[buf_i], dh->data_n,
nvi_ts_dev(st, 0, dh->dev, dh->aux_port),
ap->nmp.ext_driver);
"%s ERR: DMP sync HDR2=%hx\n",
__func__, hdr2);
nvi_err(st);
+ st->icm_fifo_off = true;
return -1;
}
"%s ERR: DMP sync HDR1: %x\n",
__func__, hdr1);
nvi_err(st);
+ st->icm_fifo_off = true;
return -1;
}
}
* SRC_AUX has timestamps set to ts_now = 0 since SRC_AUX has fixed
* rates and can't sync with the other sources.
*/
- period_us = min(period_us_req[SRC_GYR], period_us_req[SRC_ACC]);
+ period_us = -1;
+ for (src = 0; src < st->hal->src_n; src++) {
+ if (period_us_req[src] < period_us)
+ period_us = period_us_req[src];
+ }
+
/* The latest INV driver implements this WAR with a twist: the gmf
* lookup table, nvi_dmp_gmf_us_periods.
*/
period_us = nvi_dmp_gmf_us_periods[i];
}
+ period_us_req[SRC_AUX] = period_us;
+ } else if (en_msk & MSK_EN_AUX_PORTS) {
+ /* other aux device(s) enabled */
period_us_req[SRC_AUX] = period_us;
} else {
period_us_req[SRC_AUX] = st->src[SRC_AUX].period_us_req;
continue;
if (dd->dev == DEV_AUX) {
+ if (dd->aux_port >= AUX_PORT_IO)
+ /* unused port */
+ continue;
+
if (!(en_msk & (1 << (dd->aux_port + DEV_N_AUX))))
/* AUX sensor not enabled */
continue;
}
if (irq_msk & (1 << dd->dev)) {
/* ODR rate for sent sensor data */
+#if ICM_DMP_FW_VER == 2
+ /* everything is off of SRC_GYR for v.2 */
+ odr_cfg = period_us / st->src[SRC_GYR].period_us_src;
+#else /* ICM_DMP_FW_VER < 2 */
odr_cfg = period_us /
st->src[dd->odr_src].period_us_src;
+#endif /* ICM_DMP_FW_VER */
if (odr_cfg)
odr_cfg--;
} else {
unsigned int j;
unsigned int k;
- if (st->aux.port[AUX_PORT_DEV_GMF].nmp.type !=
- SECONDARY_SLAVE_TYPE_COMPASS)
+ if (!st->aux.port[AUX_PORT_DEV_GMF].nmp.addr)
+ /* no device */
return -EINVAL;
nmp = &st->aux.port[AUX_PORT_DEV_GMF].nmp;
return ret;
}
+static int nvi_dmp_aux_war(struct nvi_state *st)
+{
+ if (!st->aux.port[3].nmp.addr)
+ /* pressure not populated */
+ return 0;
+
+ if (!st->aux.port[0].dd)
+ /* need this info for the WAR */
+ return -EINVAL;
+
+ /* The ICM DMP FW requires port 0 to be enabled and reading 10 bytes
+ * and port 2 enabled and reading 8 bytes when port 3 (pressure in
+ * continuous mode) is enabled reading 6 bytes.
+ * To accomplish this, we create fake port data for port 2 that will
+ * read 8 bytes from the pressure sensor.
+ * When the pressure is enabled, the MSK_AUX_PORTS_DEV_PRS will also
+ * enable ports 0, 1, and 2.
+ * When the pressure is disabled, either the nvi_aux_enable will detect
+ * that port 2 is no longer enabled when not in DMP mode or if in DMP
+ * mode port 2 will simply not be enabled.
+ */
+ /* Obviously if compass is not populated or port 2 has a legitimate
+ * device on it, then this WAR needs to be modified to account for all
+ * possible scenarios so that port 0 reads 10 bytes and port 2 reads 8
+ * bytes when port 3 is enabled to read 6 bytes of pressure/temp data.
+ */
+ st->aux.port[2].nmp.addr = st->aux.port[3].nmp.addr;
+ st->aux.port[2].nmp.reg = 0x88; /* BMP280_REG_CWORD00 */
+ /* Note that technically the above is true and is what INV also does as
+ * a WAR in their source drop. However, due to the port 0 big endian
+ * byte swapping read configuration on an odd address that leaves a
+ * byte dangling, the actual number of bytes needing to be read on port
+ * 2 is 9 for some compass devices.
+ */
+ st->aux.port[2].nmp.ctrl = 8 + 10 - (st->aux.port[0].dd->dmp_rd_ctrl &
+ BITS_I2C_SLV_CTRL_LEN);
+ return 0;
+}
+
static int nvi_dmp_init(struct nvi_state *st)
{
int ret;
ret = nvi_dmp_init_gyr(st);
nvi_dmp_init_gmf(st);
+ /* WAR: DMP FW for auxiliary ports has issues */
+ nvi_dmp_aux_war(st);
return ret;
}
en = false;
if (dd->dev == DEV_AUX) {
+ if (dd->aux_port >= AUX_PORT_IO)
+ /* unused port */
+ continue;
+
if (en_msk & (1 << (dd->aux_port + DEV_N_AUX)))
en = true;
} else if (dd->dev < DEV_AUX) {
if (en) {
if (dd->int_ctl && (irq_msk & (1 << dd->dev)))
out_ctl |= (dd->int_ctl << 16);
- st->snsr[dd->dev].buf_n = dd->buf_n;
- st->snsr[dd->dev].buf_shft = dd->buf_shft;
+ if (dd->dev != DEV_AUX) {
+ st->snsr[dd->dev].buf_n = dd->buf_n;
+ st->snsr[dd->dev].buf_shft = dd->buf_shft;
+ }
} else {
if (dd->dev == DEV_AUX)
en_msk &= ~(1 << (dd->aux_port + DEV_N_AUX));
for (i = 0; i < ARRAY_SIZE(nvi_dmp_devs); i++) {
dd = &nvi_dmp_devs[i];
if (dd->dev == DEV_AUX) {
+ if (dd->aux_port >= AUX_PORT_IO)
+ /* unused port */
+ continue;
+
if (st->snsr[DEV_AUX].enable & (1 << dd->aux_port)) {
irq_msk |= (1 << DEV_AUX);
irq_msk |= (1 << (dd->aux_port + DEV_N_AUX));
st->src[SRC_AUX].period_us_max = st->hal->src[SRC_AUX].period_us_max;
if (!ret) {
st->en_msk |= (1 << DEV_DMP);
+ /* TODO: WAR: pm2 has a mind of its own */
ret = nvi_i2c_wr(st, &st->hal->reg->pm2, 0, __func__);
nvi_push_delay(st);
ret |= nvi_reset(st, __func__, true, false, true);
.en_msk = MSK_DEV_ALL,
.dd_n = ARRAY_SIZE(nvi_dmp_devs),
.dd = nvi_dmp_devs,
+ .ap = nvi_dmp_ap,
+ .ap_n = ARRAY_SIZE(nvi_dmp_ap),
.fn_rd = &nvi_dmp_rd,
.fn_clk_n = &nvi_dmp_clk_n,
.fn_init = &nvi_dmp_init,
#define AUX_PORT_DEV_GMF (0)
#define MSK_AUX_PORTS_DEV_GMF (0x3)
#define AUX_PORT_DEV_PRS (2)
-#define MSK_AUX_PORTS_DEV_PRS (0xC)
+/* The MPU DMP FW requires port 0 to be enabled and reading 10 bytes
+ * when pressure is enabled. This is accomplished by enabling the
+ * compass with the pressure dependency mask, MSK_AUX_PORTS_DEV_PRS.
+ */
+#define MSK_AUX_PORTS_DEV_PRS (0xF)
#define MSK_EN_AUX_PORTS (((1 << (AUX_PORT_IO + DEV_N_AUX)) - \
1) & ~MSK_DEV_SNSR)
+static struct nvi_aux_port_dmp_dev ap_dd_gmf[] = {
+ {
+ .dev = COMPASS_ID_AK8963,
+ .dmp_rd_len_sts = 0,
+ .dmp_rd_len_data = 6,
+ .dmp_rd_be_sts = true,
+ .dmp_rd_be_data = false,
+ .dmp_rd_ctrl = 0x0A,
+ .dmp_rd_reg = 0x01,
+ },
+ {
+ .dev = COMPASS_ID_AK8975,
+ .dmp_rd_len_sts = 0,
+ .dmp_rd_len_data = 6,
+ .dmp_rd_be_sts = true,
+ .dmp_rd_be_data = false,
+ .dmp_rd_ctrl = 0x0A,
+ .dmp_rd_reg = 0x01,
+ },
+ {
+ .dev = COMPASS_ID_AK09911,
+ .dmp_rd_len_sts = 0,
+ .dmp_rd_len_data = 6,
+ .dmp_rd_be_sts = true,
+ .dmp_rd_be_data = false,
+ .dmp_rd_ctrl = 0x0A,
+ .dmp_rd_reg = 0x10,
+ },
+};
+
+static struct nvi_aux_port_dmp_dev ap_dd_prs[] = {
+ {
+ .dev = PRESSURE_ID_BMP280,
+ .dmp_rd_len_sts = 0,
+ .dmp_rd_len_data = 6,
+ .dmp_rd_be_sts = true,
+ .dmp_rd_be_data = true,
+ .dmp_rd_ctrl = 0x06,
+ .dmp_rd_reg = 0xF7,
+ },
+};
+
+static struct nvi_dmp_aux_port nvi_dmp_ap[] = {
+ /* MPU DMP FW supports only this configuration */
+ /* port 0 */
+ {
+ .type = SECONDARY_SLAVE_TYPE_COMPASS,
+ .port_rd = true,
+ .port = AUX_PORT_DEV_GMF,
+ .dd_n = ARRAY_SIZE(ap_dd_gmf),
+ .dd = ap_dd_gmf,
+ },
+ /* port 1 */
+ {
+ .type = SECONDARY_SLAVE_TYPE_COMPASS,
+ .port_rd = false,
+ .port = AUX_PORT_DEV_GMF + 1,
+ },
+ /* port 2 */
+ {
+ .type = SECONDARY_SLAVE_TYPE_PRESSURE,
+ .port_rd = true,
+ .port = AUX_PORT_DEV_PRS,
+ .dd_n = ARRAY_SIZE(ap_dd_prs),
+ .dd = ap_dd_prs,
+ },
+ /* port 3 */
+ {
+ .type = SECONDARY_SLAVE_TYPE_PRESSURE,
+ .port_rd = false,
+ .port = AUX_PORT_DEV_PRS + 1,
+ },
+};
+
struct nvi_dmp_dev {
unsigned int dev;
unsigned int aux_port;
};
-/* prs = pressure */
-static int nvi_dmp_prs_init(struct nvi_state *st, unsigned int *en_msk)
-{
- return 1;
-}
-
-/* gmf = GeoMagnetic Field (compass) */
-static int nvi_dmp_gmf_init(struct nvi_state *st, unsigned int *en_msk)
-{
- if (st->aux.port[AUX_PORT_DEV_GMF].nmp.type !=
- SECONDARY_SLAVE_TYPE_COMPASS)
- /* DMP shouldn't run if AUX device not supported */
- return -EINVAL;
-
- if (!st->aux.port[AUX_PORT_DEV_GMF].nmp.handler)
- /* no handler */
- return 1;
-
- return 0;
-}
-
static int nvi_dmp_sm_init(struct nvi_state *st, unsigned int *en_msk)
{
int ret;
.odr_cfg = KEY_CFG_GYRO_ODR,
.odr_cntr = KEY_ODR_CNTR_GYRO,
},
-#ifdef NVI_6QUAT_EN
+#if NVI_6QUAT_EN
{
.dev = DEV_QTN,
.depend_msk = (1 << DEV_ACC) |
.aux_port = AUX_PORT_DEV_GMF,
.depend_msk = (MSK_AUX_PORTS_DEV_GMF << DEV_N_AUX),
.buf_n = 6,
- .fn_init = &nvi_dmp_gmf_init,
.en_addr = CFG_OUT_CPASS,
.en_len = 2,
.en = { 0xA3, 0xA3 },
.aux_port = AUX_PORT_DEV_PRS,
.depend_msk = (MSK_AUX_PORTS_DEV_PRS << DEV_N_AUX),
.buf_n = 6,
- .fn_init = &nvi_dmp_prs_init,
.en_addr = CFG_OUT_PRESS,
.en_len = 2,
.en = { 0xA3, 0xA3 },
},
};
-static int nvi_dmp_rd(struct nvi_state *st, s64 ts, unsigned int n)
+static unsigned int nvi_dmp_dbg(struct nvi_state *st, unsigned int n)
+{
+ dev_info(&st->i2c->dev,
+ "n=%04u %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ n, st->buf[st->buf_i], st->buf[st->buf_i + 1],
+ st->buf[st->buf_i + 2], st->buf[st->buf_i + 3],
+ st->buf[st->buf_i + 4], st->buf[st->buf_i + 5],
+ st->buf[st->buf_i + 6], st->buf[st->buf_i + 7]);
+ dev_info(&st->i2c->dev,
+ " %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ st->buf[st->buf_i + 8], st->buf[st->buf_i + 9],
+ st->buf[st->buf_i + 10], st->buf[st->buf_i + 11],
+ st->buf[st->buf_i + 12], st->buf[st->buf_i + 13],
+ st->buf[st->buf_i + 14], st->buf[st->buf_i + 15]);
+ if (n > 16) {
+ st->buf_i += 16;
+ n -= 16;
+ } else {
+ st->buf_i += n;
+ n = 0;
+ }
+ return n;
+}
+
+static void nvi_dmp_rd_aux(struct nvi_state *st, struct nvi_dmp_hdr *dh,
+ unsigned int buf_i, s64 ts)
{
- const struct nvi_dmp_hdr *dh;
struct aux_port *ap;
+
+ if (dh->aux_port >= AUX_PORT_IO)
+ return;
+
+ if (!(st->snsr[DEV_AUX].enable & (1 << dh->aux_port)))
+ return;
+
+ ap = &st->aux.port[dh->aux_port];
+ ap->nmp.handler(&st->buf[buf_i], dh->buf_n,
+ nvi_ts_dev(st, ts, dh->dev, dh->aux_port),
+ ap->nmp.ext_driver);
+}
+
+static int nvi_dmp_rd(struct nvi_state *st, s64 ts, unsigned int n)
+{
+ struct nvi_dmp_hdr *dh;
unsigned int dh_i;
unsigned int i;
u8 byte;
while (n > DMP_HDR_LEN_MAX) {
+ if (st->sts & NVI_DBG_SPEW_FIFO) {
+ n = nvi_dmp_dbg(st, n);
+ continue;
+ }
+
if (st->sts & (NVS_STS_SUSPEND | NVS_STS_SHUTDOWN))
return -1;
}
if (dh_i >= ARRAY_SIZE(nvi_dmp_hdrs)) {
/* unknown header: lost DMP sync so DMP reset */
- if (st->sts & NVI_DBG_SPEW_FIFO)
+ if (st->sts & NVI_DBG_SPEW_MSG)
dev_err(&st->i2c->dev,
"%s ERR: DMP sync HDR: %x %x %x %x\n",
__func__, st->buf[st->buf_i],
}
if (n > dh->buf_n + i) {
- if (dh->dev == DEV_AUX) {
- if (st->sts & NVI_DBG_SPEW_FIFO)
- dev_info(&st->i2c->dev,
- "%s DMP HDR: AUX port=%u\n",
- __func__, dh->aux_port);
- ap = &st->aux.port[dh->aux_port];
- ap->nmp.handler(&st->buf[st->buf_i + i],
- dh->buf_n,
- nvi_ts_dev(st, ts, dh->dev,
- dh->aux_port),
- ap->nmp.ext_driver);
- } else if (dh->dev < DEV_N) {
- if (st->sts & NVI_DBG_SPEW_FIFO)
- dev_info(&st->i2c->dev,
- "%s DMP HDR: %s\n", __func__,
- st->snsr[dh->dev].cfg.name);
+ if (dh->dev == DEV_AUX)
+ nvi_dmp_rd_aux(st, dh, st->buf_i + i, ts);
+ else if (dh->dev < DEV_N)
nvi_push(st, dh->dev, &st->buf[st->buf_i + i],
nvi_ts_dev(st, ts, dh->dev, 0));
- }
i += dh->buf_n;
st->buf_i += i;
n -= i;
{ 0x36, 0x57, 0x76 },
{ 0x37, 0x57, 0x76 },
{ 0x37, 0x56, 0x76 },
- { 0x37, 0x57, 0x77 },
+ { 0x37, 0x56, 0x77 },
{ 0x37, 0x56, 0x77 },
{ 0x36, 0x57, 0x77 },
{ 0x36, 0x56, 0x77 },
.en_msk = (1 << DEV_SM) | (1 << DEV_QTN),
.dd_n = ARRAY_SIZE(nvi_dmp_devs),
.dd = nvi_dmp_devs,
+ .ap = nvi_dmp_ap,
+ .ap_n = ARRAY_SIZE(nvi_dmp_ap),
.fn_rd = &nvi_dmp_rd,
.fn_clk_n = &nvi_dmp_clk_n,
.fn_init = &nvi_dmp_init,
ret = nvi_aux_delay(st, __func__);
}
if (st->sts & (NVS_STS_SPEW_MSG | NVI_DBG_SPEW_MSG))
- dev_info(&st->i2c->dev, "%s src[SRC_AUX]: period=%u err=%d\n",
- __func__, st->src[SRC_AUX].period_us_req, ret);
+ dev_info(&st->i2c->dev,
+ "%s src[SRC_AUX] period_req=%u period_src=%u err=%d\n",
+ __func__, st->src[SRC_AUX].period_us_req,
+ st->src[SRC_AUX].period_us_src, ret);
return ret;
}
* defined in struct i2c_client.irq, the driver is configured to only use the
* device's continuous mode if the device supports it. If the device does not
* support continuous mode, then the interrupt is not used.
- * If the device is connected to the MPU, the interrupt from the board file is
- * used as a SW flag. The interrupt itself is never touched so any value can
- * be used. If the struct i2c_client.irq is > 0, then the driver will only use
- * the continuous modes of the device if supported. This frees the MPU
- * auxiliary port used for writes. This configuration would be used if another
- * MPU auxiliary port was needed for another device connected to the MPU.
* If the device is connected to the host, the delay timing used in continuous
* mode is the one closest to the device's supported modes. Example: A 70ms
* request will use the 125ms from the possible 10ms and 125ms on the AK8963.
#include <linux/mpu_iio.h>
#endif /* AKM_NVI_MPU_SUPPORT */
-#define AKM_DRIVER_VERSION (325)
+#define AKM_DRIVER_VERSION (336)
#define AKM_VENDOR "AsahiKASEI"
#define AKM_NAME "ak89xx"
#define AKM_NAME_AK8963 "ak8963"
unsigned int rr_i; /* resolution/range index */
u16 i2c_addr; /* I2C address */
u8 dev_id; /* device ID */
+ unsigned int dmp_rd_len_sts; /* status length from DMP */
+ unsigned int dmp_rd_len_data; /* data length from DMP */
+ bool dmp_rd_be_sts; /* status endian from DMP */
+ bool dmp_rd_be_data; /* data endian from DMP */
bool irq_dis; /* interrupt host disable flag */
bool initd; /* set if initialized */
bool matrix_en; /* handle matrix internally */
+ bool cmode; /* continuous mode */
bool mpu_en; /* if device behind MPU */
bool port_en[PORT_N]; /* enable status of MPU write port */
int port_id[PORT_N]; /* MPU port ID */
u8 mode_rom_read;
struct akm_cmode *cmode_tbl;
bool irq;
+#if AKM_NVI_MPU_SUPPORT
unsigned int mpu_id;
+#endif /* AKM_NVI_MPU_SUPPORT */
};
int ret = 0;
#if AKM_NVI_MPU_SUPPORT
- if (st->mpu_en && !st->i2c->irq) {
+ if (st->mpu_en && !st->cmode) {
ret = nvi_mpu_data_out(st->port_id[WR], mode);
} else {
ret = akm_nvi_mpu_bypass_request(st);
if (!ret) {
- if (st->i2c->irq) {
+ if (st->cmode) {
ret = akm_i2c_wr(st, st->hal->reg_mode,
AKM_MODE_POWERDOWN);
if (mode & st->hal->mode_mask) {
}
}
#else /* AKM_NVI_MPU_SUPPORT */
- if (st->i2c->irq) {
+ if (st->cmode) {
ret = akm_i2c_wr(st, st->hal->reg_mode,
AKM_MODE_POWERDOWN);
if (mode & st->hal->mode_mask) {
if (ret > 0)
mdelay(AKM_HW_DELAY_POR_MS);
} else {
- if (st->i2c->irq) {
+ if (st->cmode) {
ret = nvs_vregs_sts(st->vreg, ARRAY_SIZE(akm_vregs));
if ((ret < 0) || (ret == ARRAY_SIZE(akm_vregs))) {
ret = akm_mode_wr(st, AKM_MODE_POWERDOWN);
int ret;
mode = AKM_MODE_SINGLE;
- if (st->i2c->irq) {
+ if (st->cmode) {
i = 0;
while (st->hal->cmode_tbl[i].t_us) {
mode = st->hal->cmode_tbl[i].mode;
unsigned int i;
int ret;
- if (ts < 0)
+ if (ts < 0 || !len)
/* error - just drop */
return;
}
if (st->enabled) {
- if (len == 2) {
- /* status from the DMP in big endian */
- st->magn[AXIS_N] = be16_to_cpup((s16 *)data);
+ if (len == st->dmp_rd_len_sts) {
+ /* this is the status data from the DMP */
+ if (st->dmp_rd_be_sts)
+ st->magn[AXIS_N] = be16_to_cpup((u16 *)data);
+ else
+ st->magn[AXIS_N] = le16_to_cpup((u16 *)data);
return;
}
- if (len == 6) {
- /* this data is from the DMP in big endian */
- be = true;
+ if (len == st->dmp_rd_len_data) {
+ /* this data is from the DMP */
+ be = st->dmp_rd_be_data;
i = 0;
ret = 1;
} else {
return ret;
}
-static void nvi_disable_irq(struct akm_state *st)
+static void akm_disable_irq(struct akm_state *st)
{
if (!st->irq_dis) {
disable_irq_nosync(st->i2c->irq);
}
}
-static void nvi_enable_irq(struct akm_state *st)
+static void akm_enable_irq(struct akm_state *st)
{
if (st->irq_dis) {
enable_irq(st->i2c->irq);
if (st->mpu_en) {
ret = akm_ports_enable(st, false);
} else {
- if (st->i2c->irq)
- nvi_disable_irq(st);
+ if (st->cmode)
+ akm_disable_irq(st);
else
cancel_delayed_work(&st->dw);
}
} else {
st->enabled = 1;
if (!st->mpu_en) {
- if (st->i2c->irq)
- nvi_enable_irq(st);
+ if (st->cmode)
+ akm_enable_irq(st);
else
schedule_delayed_work(&st->dw,
usecs_to_jiffies(
if (!ret)
#endif /* AKM_NVI_MPU_SUPPORT */
st->poll_delay_us = period;
- if (st->enabled && st->i2c->irq && !ret)
+ if (st->enabled && st->cmode && !ret)
ret = akm_mode(st);
return ret;
}
st->asa_q30[AXIS_Y]);
t += snprintf(buf + t, PAGE_SIZE - t, "asa_q30_z=%llu\n",
st->asa_q30[AXIS_Z]);
+ t += snprintf(buf + t, PAGE_SIZE - t, "cmode_enable=%x\n", st->cmode);
return t;
}
{
#if AKM_NVI_MPU_SUPPORT
struct nvi_mpu_port nmp;
+ struct nvi_mpu_inf inf;
unsigned int i;
u64 q30;
u8 config_boot;
u8 val = 0;
int ret;
- if (st->i2c->irq < 0)
- st->i2c->irq = 0;
if (!strcmp(name, AKM_NAME_AK8963))
st->dev_id = AKM_DEVID_AK8963;
else if (!strcmp(name, AKM_NAME_AK8975))
ret = akm_id_hal(st, st->dev_id);
else
ret = akm_id_compare(st, name);
- if (!ret) {
- akm_init_hw(st);
- nmp.addr = st->i2c_addr | 0x80;
- nmp.reg = st->hal->reg_start_rd;
- nmp.ctrl = 10; /* MPU FIFO can't handle odd size */
- nmp.dmp_ctrl = 0x59; /* switch to big endian */
- nmp.data_out = 0;
- nmp.delay_ms = 0;
- nmp.delay_us = st->poll_delay_us;
- if ((st->hal->cmode_tbl != NULL) && st->i2c->irq)
- nmp.shutdown_bypass = true;
+ if (ret)
+ return ret;
+
+ akm_init_hw(st);
+ nmp.type = SECONDARY_SLAVE_TYPE_COMPASS;
+ nmp.id = st->hal->mpu_id;
+ nmp.addr = st->i2c_addr; /* write port */
+ nmp.reg = st->hal->reg_mode;
+ nmp.ctrl = 1;
+ nmp.data_out = AKM_MODE_SINGLE;
+ nmp.delay_ms = AKM_HW_DELAY_TSM_MS;
+ nmp.period_us = 0;
+ nmp.shutdown_bypass = false;
+ nmp.handler = NULL;
+ nmp.ext_driver = NULL;
+ ret = nvi_mpu_port_alloc(&nmp);
+ dev_dbg(&st->i2c->dev, "%s MPU port/ret=%d\n",
+ __func__, ret);
+ /* By requesting the write port first it allows us to
+ * automatically determine if the DMP requires a single
+ * port, in which case this port request will fail.
+ * If this part does not support continuous mode
+ * required for single port operation, then this device
+ * population fails.
+ */
+ if (ret < 0) {
+ if (st->hal->cmode_tbl)
+ st->cmode = true;
else
- nmp.shutdown_bypass = false;
- nmp.handler = &akm_mpu_handler;
- nmp.ext_driver = (void *)st;
- memcpy(nmp.matrix, st->cfg.matrix, sizeof(nmp.matrix));
- nmp.type = SECONDARY_SLAVE_TYPE_COMPASS;
- nmp.id = st->hal->mpu_id;
- for (i = 0; i < AXIS_N; i++) {
- q30 = st->asa_q30[i];
- q30 *= st->hal->rr[st->rr_i].resolution.fval;
- if (st->cfg.float_significance)
- do_div(q30,
- NVS_FLOAT_SIGNIFICANCE_NANO);
- else
- do_div(q30,
- NVS_FLOAT_SIGNIFICANCE_MICRO);
- nmp.q30[i] = q30;
- }
- ret = nvi_mpu_port_alloc(&nmp, 0);
- dev_dbg(&st->i2c->dev, "%s MPU port/ret=%d\n",
- __func__, ret);
- if (ret < 0)
return ret;
+ } else {
+ st->port_id[WR] = ret;
+ }
- st->port_id[RD] = ret;
- ret = 0;
- if ((st->hal->cmode_tbl == NULL) || !st->i2c->irq) {
- st->i2c->irq = 0;
- nmp.addr = st->i2c_addr;
- nmp.reg = st->hal->reg_mode;
- nmp.ctrl = 1;
- nmp.dmp_ctrl = nmp.ctrl;
- nmp.data_out = AKM_MODE_SINGLE;
- nmp.delay_ms = AKM_HW_DELAY_TSM_MS;
- nmp.delay_us = 0;
- nmp.shutdown_bypass = false;
- nmp.handler = NULL;
- nmp.ext_driver = NULL;
- nmp.type = SECONDARY_SLAVE_TYPE_COMPASS;
- ret = nvi_mpu_port_alloc(&nmp, 1);
- dev_dbg(&st->i2c->dev, "%s MPU port/ret=%d\n",
- __func__, ret);
- if (ret < 0) {
- akm_ports_free(st);
- return ret;
- }
-
- st->port_id[WR] = ret;
- }
-
- nvi_mpu_fifo(st->port_id[RD],
- &st->cfg.fifo_rsrv_evnt_cnt,
- &st->cfg.fifo_max_evnt_cnt);
- ret = 0;
+ nmp.addr = st->i2c_addr | 0x80; /* read port */
+ nmp.reg = st->hal->reg_start_rd;
+ nmp.ctrl = 10; /* MPU FIFO can't handle odd size */
+ nmp.data_out = 0;
+ nmp.delay_ms = 0;
+ nmp.period_us = st->poll_delay_us;
+ if (st->cmode)
+ nmp.shutdown_bypass = true;
+ nmp.handler = &akm_mpu_handler;
+ nmp.ext_driver = (void *)st;
+ memcpy(nmp.matrix, st->cfg.matrix, sizeof(nmp.matrix));
+ for (i = 0; i < AXIS_N; i++) {
+ q30 = st->asa_q30[i];
+ q30 *= st->hal->rr[st->rr_i].resolution.fval;
+ if (st->cfg.float_significance)
+ do_div(q30,
+ NVS_FLOAT_SIGNIFICANCE_NANO);
+ else
+ do_div(q30,
+ NVS_FLOAT_SIGNIFICANCE_MICRO);
+ nmp.q30[i] = q30;
}
- return ret;
+ ret = nvi_mpu_port_alloc(&nmp);
+ dev_dbg(&st->i2c->dev, "%s MPU port/ret=%d\n",
+ __func__, ret);
+ if (ret < 0) {
+ akm_ports_free(st);
+ return ret;
+ }
+
+ st->port_id[RD] = ret;
+ ret = nvi_mpu_info(st->port_id[RD], &inf);
+ if (ret)
+ return ret;
+
+ st->cfg.fifo_rsrv_evnt_cnt = inf.fifo_reserve;
+ st->cfg.fifo_max_evnt_cnt = inf.fifo_max;
+ st->cfg.delay_us_min = inf.period_us_min;
+ st->cfg.delay_us_max = inf.period_us_max;
+ st->dmp_rd_len_sts = inf.dmp_rd_len_sts;
+ st->dmp_rd_len_data = inf.dmp_rd_len_data;
+ st->dmp_rd_be_sts = inf.dmp_rd_be_sts;
+ st->dmp_rd_be_data = inf.dmp_rd_be_data;
+ return 0;
}
#endif /* AKM_NVI_MPU_SUPPORT */
/* NVI_CONFIG_BOOT_HOST */
/* setup default ptrs even though err */
akm_id_hal(st, 0);
}
- if (!ret)
+ if (!ret) {
akm_init_hw(st);
- if (st->i2c->irq && !ret) {
- if ((st->hal->cmode_tbl == NULL) || !st->hal->irq) {
- nvi_disable_irq(st);
- st->i2c->irq = 0;
- }
+ if (st->i2c->irq && st->hal->cmode_tbl && st->hal->irq)
+ st->cmode = true;
}
return ret;
}
signed char matrix[9];
int ret;
+ dev_info(&client->dev, "%s %s\n", id->name, __func__);
st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL);
if (st == NULL) {
dev_err(&client->dev, "%s devm_kzalloc ERR\n", __func__);
memcpy(st->cfg.matrix, matrix, sizeof(st->cfg.matrix));
if (!st->mpu_en)
INIT_DELAYED_WORK(&st->dw, akm_work);
- if ((st->i2c->irq > 0) && !st->mpu_en) {
- ret = request_threaded_irq(st->i2c->irq, NULL, akm_irq_thread,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- AKM_NAME, st);
- if (ret) {
- dev_err(&client->dev, "%s req_threaded_irq ERR %d\n",
- __func__, ret);
- ret = -ENOMEM;
- goto akm_probe_err;
+ if (st->i2c->irq) {
+ if (st->cmode && !st->mpu_en) {
+ ret = request_threaded_irq(st->i2c->irq, NULL,
+ akm_irq_thread,
+ IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT,
+ AKM_NAME, st);
+ if (ret) {
+ dev_err(&client->dev, "%s req_threaded_irq ERR %d\n",
+ __func__, ret);
+ ret = -ENOMEM;
+ goto akm_probe_err;
+ }
+ } else {
+ akm_disable_irq(st);
}
}
* initialize. No device identification and connect testing is done for
* specific configurations.
*/
-/* A defined interrupt can be used as a SW flag to configure the device if
- * behind the MPU. When an interrupt is defined in struct i2c_client.irq,
- * the driver is configured to only use the device's continuous mode if the
- * device supports it. The interrupt itself is never touched so any value can
- * be used. This frees the MPU auxiliary port used for writes. This
- * configuration would be used if another MPU auxiliary port was needed for
- * another device connected to the MPU. The delay timing used in continuous
- * mode is equal to or the next fastest supported speed.
- */
/* The NVS = NVidia Sensor framework */
/* NVI = NVidia/Invensense */
/* See Nvs.cpp in the HAL for the NVS implementation of batch/flush. */
#include <linux/mpu_iio.h>
#endif /* BMP_NVI_MPU_SUPPORT */
-#define BMP_DRIVER_VERSION (325)
+#define BMP_DRIVER_VERSION (336)
#define BMP_VENDOR "Bosch"
#define BMP_NAME "bmpX80"
#define BMP180_NAME "bmp180"
#define BMP_PRES_MAX_RANGE_MICRO (0)
#define BMP_TEMP_MAX_RANGE_IVAL (125)
#define BMP_TEMP_MAX_RANGE_MICRO (0)
-#define BMP180_RANGE_DFLT (0)
-/* until BMP280 OSS pressure calculation is supported, this defaults to 5 */
-#define BMP280_RANGE_DFLT (5)
#define BMP_HW_DELAY_POR_MS (10)
#define BMP_POLL_DELAY_MS_DFLT (200)
#define BMP_MPU_RETRY_COUNT (50)
#define BMP280_REG_CTRL_MODE_FORCED2 (2)
#define BMP280_REG_CTRL_MODE_NORMAL (3)
#define BMP280_REG_CTRL_OSRS_P (2)
-#define BMP280_REG_CTRL_OSRS_P_MASK (0x1C)
#define BMP280_REG_CTRL_OSRS_T (5)
-#define BMP280_REG_CTRL_OSRS_T_MASK (0xE0)
#define BMP180_REG_OUT_MSB (0xF6)
#define BMP180_REG_OUT_LSB (0xF7)
#define BMP180_REG_OUT_XLSB (0xF8)
#define RD (1)
#define PORT_N (2)
/* _buf_push expects this scan order */
-#define BMP_DEV_PRES (0)
-#define BMP_DEV_TEMP (1)
+#define BMP_DEV_PRS (0)
+#define BMP_DEV_TMP (1)
#define BMP_DEV_N (2)
/* regulator names in order of powering on */
};
struct bmp_scale {
- unsigned long delay_ms;
+ unsigned int delay_ms;
+ u8 os; /* oversampling */
struct nvs_float resolution;
struct nvs_float milliamp;
};
struct bmp_hal_dev {
int version;
- unsigned int scale_i_max;
- unsigned int scale_dflt;
+ unsigned int scale_n;
struct bmp_scale *scale;
struct nvs_float scale_float;
};
unsigned int sts; /* status flags */
unsigned int errs; /* error count */
unsigned int enabled; /* enable status */
+ unsigned int period_us_min; /* minimum period from MPU */
unsigned int poll_delay_us; /* global sampling delay */
unsigned int delay_us[BMP_DEV_N]; /* sampling delay */
unsigned int timeout_us[BMP_DEV_N]; /* batch timeout */
unsigned int scale_i; /* oversampling index */
unsigned int scale_user; /* user oversampling index */
+ unsigned int mpu_bypass_n; /* allow single bypass call */
+ unsigned int dmp_rd_len_sts; /* status length from DMP */
+ unsigned int dmp_rd_len_data; /* data length from DMP */
u16 i2c_addr; /* I2C address */
u8 dev_id; /* device ID */
bool initd; /* set if initialized */
+ bool cmode; /* mode normal (continuous) */
bool mpu_en; /* if device behind MPU */
bool port_en[PORT_N]; /* enable status of MPU write port */
int port_id[PORT_N]; /* MPU port ID */
s32 ut; /* uncompensated temperature */
s32 up; /* uncompensated pressure */
s32 t_fine; /* temperature used in pressure calc */
- s32 temp; /* true temperature */
- int pressure; /* true pressure hPa/100 Pa/1 mBar */
- s64 ts; /* sample data timestamp */
+ s32 tmp; /* true temperature */
+ u32 prs; /* true pressure hPa/100 Pa/1 mBar */
u8 nvi_config; /* NVI configuration */
};
struct bmp_hal {
- struct bmp_hal_dev *p;
- struct bmp_hal_dev *t;
+ struct bmp_hal_dev *dev;
const char *part;
u8 rom_addr_start;
u8 rom_size;
u8 mode_mask;
struct bmp_cmode *cmode_tbl;
int (*bmp_read)(struct bmp_state *st);
+#if BMP_NVI_MPU_SUPPORT
unsigned int mpu_id;
+ u8 port_rd_reg;
+ u8 port_rd_ctrl;
+ void (*port_rd_handler)(u8 *data, unsigned int len,
+ long long timestamp, void *ext_driver);
+#endif /* BMP_NVI_MPU_SUPPORT */
};
int i;
if (st->mpu_en) {
- for (i = 0; i < BMP_MPU_RETRY_COUNT; i++) {
- ret = nvi_mpu_bypass_request(true);
- if ((!ret) || (ret == -EPERM))
- break;
+ if (!st->mpu_bypass_n) {
+ for (i = 0; i < BMP_MPU_RETRY_COUNT; i++) {
+ ret = nvi_mpu_bypass_request(true);
+ if ((!ret) || (ret == -EPERM))
+ break;
- msleep(BMP_MPU_RETRY_DELAY_MS);
+ msleep(BMP_MPU_RETRY_DELAY_MS);
+ }
+
+ if (ret) {
+ if (st->sts & NVS_STS_SPEW_MSG)
+ dev_err(&st->i2c->dev, "%s err=%d\n",
+ __func__, ret);
+ if (ret == -EPERM)
+ ret = 0;
+ } else {
+ st->mpu_bypass_n++;
+ if (st->sts & NVS_STS_SPEW_MSG)
+ dev_info(&st->i2c->dev, "%s\n",
+ __func__);
+ }
+ } else {
+ st->mpu_bypass_n++;
}
- if (ret == -EPERM)
- ret = 0;
}
#endif /* BMP_NVI_MPU_SUPPORT */
return ret;
int ret = 0;
#if BMP_NVI_MPU_SUPPORT
- if (st->mpu_en)
- ret = nvi_mpu_bypass_release();
+ if (st->mpu_en) {
+ if (st->mpu_bypass_n == 1) {
+ ret = nvi_mpu_bypass_release();
+ if (ret) {
+ if (st->sts & NVS_STS_SPEW_MSG)
+ dev_err(&st->i2c->dev, "%s err=%d\n",
+ __func__, ret);
+ } else {
+ st->mpu_bypass_n--;
+ if (st->sts & NVS_STS_SPEW_MSG)
+ dev_info(&st->i2c->dev, "%s\n",
+ __func__);
+ }
+ } else {
+ st->mpu_bypass_n--;
+ }
+ }
#endif /* BMP_NVI_MPU_SUPPORT */
return ret;
}
int ret;
#if BMP_NVI_MPU_SUPPORT
- if (st->mpu_en && !st->i2c->irq) {
+ if (st->mpu_en && !st->cmode) {
ret = nvi_mpu_data_out(st->port_id[WR], mode);
} else {
ret = bmp_nvi_mpu_bypass_request(st);
if (!ret) {
- if (st->i2c->irq) {
+ if (st->cmode) {
ret = bmp_i2c_wr(st, BMP_REG_CTRL,
BMP_REG_CTRL_MODE_SLEEP);
if (mode & st->hal->mode_mask) {
} else {
ret = bmp_i2c_wr(st, BMP_REG_CTRL, mode);
}
+ if (st->sts & NVS_STS_SPEW_MSG)
+ dev_info(&st->i2c->dev, "%s mode=%x err=%d\n",
+ __func__, mode, ret);
bmp_nvi_mpu_bypass_release(st);
}
}
#else /* BMP_NVI_MPU_SUPPORT */
ret = bmp_i2c_wr(st, BMP_REG_CTRL, mode);
+ if (st->sts & NVS_STS_SPEW_MSG)
+ dev_info(&st->i2c->dev, "%s mode=%x err=%d\n",
+ __func__, mode, ret);
#endif /* BMP_NVI_MPU_SUPPORT */
if (!ret)
st->data_out = mode;
if (ret)
mdelay(BMP_HW_DELAY_POR_MS);
} else {
- if (st->i2c->irq) {
+ if (st->cmode) {
ret = nvs_vregs_sts(st->vreg, ARRAY_SIZE(bmp_vregs));
if ((ret < 0) || (ret == ARRAY_SIZE(bmp_vregs))) {
ret = bmp_mode_wr(st, BMP_REG_CTRL_MODE_SLEEP);
return ret;
}
+#if BMP_NVI_MPU_SUPPORT
static int bmp_port_free(struct bmp_state *st, int port)
{
int ret = 0;
-#if BMP_NVI_MPU_SUPPORT
if (st->port_id[port] >= 0) {
ret = nvi_mpu_port_free(st->port_id[port]);
if (!ret)
st->port_id[port] = -1;
}
-#endif /* BMP_NVI_MPU_SUPPORT */
return ret;
}
ret |= bmp_port_free(st, RD);
return ret;
}
+#endif /* BMP_NVI_MPU_SUPPORT */
static void bmp_pm_exit(struct bmp_state *st)
{
+#if BMP_NVI_MPU_SUPPORT
bmp_ports_free(st);
+#endif /* BMP_NVI_MPU_SUPPORT */
bmp_pm(st, false);
nvs_vregs_exit(&st->i2c->dev, st->vreg, ARRAY_SIZE(bmp_vregs));
}
{
int ret;
- st->enabled = 0;
- st->delay_us[BMP_DEV_PRES] = (BMP_POLL_DELAY_MS_DFLT * 1000);
- st->delay_us[BMP_DEV_TEMP] = (BMP_POLL_DELAY_MS_DFLT * 1000);
+ st->delay_us[BMP_DEV_PRS] = (BMP_POLL_DELAY_MS_DFLT * 1000);
+ st->delay_us[BMP_DEV_TMP] = (BMP_POLL_DELAY_MS_DFLT * 1000);
st->poll_delay_us = (BMP_POLL_DELAY_MS_DFLT * 1000);
- st->initd = false;
- st->mpu_en = false;
- st->port_en[WR] = false;
- st->port_en[RD] = false;
st->port_id[WR] = -1;
st->port_id[RD] = -1;
nvs_vregs_init(&st->i2c->dev,
return ret;
}
+#if BMP_NVI_MPU_SUPPORT
static int bmp_ports_enable(struct bmp_state *st, bool enable)
{
int ret = 0;
-#if BMP_NVI_MPU_SUPPORT
unsigned int port_mask = 0;
unsigned int i;
}
}
}
-#endif /* BMP_NVI_MPU_SUPPORT */
-
return ret;
}
+#endif /* BMP_NVI_MPU_SUPPORT */
static int bmp_wr(struct bmp_state *st, u8 reg, u8 val)
{
return ret;
}
-static int bmp_mode(struct bmp_state *st)
+static unsigned int bmp_cmode_t(struct bmp_state *st, u8 *t_sb,
+ unsigned int period_us, unsigned int scale_i)
+{
+ unsigned int us = 0;
+ unsigned int i = 0;
+
+
+ while (st->hal->cmode_tbl[i].t_us) {
+ *t_sb = st->hal->cmode_tbl[i].t_sb;
+ us = st->hal->cmode_tbl[i].t_us;
+ us += st->hal->dev[BMP_DEV_PRS].scale[scale_i].delay_ms * 1000;
+ if (period_us >= us)
+ return us;
+
+ i++;
+ if ((!st->mpu_en) && st->hal->cmode_tbl[i].t_us) {
+ us -= st->hal->cmode_tbl[i].t_us;
+ us >>= 1;
+ us += st->hal->cmode_tbl[i].t_us;
+ us += st->hal->dev[BMP_DEV_PRS].scale[scale_i].
+ delay_ms * 1000;
+ if (period_us > us)
+ return us;
+ }
+ }
+
+ return us;
+}
+
+static int bmp_mode(struct bmp_state *st, unsigned int period_us,
+ unsigned int scale_user, unsigned int enable)
{
u8 mode;
u8 t_sb;
- unsigned int t_us;
unsigned int i;
- int ret;
-
- if (st->dev_id == BMP_REG_ID_BMP180) {
- mode = st->scale_i << BMP180_REG_CTRL_OSS;
- mode |= BMP180_REG_CTRL_MODE_TEMP;
- } else {
- mode = st->scale_i + 1;
- mode = ((mode << BMP280_REG_CTRL_OSRS_T) |
- (mode << BMP280_REG_CTRL_OSRS_P));
- mode |= BMP280_REG_CTRL_MODE_FORCED1;
- }
- if (st->i2c->irq) {
- i = 0;
- t_sb = 0;
- while (st->hal->cmode_tbl[i].t_us) {
- t_sb = st->hal->cmode_tbl[i].t_sb;
- t_us = st->hal->cmode_tbl[i].t_us;
- if (st->poll_delay_us >=
- st->hal->cmode_tbl[i].t_us)
- break;
+ unsigned int scale_i;
+ unsigned int us = 0;
+ int ret = 0;
- i++;
- if (!st->mpu_en) {
- t_us -= st->hal->cmode_tbl[i].t_us;
- t_us >>= 1;
- t_us += st->hal->cmode_tbl[i].t_us;
- if (st->poll_delay_us > t_us)
+ i = BMP_DEV_PRS;
+ if (st->cmode) {
+ if (scale_user) {
+ /* static scale mode */
+ scale_i = scale_user - 1;
+ us = bmp_cmode_t(st, &t_sb, period_us, scale_i);
+ } else {
+ /* auto scale mode - matching scale to the period */
+ scale_i = 0;
+ for (; scale_i < st->hal->dev[i].scale_n; scale_i++) {
+ us = bmp_cmode_t(st, &t_sb,
+ period_us, scale_i);
+ if (period_us >= us)
+ /* HW (us) is fast enough */
break;
}
+
+ if (scale_i >= st->hal->dev[i].scale_n)
+ scale_i = st->hal->dev[i].scale_n - 1;
}
+
+ if (period_us < us)
+ period_us = us;
+ mode = BMP280_REG_CTRL_MODE_NORMAL;
+ mode |= st->hal->dev[BMP_DEV_TMP].scale[scale_i].os <<
+ BMP280_REG_CTRL_OSRS_T;
+ if (enable & (1 << BMP_DEV_PRS))
+ mode |= st->hal->dev[BMP_DEV_PRS].scale[scale_i].os <<
+ BMP280_REG_CTRL_OSRS_P;
+ /* else presure will be disabled */
t_sb <<= BMP280_REG_CONFIG_T_SB;
- bmp_wr(st, BMP280_REG_CONFIG, t_sb);
- mode |= BMP280_REG_CTRL_MODE_NORMAL;
+ ret = bmp_nvi_mpu_bypass_request(st);
+ if (!ret) {
+ ret = bmp_wr(st, BMP280_REG_CONFIG, t_sb);
+ if (ret)
+ mode = BMP_REG_CTRL_MODE_SLEEP;
+ if (st->sts & NVS_STS_SPEW_MSG)
+ dev_info(&st->i2c->dev, "%s cfg=%x err=%d\n",
+ __func__, t_sb, ret);
+ ret |= bmp_mode_wr(st, mode);
+ bmp_nvi_mpu_bypass_release(st);
+ }
+ } else {
+ if (scale_user) {
+ scale_i = scale_user - 1;
+ us = st->hal->dev[i].scale[scale_i].delay_ms * 1000;
+ } else {
+ /* scale is automatic based on period */
+ scale_i = 0;
+ for (; scale_i < st->hal->dev[i].scale_n; scale_i++) {
+ us = st->hal->dev[i].scale[scale_i].delay_ms;
+ us *= 1000;
+ if (period_us >= us)
+ /* HW (us) is fast enough */
+ break;
+ }
+
+ if (scale_i >= st->hal->dev[i].scale_n)
+ scale_i = st->hal->dev[i].scale_n - 1;
+ }
+
+ if (period_us < us)
+ period_us = us;
+#if BMP_NVI_MPU_SUPPORT
+ if (scale_i != st->scale_i && st->mpu_en &&
+ st->port_id[WR] >= 0)
+ ret = nvi_mpu_delay_ms(st->port_id[WR],
+ st->hal->dev[i].scale[scale_i].delay_ms);
+#endif /* BMP_NVI_MPU_SUPPORT */
+ if (st->dev_id == BMP_REG_ID_BMP180) {
+ mode = st->hal->dev[i].scale[scale_i].os <<
+ BMP180_REG_CTRL_OSS;
+ mode |= BMP180_REG_CTRL_MODE_TEMP;
+ } else {
+ mode = BMP280_REG_CTRL_MODE_FORCED1;
+ mode |= st->hal->dev[BMP_DEV_TMP].scale[scale_i].os <<
+ BMP280_REG_CTRL_OSRS_T;
+ if (enable & (1 << BMP_DEV_PRS))
+ mode |= st->hal->dev[i].scale[scale_i].os <<
+ BMP280_REG_CTRL_OSRS_P;
+ }
+ ret |= bmp_mode_wr(st, mode);
+ }
+ if (!ret) {
+ if (period_us != st->poll_delay_us) {
+ if (st->sts & NVS_STS_SPEW_MSG)
+ dev_info(&st->i2c->dev, "%s: period_us=%u\n",
+ __func__, period_us);
+#if BMP_NVI_MPU_SUPPORT
+ if (st->mpu_en) {
+ us = -1;
+ for (i = 0; i < BMP_DEV_N; i++) {
+ if ((enable & (1 << i)) &&
+ st->timeout_us[i] < us)
+ us = st->timeout_us[i];
+ }
+ ret = nvi_mpu_batch(st->port_id[RD],
+ period_us, us);
+ }
+ if (!ret)
+#endif /* BMP_NVI_MPU_SUPPORT */
+ st->poll_delay_us = period_us;
+ }
+ if (!ret)
+ st->scale_i = scale_i;
}
- ret = bmp_mode_wr(st, mode);
return ret;
}
long X1, X2, X3, B3, B5, B6, p;
unsigned long B4, B7;
long pressure;
+ u8 oss = st->hal->dev[BMP_DEV_PRS].scale[st->scale_i].os;
X1 = ((st->ut - st->rom.bmp180.ac6) * st->rom.bmp180.ac5) >> 15;
X2 = st->rom.bmp180.mc * (1 << 11) / (X1 + st->rom.bmp180.md);
B5 = X1 + X2;
- st->temp = (B5 + 8) >> 4;
+ st->tmp = (B5 + 8) >> 4;
B6 = B5 - 4000;
X1 = (st->rom.bmp180.b2 * ((B6 * B6) >> 12)) >> 11;
X2 = (st->rom.bmp180.ac2 * B6) >> 11;
X3 = X1 + X2;
- B3 = ((((st->rom.bmp180.ac1 << 2) + X3) << st->scale_i) + 2) >> 2;
+ B3 = ((((st->rom.bmp180.ac1 << 2) + X3) << oss) + 2) >> 2;
X1 = (st->rom.bmp180.ac3 * B6) >> 13;
X2 = (st->rom.bmp180.b1 * ((B6 * B6) >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
B4 = (st->rom.bmp180.ac4 * (unsigned long)(X3 + 32768)) >> 15;
- B7 = ((unsigned long)st->up - B3) * (50000 >> st->scale_i);
+ B7 = ((unsigned long)st->up - B3) * (50000 >> oss);
if (B7 < 0x80000000)
p = (B7 << 1) / B4;
else
X1 = (X1 * 3038) >> 16;
X2 = (-7357 * p) >> 16;
pressure = p + ((X1 + X2 + 3791) >> 4);
- st->pressure = (int)pressure;
+ st->prs = (int)pressure;
}
static int bmp_read_sts_180(struct bmp_state *st, u8 *data, s64 ts)
{
+ u8 oss;
s32 val;
int ret = 0;
/* BMP180_REG_CTRL_SCO is 0 when data is ready */
if (!(data[0] & (1 << BMP180_REG_CTRL_SCO))) {
+ oss = st->hal->dev[BMP_DEV_PRS].scale[st->scale_i].os;
ret = -1;
if (data[0] == 0x0A) { /* temperature */
st->ut = ((data[2] << 8) + data[3]);
st->data_out = BMP180_REG_CTRL_MODE_PRES |
- (st->scale_i << BMP180_REG_CTRL_OSS);
+ (oss << BMP180_REG_CTRL_OSS);
} else { /* pressure */
- val = ((data[2] << 16) + (data[3] << 8) +
- data[4]) >> (8 - st->scale_i);
+ val = ((data[2] << 16) + (data[3] << 8) + data[4]);
+ val >>= (8 - oss);
st->data_out = BMP180_REG_CTRL_MODE_TEMP;
st->up = val;
bmp_calc_180(st);
- st->ts = ts;
ret = 1;
}
}
ts = nvs_timestamp();
ret = bmp_read_sts_180(st, data, ts);
if (ret > 0) {
- if (st->nvs_st[BMP_DEV_PRES])
- st->nvs->handler(st->nvs_st[BMP_DEV_PRES],
- &st->pressure, ts);
- if (st->nvs_st[BMP_DEV_TEMP])
- st->nvs->handler(st->nvs_st[BMP_DEV_TEMP],
- &st->temp, ts);
+ if (st->enabled & (1 << BMP_DEV_PRS))
+ st->nvs->handler(st->nvs_st[BMP_DEV_PRS],
+ &st->prs, ts);
+ if (st->enabled & (1 << BMP_DEV_TMP))
+ /* nvs handles on-change sensor timing & same values */
+ st->nvs->handler(st->nvs_st[BMP_DEV_TMP],
+ &st->tmp, ts);
bmp_i2c_wr(st, BMP_REG_CTRL, st->data_out);
} else if (ret < 0) {
bmp_i2c_wr(st, BMP_REG_CTRL, st->data_out);
static void bmp_calc_temp_280(struct bmp_state *st)
{
- s32 adc_t;
s32 var1;
s32 var2;
- adc_t = st->ut;
- adc_t >>= (4 - st->scale_i);
- var1 = adc_t >> 3;
- var1 -= ((s32)st->rom.bmp280.dig_T1 << 1);
- var1 *= (s32)st->rom.bmp280.dig_T2;
+ var1 = st->ut;
+ var1 >>= 3;
+ var2 = st->rom.bmp280.dig_T1;
+ var2 <<= 1;
+ var1 -= var2;
+ var1 *= st->rom.bmp280.dig_T2;
var1 >>= 11;
- var2 = adc_t >> 4;
+ var2 = st->ut;
+ var2 >>= 4;
var2 -= (s32)st->rom.bmp280.dig_T1;
var2 *= var2;
var2 >>= 12;
- var2 *= (s32)st->rom.bmp280.dig_T3;
+ var2 *= st->rom.bmp280.dig_T3;
var2 >>= 14;
st->t_fine = var1 + var2;
- st->temp = (st->t_fine * 5 + 128) >> 8;
+ st->tmp = (st->t_fine * 5 + 128) >> 8;
}
static int bmp_calc_pres_280(struct bmp_state *st)
{
- s32 adc_p;
- s32 var1;
- s32 var2;
- s32 var3;
- u32 p;
-
- adc_p = st->up;
- var1 = st->t_fine >> 1;
- var1 -= 64000;
- var2 = var1 >> 2;
- var2 *= var2;
- var3 = var2;
- var2 >>= 11;
+ s64 var1;
+ s64 var2;
+ s64 var3;
+ s64 p;
+
+ var1 = st->t_fine;
+ var1 -= 128000;
+ var2 = var1 * var1;
var2 *= st->rom.bmp280.dig_P6;
- var2 += ((var1 * st->rom.bmp280.dig_P5) << 1);
- var2 >>= 2;
- var2 += (st->rom.bmp280.dig_P4 << 16);
- var3 >>= 13;
- var3 *= st->rom.bmp280.dig_P3;
- var3 >>= 3;
- var1 *= st->rom.bmp280.dig_P2;
- var1 >>= 1;
+ var3 = st->rom.bmp280.dig_P5;
+ var3 *= var1;
+ var3 <<= 17;
+ var2 += var3;
+ var3 = st->rom.bmp280.dig_P4;
+ var3 <<= 35;
+ var2 += var3;
+ var3 = var1;
+ var3 *= st->rom.bmp280.dig_P2;
+ var3 <<= 12;
+ var1 *= var1;
+ var1 *= st->rom.bmp280.dig_P3;
+ var1 >>= 8;
+ var1 += var3;
+ var3 = 1;
+ var3 <<= 47;
var1 += var3;
- var1 >>= 18;
- var1 += 32768;
var1 *= st->rom.bmp280.dig_P1;
- var1 >>= 15;
+ var1 >>= 33;
if (!var1)
return -1;
- p = ((u32)(((s32)1048576) - adc_p) - (var2 >> 12)) * 3125;
- if (p < 0x80000000)
- p = (p << 1) / ((u32)var1);
- else
- p = (p / (u32)var1) << 1;
- var3 = p >> 3;
- var3 *= var3;
- var3 >>= 13;
- var1 = (s32)st->rom.bmp280.dig_P9 * var3;
- var1 >>= 12;
- var2 = (s32)(p >> 2);
- var2 *= (s32)st->rom.bmp280.dig_P8;
- var2 >>= 13;
- var3 = var1 + var2 + st->rom.bmp280.dig_P7;
- var3 >>= 4;
- p = (u32)((s32)p + var3);
- st->pressure = (int)p;
+ p = 1048576 - st->up;
+ p <<= 31;
+ p -= var2;
+ p *= 3125;
+ p = div64_s64(p, var1);
+ var1 = p;
+ var1 >>= 13;
+ var1 *= var1;
+ var1 *= st->rom.bmp280.dig_P9;
+ var1 >>= 25;
+ var2 = st->rom.bmp280.dig_P8;
+ var2 *= p;
+ var2 >>= 19;
+ var3 = st->rom.bmp280.dig_P7;
+ var3 <<= 4;
+ p += var1;
+ p += var2;
+ p >>= 8;
+ p += var3;
+ p >>= 8;
+ st->prs = (u32)p;
return 1;
}
val >>= 4;
st->ut = val;
bmp_calc_temp_280(st);
- ret = bmp_calc_pres_280(st);
- if (ret > 0) {
- st->ts = ts;
- if (st->nvs_st[BMP_DEV_PRES])
- st->nvs->handler(st->nvs_st[BMP_DEV_PRES],
- &st->pressure, ts);
- if (st->nvs_st[BMP_DEV_TEMP])
- st->nvs->handler(st->nvs_st[BMP_DEV_TEMP],
- &st->temp, ts);
+ if (st->enabled & (1 << BMP_DEV_PRS)) {
+ ret = bmp_calc_pres_280(st);
+ if (ret > 0)
+ st->nvs->handler(st->nvs_st[BMP_DEV_PRS],
+ &st->prs, ts);
+ } else {
+ ret = 1;
}
+ if (st->enabled & (1 << BMP_DEV_TMP))
+ /* nvs handles on-change sensor timing & same values */
+ st->nvs->handler(st->nvs_st[BMP_DEV_TMP], &st->tmp, ts);
return ret;
}
}
if (st->enabled) {
- if (len == 6) {
+ if (len == st->dmp_rd_len_sts)
+ /* status data from the DMP not supported */
+ return;
+
+ if (len == st->dmp_rd_len_data) {
/* this data is from the DMP */
i = 0;
ret = 1;
return;
}
- if (st->enabled) {
- ret = bmp_read_sts_180(st, data, ts);
- if (ret > 0) {
- if (st->nvs_st[BMP_DEV_PRES])
- st->nvs->handler(st->nvs_st[BMP_DEV_PRES],
- &st->pressure, ts);
- if (st->nvs_st[BMP_DEV_TEMP])
- st->nvs->handler(st->nvs_st[BMP_DEV_TEMP],
- &st->temp, ts);
- nvi_mpu_data_out(st->port_id[WR], st->data_out);
- } else if (ret < 0) {
- nvi_mpu_data_out(st->port_id[WR], st->data_out);
- }
+ ret = bmp_read_sts_180(st, data, ts);
+ if (ret > 0) {
+ if (st->enabled & (1 << BMP_DEV_PRS))
+ st->nvs->handler(st->nvs_st[BMP_DEV_PRS],
+ &st->prs, ts);
+ if (st->enabled & (1 << BMP_DEV_TMP))
+ /* nvs handles on-change sensor timing & same values */
+ st->nvs->handler(st->nvs_st[BMP_DEV_TMP],
+ &st->tmp, ts);
+ nvi_mpu_data_out(st->port_id[WR], st->data_out);
+ } else if (ret < 0) {
+ nvi_mpu_data_out(st->port_id[WR], st->data_out);
}
}
#endif /* BMP_NVI_MPU_SUPPORT */
st->nvs->nvs_mutex_unlock(st->nvs_st[i]);
}
-static unsigned int bmp_poll_delay(struct bmp_state *st)
+static unsigned int bmp_poll_delay(struct bmp_state *st, unsigned int en_msk)
{
unsigned int i;
unsigned int delay_us = -1;
+ bool valid = false;
for (i = 0; i < BMP_DEV_N; i++) {
- if (st->enabled & (1 << i)) {
- if (st->delay_us[i] < delay_us)
+ if (en_msk & (1 << i)) {
+ if (st->delay_us[i] && st->delay_us[i] < delay_us) {
delay_us = st->delay_us[i];
+ valid = true;
+ }
}
}
- if (delay_us == -1)
+ if (!valid)
delay_us = (BMP_POLL_DELAY_MS_DFLT * 1000);
return delay_us;
}
-static int bmp_delay(struct bmp_state *st,
- unsigned int delay_us, int scale_user)
-{
- unsigned int timeout;
- unsigned int i;
- int ret;
- int ret_t = 0;
-
- if (scale_user) {
- i = scale_user - 1;
- } else {
- for (i = (st->hal->p->scale_i_max - 1); i > 0; i--) {
- if (delay_us >= (st->hal->p->scale[i].delay_ms * 1000))
- break;
- }
- }
- if (i != st->scale_i) {
- ret = 0;
-#if BMP_NVI_MPU_SUPPORT
- if (st->mpu_en)
- ret = nvi_mpu_delay_ms(st->port_id[WR],
- st->hal->p->scale[i].delay_ms);
-#endif /* BMP_NVI_MPU_SUPPORT */
- if (ret < 0)
- ret_t |= ret;
- else
- st->scale_i = i;
- }
- if (delay_us < (st->hal->p->scale[st->scale_i].delay_ms * 1000))
- delay_us = (st->hal->p->scale[st->scale_i].delay_ms * 1000);
- if (delay_us != st->poll_delay_us) {
- if (st->sts & NVS_STS_SPEW_MSG)
- dev_info(&st->i2c->dev, "%s: %u\n",
- __func__, delay_us);
-#if BMP_NVI_MPU_SUPPORT
- ret = 0;
- if (st->mpu_en) {
- timeout = -1;
- for (i = 0; i < BMP_DEV_N; i++) {
- if (st->enabled & (1 << i)) {
- if (st->timeout_us[i] < timeout)
- timeout = st->timeout_us[i];
- }
- }
- ret = nvi_mpu_batch(st->port_id[RD],
- delay_us, timeout);
- }
- if (ret)
- ret_t |= ret;
- else
-#endif /* BMP_NVI_MPU_SUPPORT */
- st->poll_delay_us = delay_us;
- }
- return ret_t;
-}
-
static int bmp_init_hw(struct bmp_state *st)
{
u8 *p_rom8;
st->ut = 0;
st->up = 0;
- st->temp = 0;
- st->pressure = 0;
+ st->tmp = 0;
+ st->prs = 0;
p_rom8 = (u8 *)&st->rom;
ret = bmp_nvi_mpu_bypass_request(st);
if (!ret) {
static int bmp_dis(struct bmp_state *st)
{
+#if BMP_NVI_MPU_SUPPORT
int ret = 0;
if (st->mpu_en)
if (!ret)
st->enabled = 0;
return ret;
+#else /* BMP_NVI_MPU_SUPPORT */
+ cancel_delayed_work(&st->dw);
+ st->enabled = 0;
+ return 0;
+#endif /* BMP_NVI_MPU_SUPPORT */
}
static int bmp_disable(struct bmp_state *st, int snsr_id)
enable = st->enabled | (1 << snsr_id);
ret = bmp_en(st);
if (!ret) {
- ret |= bmp_delay(st, bmp_poll_delay(st),
- st->scale_user);
- ret |= bmp_mode(st);
+ ret = bmp_mode(st, bmp_poll_delay(st, enable),
+ st->scale_user, enable);
+#if BMP_NVI_MPU_SUPPORT
if (st->mpu_en)
ret |= bmp_ports_enable(st, true);
+#endif /* BMP_NVI_MPU_SUPPORT */
if (ret) {
bmp_disable(st, snsr_id);
} else {
unsigned int period, unsigned int timeout)
{
struct bmp_state *st = (struct bmp_state *)client;
+ int ret = 0;
unsigned int old_period;
unsigned int old_timeout;
- int ret;
if (timeout && !st->mpu_en)
/* timeout not supported (no HW FIFO) */
old_timeout = st->timeout_us[snsr_id];
st->delay_us[snsr_id] = period;
st->timeout_us[snsr_id] = timeout;
- ret = bmp_delay(st, bmp_poll_delay(st), st->scale_user);
- if (st->enabled && st->i2c->irq && !ret)
- ret = bmp_mode(st);
- if (ret) {
- st->delay_us[snsr_id] = old_period;
- st->timeout_us[snsr_id] = old_timeout;
+ if (st->enabled) {
+ ret = bmp_mode(st, bmp_poll_delay(st, st->enabled),
+ st->scale_user, st->enabled);
+ if (ret) {
+ st->delay_us[snsr_id] = old_period;
+ st->timeout_us[snsr_id] = old_timeout;
+ }
}
- return 0;
+ return ret;
}
static int bmp_flush(void *client, int snsr_id)
if (st->mpu_en)
ret = nvi_mpu_flush(st->port_id[RD]);
#endif /* BMP_NVI_MPU_SUPPORT */
+
return ret;
}
static int bmp_resolution(void *client, int snsr_id, int resolution)
{
struct bmp_state *st = (struct bmp_state *)client;
+ unsigned int us;
+ unsigned int i;
int ret;
- if (snsr_id != BMP_DEV_PRES)
+ if (snsr_id != BMP_DEV_PRS)
return -EINVAL;
- if (resolution < 0 || resolution > st->hal->p->scale_i_max)
- return -EINVAL;
+ if (resolution < 0)
+ resolution = 0;
+ if (resolution > st->hal->dev[BMP_DEV_PRS].scale_n)
+ resolution = st->hal->dev[BMP_DEV_PRS].scale_n;
+ if (st->enabled) {
+ ret = bmp_mode(st, st->poll_delay_us, resolution, st->enabled);
+ if (ret)
+ return ret;
+ } else {
+ if (resolution)
+ st->scale_i = resolution - 1;
+ else
+ st->scale_i = 0;
+ }
- ret = bmp_delay(st, st->poll_delay_us, resolution);
- if (!ret) {
- st->scale_user = resolution;
- if (st->enabled && st->i2c->irq)
- ret = bmp_mode(st);
+ st->scale_user = resolution;
+ for (i = 0; i < BMP_DEV_N; i++) {
+ st->cfg[i].resolution.ival =
+ st->hal->dev[i].scale[st->scale_i].resolution.ival;
+ st->cfg[i].resolution.fval =
+ st->hal->dev[i].scale[st->scale_i].resolution.fval;
+ st->cfg[i].milliamp.ival =
+ st->hal->dev[i].scale[st->scale_i].milliamp.ival;
+ st->cfg[i].milliamp.fval =
+ st->hal->dev[i].scale[st->scale_i].milliamp.fval;
+ us = st->hal->dev[i].scale[st->scale_i].delay_ms * 1000;
+ if (us < st->period_us_min)
+ us = st->period_us_min;
+ st->cfg[i].delay_us_min = us;
}
- if (ret)
- return ret;
- st->cfg[BMP_DEV_PRES].resolution.ival =
- st->hal->p->scale[st->scale_i].resolution.ival;
- st->cfg[BMP_DEV_PRES].resolution.fval =
- st->hal->p->scale[st->scale_i].resolution.fval;
- st->cfg[BMP_DEV_PRES].milliamp.ival =
- st->hal->p->scale[st->scale_i].milliamp.ival;
- st->cfg[BMP_DEV_PRES].milliamp.fval =
- st->hal->p->scale[st->scale_i].milliamp.fval;
- st->cfg[BMP_DEV_PRES].delay_us_min =
- st->hal->p->scale[st->scale_i].delay_ms * 1000;
- st->cfg[BMP_DEV_TEMP].resolution.ival =
- st->hal->t->scale[st->scale_i].resolution.ival;
- st->cfg[BMP_DEV_TEMP].resolution.fval =
- st->hal->t->scale[st->scale_i].resolution.fval;
- st->cfg[BMP_DEV_TEMP].milliamp.ival =
- st->hal->t->scale[st->scale_i].milliamp.ival;
- st->cfg[BMP_DEV_TEMP].milliamp.fval =
- st->hal->t->scale[st->scale_i].milliamp.fval;
- st->cfg[BMP_DEV_TEMP].delay_us_min =
- st->hal->t->scale[st->scale_i].delay_ms * 1000;
return 0;
}
int ret;
if (!st->initd) {
- t = sprintf(buf, "calibration: NEED ENABLE\n");
+ t = snprintf(buf, PAGE_SIZE, "calibration: NEED ENABLE\n");
} else {
- t = sprintf(buf, "calibration:\n");
+ t = snprintf(buf, PAGE_SIZE, "calibration:\n");
cal = &st->rom.bmp280.dig_T1;
for (i = 0; i < st->hal->rom_size; i = i + 2)
- t += sprintf(buf + t, "%#2x=%#2x\n",
- st->hal->rom_addr_start + i,
- *cal++);
+ t += snprintf(buf + t, PAGE_SIZE - t, "%#2x=%#2x\n",
+ st->hal->rom_addr_start + i, *cal++);
}
ret = bmp_nvi_mpu_bypass_request(st);
if (!ret) {
bmp_nvi_mpu_bypass_release(st);
}
if (ret) {
- t += sprintf(buf + t, "registers: ERR %d\n", ret);
+ t += snprintf(buf + t, PAGE_SIZE - t,
+ "registers: ERR %d\n", ret);
} else {
- t += sprintf(buf + t, "registers:\n");
- t += sprintf(buf + t, "%#2x=%#2x\n",
- BMP_REG_ID, data[0]);
+ t += snprintf(buf + t, PAGE_SIZE - t, "registers:\n");
+ t += snprintf(buf + t, PAGE_SIZE - t, "%#2x=%#2x\n",
+ BMP_REG_ID, data[0]);
for (i = 0; i < 10; i++)
- t += sprintf(buf + t, "%#2x=%#2x\n",
- BMP280_REG_STATUS + i,
- data[i + 1]);
+ t += snprintf(buf + t, PAGE_SIZE - t, "%#2x=%#2x\n",
+ BMP280_REG_STATUS + i, data[i + 1]);
}
return t;
}
struct bmp_state *st = (struct bmp_state *)client;
ssize_t t;
- t = sprintf(buf, "driver v.%u\n", BMP_DRIVER_VERSION);
- t += sprintf(buf + t, "mpu_en=%x\n", st->mpu_en);
- t += sprintf(buf + t, "nvi_config=%hhu\n", st->nvi_config);
+ t = snprintf(buf, PAGE_SIZE, "driver v.%u\n", BMP_DRIVER_VERSION);
+ t += snprintf(buf + t, PAGE_SIZE - t, "mpu_en=%x\n", st->mpu_en);
+ t += snprintf(buf + t, PAGE_SIZE - t, "nvi_config=%hhu\n",
+ st->nvi_config);
+ t += snprintf(buf + t, PAGE_SIZE - t, "cmode_enable=%x\n", st->cmode);
+ if (!st->scale_user)
+ t += snprintf(buf + t, PAGE_SIZE - t, "scale_user=auto\n");
+ t += snprintf(buf + t, PAGE_SIZE - t, "scale_i=%x\n", st->scale_i);
return t;
}
struct sensor_cfg bmp_cfg_dflt[] = {
{
.name = "pressure",
- .snsr_id = BMP_DEV_PRES,
+ .snsr_id = BMP_DEV_PRS,
.kbuf_sz = BMP_KBUF_SIZE,
.ch_n = 1,
.ch_sz = -4,
.ival = BMP_PRES_MAX_RANGE_IVAL,
.fval = BMP_PRES_MAX_RANGE_MICRO,
},
- .delay_us_min = 10000,
- .delay_us_max = 255000,
},
{
.name = "ambient_temperature",
- .snsr_id = BMP_DEV_TEMP,
+ .snsr_id = BMP_DEV_TMP,
.ch_n = 1,
.ch_sz = -4,
.part = BMP_NAME,
.ival = BMP_TEMP_MAX_RANGE_IVAL,
.fval = BMP_TEMP_MAX_RANGE_MICRO,
},
- .delay_us_min = 10000,
- .delay_us_max = 255000,
.flags = SENSOR_FLAG_ON_CHANGE_MODE,
},
};
-static struct bmp_scale bmp_scale_pres_180[] = {
+static struct bmp_scale bmp_scale_prs_180[] = {
{
- .delay_ms = 5,
+ .delay_ms = 26,
+ .os = 0x03,
.resolution = {
.ival = 0,
.fval = 10000,
},
.milliamp = {
.ival = 0,
- .fval = 3000,
+ .fval = 12000,
},
},
{
- .delay_ms = 8,
+ .delay_ms = 14,
+ .os = 0x02,
.resolution = {
.ival = 0,
.fval = 10000,
},
.milliamp = {
.ival = 0,
- .fval = 5000,
+ .fval = 7000,
},
},
{
- .delay_ms = 14,
+ .delay_ms = 8,
+ .os = 0x01,
.resolution = {
.ival = 0,
.fval = 10000,
},
.milliamp = {
.ival = 0,
- .fval = 7000,
+ .fval = 5000,
},
},
{
- .delay_ms = 26,
+ .delay_ms = 5,
+ .os = 0x00,
.resolution = {
.ival = 0,
.fval = 10000,
},
.milliamp = {
.ival = 0,
- .fval = 12000,
+ .fval = 3000,
},
},
};
-static struct bmp_scale bmp_scale_temp_180[] = {
+static struct bmp_scale bmp_scale_tmp_180[] = {
{
- .delay_ms = 5,
+ .delay_ms = 26,
.resolution = {
.ival = 0,
.fval = 100000,
},
.milliamp = {
.ival = 0,
- .fval = 3000,
+ .fval = 12000,
},
},
{
- .delay_ms = 8,
+ .delay_ms = 14,
.resolution = {
.ival = 0,
.fval = 100000,
},
.milliamp = {
.ival = 0,
- .fval = 5000,
+ .fval = 7000,
},
},
{
- .delay_ms = 14,
+ .delay_ms = 8,
.resolution = {
.ival = 0,
.fval = 100000,
},
.milliamp = {
.ival = 0,
- .fval = 7000,
+ .fval = 5000,
},
},
{
- .delay_ms = 26,
+ .delay_ms = 5,
.resolution = {
.ival = 0,
.fval = 100000,
},
.milliamp = {
.ival = 0,
- .fval = 12000,
+ .fval = 3000,
},
},
};
-static struct bmp_hal_dev bmp_hal_dev_pres_180 = {
- .version = 1,
- .scale_i_max = ARRAY_SIZE(bmp_scale_pres_180),
- .scale_dflt = BMP180_RANGE_DFLT,
- .scale = bmp_scale_pres_180,
- .scale_float = {
- .ival = 0,
- .fval = 10000,
- }
-};
-
-static struct bmp_hal_dev bmp_hal_dev_temp_180 = {
- .version = 1,
- .scale_i_max = ARRAY_SIZE(bmp_scale_temp_180),
- .scale_dflt = BMP180_RANGE_DFLT,
- .scale = bmp_scale_temp_180,
- .scale_float = {
- .ival = 0,
- .fval = 100000,
- }
+static struct bmp_hal_dev bmp_hal_dev_180[] = {
+ {
+ .version = 1,
+ .scale_n = ARRAY_SIZE(bmp_scale_prs_180),
+ .scale = bmp_scale_prs_180,
+ .scale_float = {
+ .ival = 0,
+ .fval = 10000,
+ },
+ },
+ {
+ .version = 1,
+ .scale_n = ARRAY_SIZE(bmp_scale_tmp_180),
+ .scale = bmp_scale_tmp_180,
+ .scale_float = {
+ .ival = 0,
+ .fval = 100000,
+ }
+ },
};
static struct bmp_hal bmp_hal_180 = {
- .p = &bmp_hal_dev_pres_180,
- .t = &bmp_hal_dev_temp_180,
+ .dev = bmp_hal_dev_180,
.part = BMP180_NAME,
.rom_addr_start = BMP180_REG_AC1,
.rom_size = 22,
.mode_mask = BMP180_REG_CTRL_MODE_MASK,
.cmode_tbl = NULL,
.bmp_read = &bmp_read_180,
+#if BMP_NVI_MPU_SUPPORT
+ .mpu_id = 0,
+ .port_rd_reg = BMP_REG_CTRL,
+ .port_rd_ctrl = 6,
+ .port_rd_handler = &bmp_mpu_handler_180,
+#endif /* BMP_NVI_MPU_SUPPORT */
};
-static struct bmp_scale bmp_scale_pres_280[] = {
+static struct bmp_scale bmp_scale_prs_280[] = {
{
- .delay_ms = 9,
+ .delay_ms = 44,
+ .os = 0x05,
.resolution = {
.ival = 0,
- .fval = 28700,
+ .fval = 1800,
},
.milliamp = {
.ival = 0,
- .fval = 2740,
+ .fval = 24800,
},
},
{
- .delay_ms = 12,
+ .delay_ms = 23,
+ .os = 0x04,
.resolution = {
.ival = 0,
- .fval = 14300,
+ .fval = 3600,
},
.milliamp = {
.ival = 0,
- .fval = 4170,
+ .fval = 12700,
},
},
{
- .delay_ms = 18,
+ .delay_ms = 14,
+ .os = 0x03,
.resolution = {
.ival = 0,
.fval = 7200,
},
},
{
- .delay_ms = 30,
+ .delay_ms = 9,
+ .os = 0x02,
.resolution = {
.ival = 0,
- .fval = 3600,
+ .fval = 14300,
},
.milliamp = {
.ival = 0,
- .fval = 12700,
+ .fval = 4170,
},
},
{
- .delay_ms = 57,
+ .delay_ms = 7,
+ .os = 0x01,
.resolution = {
.ival = 0,
- .fval = 1800,
+ .fval = 28700,
},
.milliamp = {
.ival = 0,
- .fval = 24800,
+ .fval = 2740,
},
},
};
-static struct bmp_scale bmp_scale_temp_280[] = {
+static struct bmp_scale bmp_scale_tmp_280[] = {
+ /* os oversampling is useless > 2x and only used for pressure @ 16x */
{
- .delay_ms = 9,
+ .delay_ms = 44,
+ .os = 0x02,
.resolution = {
.ival = 0,
- .fval = 5000,
+ .fval = 300,
},
.milliamp = {
.ival = 0,
- .fval = 2740,
+ .fval = 24800,
},
},
{
- .delay_ms = 12,
+ .delay_ms = 23,
+ .os = 0x01,
.resolution = {
.ival = 0,
- .fval = 2500,
+ .fval = 600,
},
.milliamp = {
.ival = 0,
- .fval = 4170,
+ .fval = 12700,
},
},
{
- .delay_ms = 18,
+ .delay_ms = 14,
+ .os = 0x01,
.resolution = {
.ival = 0,
.fval = 1200,
},
},
{
- .delay_ms = 30,
+ .delay_ms = 9,
+ .os = 0x01,
.resolution = {
.ival = 0,
- .fval = 600,
+ .fval = 2500,
},
.milliamp = {
.ival = 0,
- .fval = 12700,
+ .fval = 4170,
},
},
{
- .delay_ms = 57,
+ .delay_ms = 7,
+ .os = 0x01,
.resolution = {
.ival = 0,
- .fval = 300,
+ .fval = 5000,
},
.milliamp = {
.ival = 0,
- .fval = 24800,
+ .fval = 2740,
},
},
};
-static struct bmp_hal_dev bmp_hal_dev_pres_280 = {
- .version = 1,
- .scale_i_max = ARRAY_SIZE(bmp_scale_pres_280),
- .scale_dflt = BMP280_RANGE_DFLT,
- .scale = bmp_scale_pres_280,
- .scale_float = {
- .ival = 0,
- .fval = 10000,
- }
-};
-
-static struct bmp_hal_dev bmp_hal_dev_temp_280 = {
- .version = 1,
- .scale_i_max = ARRAY_SIZE(bmp_scale_temp_280),
- .scale_dflt = BMP280_RANGE_DFLT,
- .scale = bmp_scale_temp_280,
- .scale_float = {
- .ival = 0,
- .fval = 10000,
- }
+static struct bmp_hal_dev bmp_hal_dev_280[] = {
+ {
+ .version = 1,
+ .scale_n = ARRAY_SIZE(bmp_scale_prs_280),
+ .scale = bmp_scale_prs_280,
+ .scale_float = {
+ .ival = 0,
+ .fval = 10000,
+ }
+ },
+ {
+ .version = 1,
+ .scale_n = ARRAY_SIZE(bmp_scale_tmp_280),
+ .scale = bmp_scale_tmp_280,
+ .scale_float = {
+ .ival = 0,
+ .fval = 10000,
+ },
+ },
};
static struct bmp_cmode bmp_cmode_280[] = {
};
static struct bmp_hal bmp_hal_280 = {
- .p = &bmp_hal_dev_pres_280,
- .t = &bmp_hal_dev_temp_280,
+ .dev = bmp_hal_dev_280,
.part = BMP280_NAME,
.rom_addr_start = BMP280_REG_CWORD00,
.rom_size = 26,
.bmp_read = &bmp_read_280,
#if BMP_NVI_MPU_SUPPORT
.mpu_id = PRESSURE_ID_BMP280,
+ .port_rd_reg = BMP280_REG_STATUS,
+ .port_rd_ctrl = 10,
+ .port_rd_handler = &bmp_mpu_handler_280,
#endif /* BMP_NVI_MPU_SUPPORT */
};
break;
}
- st->scale_user = st->hal->p->scale_dflt;
+ /* default scale to fastest and least power usage */
+ st->scale_user = st->hal->dev[BMP_DEV_PRS].scale_n;
+ st->scale_i = st->scale_user - 1;
+ if (st->hal->cmode_tbl == NULL)
+ st->cmode = false;
for (i = 0; i < BMP_DEV_N; i++)
memcpy(&st->cfg[i], &bmp_cfg_dflt[i],
sizeof(struct sensor_cfg));
- st->cfg[BMP_DEV_PRES].part = st->hal->part;
- st->cfg[BMP_DEV_PRES].version = st->hal->p->version;
- st->cfg[BMP_DEV_PRES].resolution.ival =
- st->hal->p->scale[st->scale_i].resolution.ival;
- st->cfg[BMP_DEV_PRES].resolution.fval =
- st->hal->p->scale[st->scale_i].resolution.fval;
- st->cfg[BMP_DEV_PRES].milliamp.ival =
- st->hal->p->scale[st->scale_i].milliamp.ival;
- st->cfg[BMP_DEV_PRES].milliamp.fval =
- st->hal->p->scale[st->scale_i].milliamp.fval;
- st->cfg[BMP_DEV_PRES].delay_us_min =
- st->hal->p->scale[st->scale_i].delay_ms * 1000;
- st->cfg[BMP_DEV_PRES].scale.ival = st->hal->p->scale_float.ival;
- st->cfg[BMP_DEV_PRES].scale.fval = st->hal->p->scale_float.fval;
- st->cfg[BMP_DEV_TEMP].part = st->hal->part;
- st->cfg[BMP_DEV_TEMP].version = st->hal->t->version;
- st->cfg[BMP_DEV_TEMP].resolution.ival =
- st->hal->t->scale[st->scale_i].resolution.ival;
- st->cfg[BMP_DEV_TEMP].resolution.fval =
- st->hal->t->scale[st->scale_i].resolution.fval;
- st->cfg[BMP_DEV_TEMP].milliamp.ival =
- st->hal->t->scale[st->scale_i].milliamp.ival;
- st->cfg[BMP_DEV_TEMP].milliamp.fval =
- st->hal->t->scale[st->scale_i].milliamp.fval;
- st->cfg[BMP_DEV_TEMP].delay_us_min =
- st->hal->t->scale[st->scale_i].delay_ms * 1000;
- st->cfg[BMP_DEV_TEMP].scale.ival = st->hal->t->scale_float.ival;
- st->cfg[BMP_DEV_TEMP].scale.fval = st->hal->t->scale_float.fval;
+ for (i = 0; i < BMP_DEV_N; i++) {
+ st->cfg[i].part = st->hal->part;
+ st->cfg[i].version = st->hal->dev[i].version;
+ st->cfg[i].scale.ival = st->hal->dev[i].scale_float.ival;
+ st->cfg[i].scale.fval = st->hal->dev[i].scale_float.fval;
+ }
return ret;
}
{
#if BMP_NVI_MPU_SUPPORT
struct nvi_mpu_port nmp;
+ struct nvi_mpu_inf inf;
+ unsigned int i;
u8 config_boot;
#endif /* BMP_NVI_MPU_SUPPORT */
u8 val = 0;
if (config_boot == NVI_CONFIG_BOOT_MPU) {
st->mpu_en = true;
bmp_id_hal(st);
- if (st->hal->cmode_tbl == NULL || !st->i2c->irq) {
- nmp.addr = st->i2c_addr;
- nmp.reg = BMP_REG_CTRL;
- nmp.ctrl = 1;
- nmp.data_out = st->data_out;
- nmp.delay_ms = st->hal->p->scale[st->scale_i].delay_ms;
- nmp.delay_us = 0;
- nmp.shutdown_bypass = false;
- nmp.handler = NULL;
- nmp.ext_driver = NULL;
- ret = nvi_mpu_port_alloc(&nmp, 2);
- dev_dbg(&st->i2c->dev, "%s MPU port/ret=%d\n",
- __func__, ret);
- if (ret < 0)
+ nmp.type = SECONDARY_SLAVE_TYPE_PRESSURE;
+ nmp.id = st->hal->mpu_id;
+ nmp.addr = st->i2c_addr; /* write port */
+ nmp.reg = BMP_REG_CTRL;
+ nmp.ctrl = 1;
+ nmp.data_out = st->data_out;
+ nmp.delay_ms = st->hal->dev[BMP_DEV_PRS].
+ scale[st->scale_i].delay_ms;
+ nmp.period_us = 0;
+ nmp.shutdown_bypass = false;
+ nmp.handler = NULL;
+ nmp.ext_driver = NULL;
+ ret = nvi_mpu_port_alloc(&nmp);
+ dev_dbg(&st->i2c->dev, "%s MPU port/ret=%d\n",
+ __func__, ret);
+ /* By requesting the write port first it allows us to
+ * automatically determine if the DMP requires a single
+ * port, in which case this port request will fail.
+ * If this part does not support continuous mode
+ * required for single port operation, then this device
+ * population fails.
+ */
+ if (ret < 0) {
+ if (st->hal->cmode_tbl)
+ st->cmode = true;
+ else
return ret;
-
+ } else {
+ st->cmode = false;
st->port_id[WR] = ret;
}
- nmp.addr = st->i2c_addr | 0x80;
+
+ nmp.addr = st->i2c_addr | 0x80; /* read port */
nmp.data_out = 0;
nmp.delay_ms = 0;
- nmp.delay_us = st->poll_delay_us;
- if ((st->hal->cmode_tbl != NULL) && st->i2c->irq)
+ nmp.period_us = st->poll_delay_us;
+ if (st->cmode)
nmp.shutdown_bypass = true;
- else
- nmp.shutdown_bypass = false;
nmp.ext_driver = (void *)st;
- if (st->dev_id == BMP_REG_ID_BMP180) {
- nmp.reg = BMP_REG_CTRL;
- nmp.ctrl = 6; /* MPU FIFO can't handle odd size */
- nmp.handler = &bmp_mpu_handler_180;
- } else {
- nmp.reg = BMP280_REG_STATUS;
- nmp.ctrl = 10; /* MPU FIFO can't handle odd size */
- nmp.handler = &bmp_mpu_handler_280;
- }
- nmp.type = SECONDARY_SLAVE_TYPE_PRESSURE;
- nmp.id = st->hal->mpu_id;
- ret = nvi_mpu_port_alloc(&nmp, 3);
+ nmp.reg = st->hal->port_rd_reg;
+ nmp.ctrl = st->hal->port_rd_ctrl;
+ nmp.handler = st->hal->port_rd_handler;
+ ret = nvi_mpu_port_alloc(&nmp);
dev_dbg(&st->i2c->dev, "%s MPU port/ret=%d\n",
__func__, ret);
if (ret < 0) {
}
st->port_id[RD] = ret;
- nvi_mpu_fifo(st->port_id[RD],
- &st->cfg[BMP_DEV_PRES].fifo_rsrv_evnt_cnt,
- &st->cfg[BMP_DEV_PRES].fifo_max_evnt_cnt);
- st->cfg[BMP_DEV_TEMP].fifo_rsrv_evnt_cnt =
- st->cfg[BMP_DEV_PRES].fifo_rsrv_evnt_cnt;
- st->cfg[BMP_DEV_TEMP].fifo_max_evnt_cnt =
- st->cfg[BMP_DEV_PRES].fifo_max_evnt_cnt;
+ ret = nvi_mpu_info(st->port_id[RD], &inf);
+ if (ret)
+ return ret;
+
+ st->period_us_min = inf.period_us_min;
+ for (i = 0; i < BMP_DEV_N; i++) {
+ st->cfg[i].fifo_rsrv_evnt_cnt = inf.fifo_reserve;
+ st->cfg[i].fifo_max_evnt_cnt = inf.fifo_max;
+ st->cfg[i].delay_us_max = inf.period_us_max;
+ }
+ st->dmp_rd_len_sts = inf.dmp_rd_len_sts;
+ st->dmp_rd_len_data = inf.dmp_rd_len_data;
return 0;
}
#endif /* BMP_NVI_MPU_SUPPORT */
return -ENODEV;
/* this device supports these programmable parameters */
- if (!(of_property_read_string(dn, "nvi_config", &pchar))) {
+ if (!of_property_read_string(dn, "nvi_config", &pchar)) {
for (cfg = 0; cfg < ARRAY_SIZE(bmp_configs); cfg++) {
if (!strcasecmp(pchar, bmp_configs[cfg])) {
st->nvi_config = cfg;
}
}
}
- }
+ if (!of_property_read_u8(dn, "cmode_enable", &cfg)) {
+ if (cfg)
+ st->cmode = true;
+ else
+ st->cmode = false;
+ }
+ }
return 0;
}
{
struct bmp_state *st;
unsigned int i;
+ unsigned int n;
int ret;
dev_info(&client->dev, "%s %s\n", id->name, __func__);
bmp_pm_init(st);
ret = bmp_id_i2c(st, id);
if (ret == -EAGAIN)
- goto bmp_probe_again;
+ goto bmp_probe_exit;
else if (ret)
goto bmp_probe_err;
goto bmp_probe_err;
}
+ st->cfg[BMP_DEV_PRS].resolution.ival = st->scale_user;
+ nvs_of_dt(client->dev.of_node, &st->cfg[BMP_DEV_PRS], NULL);
+ bmp_resolution(st, BMP_DEV_PRS, st->cfg[BMP_DEV_PRS].resolution.ival);
+ nvs_of_dt(client->dev.of_node, &st->cfg[BMP_DEV_TMP], NULL);
+ if (st->cfg[BMP_DEV_PRS].snsr_id < 0)
+ /* pressure disabled so use temperature settings */
+ bmp_resolution(st, BMP_DEV_PRS,
+ st->cfg[BMP_DEV_TMP].resolution.ival);
+ n = 0;
for (i = 0; i < BMP_DEV_N; i++) {
- nvs_of_dt(client->dev.of_node, &st->cfg[i], NULL);
- ret |= st->nvs->probe(&st->nvs_st[i], st, &client->dev,
- &bmp_fn_dev, &st->cfg[i]);
+ ret = st->nvs->probe(&st->nvs_st[i], st, &client->dev,
+ &bmp_fn_dev, &st->cfg[i]);
+ if (!ret)
+ n++;
}
- if (ret) {
- dev_err(&client->dev, "%s nvs_probe ERR\n", __func__);
+ if (!n) {
ret = -ENODEV;
- goto bmp_probe_err;
+ goto bmp_probe_exit;
}
if (!st->mpu_en)
INIT_DELAYED_WORK(&st->dw, bmp_work);
-
dev_info(&client->dev, "%s done\n", __func__);
return 0;
bmp_probe_err:
dev_err(&client->dev, "%s ERR %d\n", __func__, ret);
-bmp_probe_again:
+bmp_probe_exit:
bmp_remove(client);
return ret;
}
* 3:0. If the port is to do write transactions then this
* value must be 1. See MPU documentation for the other
* bits in I2C_SLVx_CTRL that can be applied by this byte.
- * - dmp_ctrl: When the DMP in enabled, the number of
- * consecutive registers to read in 3:0. If the port is to
- * do write transactions then this value must be 1. See
- * MPU documentation for the other bits in I2C_SLVx_CTRL
- * that can be applied by this byte.
* - data_out: The data byte written if the port is configured
* to do writes (addr 7:7 = 0).
* - delay_ms: The polling delay time between I2C transactions
* in ms. Note that the MPU HW only supports one delay
* time so the longest delay of all the MPU ports enabled
* is used.
- * - delay_us: The delay at which the read data is reported.
+ * - period_us: The period at which the read data is reported.
* - shutdown_bypass: set if a connection to the host is needed
* when the system is shutdown. The MPU API will be
* disabled as part of its shutdown but it will enable the
u8 addr;
u8 reg;
u8 ctrl;
- u8 dmp_ctrl;
u8 data_out;
unsigned int delay_ms;
- unsigned long delay_us;
+ unsigned int period_us;
bool shutdown_bypass;
void (*handler)(u8 *data, unsigned int len,
long long timestamp, void *ext_driver);
u64 q30[3];
};
+struct nvi_mpu_inf {
+ unsigned int period_us_min;
+ unsigned int period_us_max;
+ unsigned int fifo_reserve;
+ unsigned int fifo_max;
+ unsigned int dmp_rd_len_sts; /* status length from DMP */
+ unsigned int dmp_rd_len_data; /* data length from DMP */
+ bool dmp_rd_be_sts; /* status endian from DMP */
+ bool dmp_rd_be_data; /* data endian from DMP */
+};
+
/**
* Expected use of the nvi_mpu_ routines are as follows:
* - nvi_mpu_dev_valid: Use to validate whether a device is
* - ext_driver: this pointer is passed in handler for
* use by external driver. This should be NULL
* if the port is configured for writes.
- * @param port: request a specific port (0 to 3).
- * If port is -1 then the returned port ID will be
- * automatically selected.
- * Requesting a specific port is used when the device
- * is expected to work with the Invensense DMP, since
- * the DMP FW is pathetically designed and has strict
- * limitations of how it will work with auxiliary
- * devices.
* @return int error/port ID
* if return >= 0 then this is the port ID. The ID
* will have a value of 0 to 3 (HW has 4 ports).
* freed.
* - -EINVAL: Problem with input parameters.
*/
-int nvi_mpu_port_alloc(struct nvi_mpu_port *nmp, int port);
+int nvi_mpu_port_alloc(struct nvi_mpu_port *nmp);
/**
* Remove a port.
int nvi_mpu_flush(int port);
/**
- * batch fifo.
- * @param port
- * @param reserve
- * @param max
+ * nvi_mpu_info. MPU/ICM populates the nvi_mpu_inf structure
+ * pointed to by inf.
+ * @param port used for reading
+ * @param ptr to nvi_mpu_inf structure.
* @return int error
* Possible errors are:
* - -EAGAIN: MPU is not initialized yet.
* - -EBUSY: MPU is busy with another request.
* - -EINVAL: Problem with input parameters.
*/
-int nvi_mpu_fifo(int port, unsigned int *reserve, unsigned int *max);
+int nvi_mpu_info(int read_port, struct nvi_mpu_inf *inf);
/**
* Enable/disable the MPU bypass mode. When enabled, the MPU