iio: imu: nvi v.336 Add DMP AUX support
Erik Lilliebjerg [Mon, 18 Jul 2016 04:48:59 +0000 (21:48 -0700)]
- Add DMP support for devices on the auxiliary ports behind the MPU/ICM.  Due
  to the differences between the MPU and ICM DMPs, the auxiliary port API was
  extended that allowed the DMP dependencies to be removed from the auxiliary
  device's external drivers.
- Updated the pressure calculations for the BMP280 driver to the latest BMP280
  specification.

Bug 200191681
Bug 200201316
Bug 200195822

Change-Id: Id4338b11094f8ef00df214c14649b7bc951a6891
Signed-off-by: Erik Lilliebjerg <elilliebjerg@nvidia.com>
Reviewed-on: http://git-master/r/1185055
GVS: Gerrit_Virtual_Submit
Tested-by: Robert Collins <rcollins@nvidia.com>
Reviewed-by: Akhilesh Khumbum <akhumbum@nvidia.com>
Reviewed-by: Robert Collins <rcollins@nvidia.com>

drivers/iio/common/nvs/nvs_iio.c
drivers/iio/imu/nvi_mpu/nvi.c
drivers/iio/imu/nvi_mpu/nvi.h
drivers/iio/imu/nvi_mpu/nvi_dmp_icm.c
drivers/iio/imu/nvi_mpu/nvi_dmp_mpu.c
drivers/iio/imu/nvi_mpu/nvi_icm.c
drivers/iio/magnetometer/nvi_ak89xx.c
drivers/iio/pressure/nvi_bmpX80.c
include/linux/mpu_iio.h

index f179aeb..8042c0b 100644 (file)
  * 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>
@@ -76,7 +82,7 @@
 #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,
@@ -169,6 +175,9 @@ struct nvs_state {
        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;
@@ -442,6 +451,18 @@ static int nvs_fn_dev_enable(void *client, int snsr_id, int enable)
        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;
@@ -519,6 +540,8 @@ static int nvs_buf_i(struct iio_dev *indio_dev, unsigned int ch)
 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;
@@ -533,25 +556,54 @@ static int nvs_buf_push(struct iio_dev *indio_dev, unsigned char *data, s64 ts)
         * 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))
@@ -563,22 +615,23 @@ static int nvs_buf_push(struct iio_dev *indio_dev, unsigned char *data, s64 ts)
                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) {
@@ -621,19 +674,38 @@ static int nvs_enable(struct iio_dev *indio_dev, bool en)
                } 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)
@@ -1124,19 +1196,18 @@ static int nvs_write_raw(struct iio_dev *indio_dev,
                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 >
@@ -1153,6 +1224,8 @@ static int nvs_write_raw(struct iio_dev *indio_dev,
                } else {
                        if (st->batch_timeout_us)
                                ret = -EINVAL;
+                       else
+                               st->batch_period_us = val;
                }
                break;
 
@@ -1327,7 +1400,6 @@ static int nvs_write_raw(struct iio_dev *indio_dev,
                        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;
@@ -1504,8 +1576,7 @@ static int nvs_chan(struct iio_dev *indio_dev)
        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) |
@@ -1679,6 +1750,7 @@ static int nvs_init(struct iio_dev *indio_dev, struct nvs_state *st)
 {
        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);
@@ -1755,6 +1827,9 @@ static int nvs_probe(void **handle, void *dev_client, struct device *dev,
        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)
index 30cb11a..7a4aad0 100644 (file)
@@ -29,7 +29,7 @@
 
 #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"
@@ -869,6 +869,13 @@ static int nvi_user_ctrl_rst(struct nvi_state *st, u8 user_ctrl)
                                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
@@ -949,11 +956,9 @@ int nvi_user_ctrl_en(struct nvi_state *st, const char *fn,
                        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]);
-                               }
                        }
                }
 
@@ -1633,8 +1638,9 @@ static void nvi_aux_dbg(struct nvi_state *st, char *tag, int val)
                        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);
        }
 
@@ -1703,12 +1709,13 @@ static int nvi_aux_port_en(struct nvi_state *st, int port, bool en)
 {
        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;
@@ -1721,25 +1728,33 @@ static int nvi_aux_port_en(struct nvi_state *st, int port, bool en)
                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);
        }
@@ -1851,30 +1866,62 @@ static int nvi_aux_port_free(struct nvi_state *st, int port)
 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)
@@ -2082,7 +2129,7 @@ int nvi_mpu_dev_valid(struct nvi_mpu_port *nmp, u8 *data)
 }
 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;
@@ -2098,13 +2145,13 @@ int nvi_mpu_port_alloc(struct nvi_mpu_port *nmp, int port)
        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);
@@ -2150,10 +2197,10 @@ int nvi_mpu_enable(unsigned int port_mask, bool enable)
 
        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;
        }
@@ -2306,39 +2353,51 @@ int nvi_mpu_flush(int port)
 }
 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)
 {
@@ -2553,8 +2612,7 @@ static void nvi_aux_rd(struct nvi_state *st)
        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);
index f81be14..cd67554 100644 (file)
@@ -332,6 +332,53 @@ struct nvi_mc {
        };
 };
 
+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;
@@ -345,6 +392,8 @@ struct nvi_dmp {
        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);
@@ -398,34 +447,6 @@ struct nvi_snsr {
        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.
@@ -471,6 +492,7 @@ struct nvi_state {
        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;
index 90647ed..75f730a 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #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;
@@ -212,15 +290,6 @@ static int nvi_dmp_acc_initd(struct nvi_state *st, u32 *out_ctl,
 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)) ||
@@ -329,18 +398,6 @@ static int nvi_dmp_gmf_initd(struct nvi_state *st, u32 *out_ctl,
        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)
 {
@@ -482,8 +539,8 @@ static struct nvi_dmp_dev nvi_dmp_devs[] = {
        },
        {
                .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,
@@ -494,13 +551,23 @@ static struct nvi_dmp_dev nvi_dmp_devs[] = {
        },
        {
                .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,
        },
 };
 
@@ -518,7 +585,7 @@ static struct nvi_dmp_hdr nvi_dmp_hdr2s[] = {
        },
        {
                .dev                    = DEV_AUX,
-               .aux_port               = AUX_PORT_DEV_GMF,
+               .aux_port               = DMP_AUX_PORT_0,
                .data_n                 = 2,
                .hdr_msk                = CPASS_ACCURACY_SET,
        },
@@ -547,13 +614,13 @@ static struct nvi_dmp_hdr nvi_dmp_hdr1s[] = {
        },
        {
                .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,
        },
@@ -574,7 +641,7 @@ static struct nvi_dmp_hdr nvi_dmp_hdr1s[] = {
        },
        {
                .dev                    = DEV_AUX,
-               .aux_port               = AUX_PORT_DEV_PRS,
+               .aux_port               = DMP_AUX_PORT_3,
                .data_n                 = 6,
                .hdr_msk                = PRESSURE_SET,
        },
@@ -631,9 +698,6 @@ static void nvi_dmp_rd_aux(struct nvi_state *st, struct nvi_dmp_hdr *dh,
                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);
@@ -737,6 +801,7 @@ static int nvi_dmp_rd(struct nvi_state *st, s64 ts, unsigned int n)
                                        "%s ERR: DMP sync HDR2=%hx\n",
                                        __func__, hdr2);
                        nvi_err(st);
+                       st->icm_fifo_off = true;
                        return -1;
                }
 
@@ -761,6 +826,7 @@ static int nvi_dmp_rd(struct nvi_state *st, s64 ts, unsigned int n)
                                        "%s ERR: DMP sync HDR1: %x\n",
                                        __func__, hdr1);
                        nvi_err(st);
+                       st->icm_fifo_off = true;
                        return -1;
                }
        }
@@ -855,7 +921,12 @@ static int nvi_dmp_period(struct nvi_state *st, u32 *out_ctl,
         * 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.
         */
@@ -872,6 +943,9 @@ static int nvi_dmp_period(struct nvi_state *st, u32 *out_ctl,
                }
 
                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;
        }
@@ -914,6 +988,10 @@ static int nvi_dmp_period(struct nvi_state *st, u32 *out_ctl,
                        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;
@@ -937,8 +1015,13 @@ static int nvi_dmp_period(struct nvi_state *st, u32 *out_ctl,
                }
                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 {
@@ -1051,8 +1134,8 @@ static int nvi_dmp_init_gmf(struct nvi_state *st)
        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;
@@ -1104,6 +1187,45 @@ static int nvi_dmp_init_gyr(struct nvi_state *st)
        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;
@@ -1123,6 +1245,8 @@ static int nvi_dmp_init(struct nvi_state *st)
 
        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;
 }
 
@@ -1149,6 +1273,10 @@ static int nvi_dd_able(struct nvi_state *st,
 
                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) {
@@ -1171,8 +1299,10 @@ static int nvi_dd_able(struct nvi_state *st,
                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));
@@ -1251,6 +1381,10 @@ static int nvi_dmp_en(struct nvi_state *st)
        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));
@@ -1279,6 +1413,7 @@ static int nvi_dmp_en(struct nvi_state *st)
        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);
@@ -4029,6 +4164,8 @@ struct nvi_dmp nvi_dmp_icm = {
        .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,
index ba18cde..61bf2f1 100644 (file)
 #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;
@@ -50,27 +128,6 @@ struct nvi_dmp_hdr {
 };
 
 
-/* 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;
@@ -114,7 +171,7 @@ static struct nvi_dmp_dev nvi_dmp_devs[] = {
                .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) |
@@ -156,7 +213,6 @@ static struct nvi_dmp_dev nvi_dmp_devs[] = {
                .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 },
@@ -169,7 +225,6 @@ static struct nvi_dmp_dev nvi_dmp_devs[] = {
                .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 },
@@ -245,15 +300,60 @@ static struct nvi_dmp_hdr nvi_dmp_hdrs[] = {
        },
 };
 
-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;
 
@@ -273,7 +373,7 @@ static int nvi_dmp_rd(struct nvi_state *st, s64 ts, unsigned int n)
                }
                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],
@@ -285,25 +385,11 @@ static int nvi_dmp_rd(struct nvi_state *st, s64 ts, unsigned int n)
                }
 
                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;
@@ -470,7 +556,7 @@ static u8 nvi_dmp_fcfg_gyro_b[8][3] = {
        { 0x36, 0x57, 0x76 },
        { 0x37, 0x57, 0x76 },
        { 0x37, 0x56, 0x76 },
-       { 0x37, 0x57, 0x77 },
+       { 0x37, 0x56, 0x77 },
        { 0x37, 0x56, 0x77 },
        { 0x36, 0x57, 0x77 },
        { 0x36, 0x56, 0x77 },
@@ -950,6 +1036,8 @@ struct nvi_dmp nvi_dmp_mpu = {
        .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,
index eb2c4a5..dc6e3c5 100644 (file)
@@ -737,8 +737,10 @@ static int nvi_src_aux(struct nvi_state *st)
                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;
 }
 
index 9eed90a..9a1c27b 100644 (file)
  * 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.
@@ -69,7 +63,7 @@
 #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"
@@ -159,9 +153,14 @@ struct akm_state {
        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 */
@@ -192,7 +191,9 @@ struct akm_hal {
        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 */
 };
 
 
@@ -281,12 +282,12 @@ static int akm_mode_wr(struct akm_state *st, u8 mode)
        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) {
@@ -302,7 +303,7 @@ static int akm_mode_wr(struct akm_state *st, u8 mode)
                }
        }
 #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) {
@@ -330,7 +331,7 @@ static int akm_pm(struct akm_state *st, bool enable)
                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);
@@ -468,7 +469,7 @@ static int akm_mode(struct akm_state *st)
        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;
@@ -583,7 +584,7 @@ static void akm_mpu_handler(u8 *data, unsigned int len, s64 ts, void *p_val)
        unsigned int i;
        int ret;
 
-       if (ts < 0)
+       if (ts < 0 || !len)
                /* error - just drop */
                return;
 
@@ -594,15 +595,18 @@ static void akm_mpu_handler(u8 *data, unsigned int len, s64 ts, void *p_val)
        }
 
        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 {
@@ -741,7 +745,7 @@ static int akm_init_hw(struct akm_state *st)
        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);
@@ -749,7 +753,7 @@ static void nvi_disable_irq(struct akm_state *st)
        }
 }
 
-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);
@@ -764,8 +768,8 @@ static int akm_dis(struct akm_state *st)
        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);
        }
@@ -813,8 +817,8 @@ static int akm_enable(void *client, int snsr_id, int enable)
                        } 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(
@@ -842,7 +846,7 @@ static int akm_batch(void *client, int snsr_id, int flags,
        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;
 }
@@ -1016,6 +1020,7 @@ static int akm_nvs_read(void *client, int snsr_id, char *buf)
                      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;
 }
 
@@ -1389,6 +1394,7 @@ static int akm_id_dev(struct akm_state *st, const char *name)
 {
 #if AKM_NVI_MPU_SUPPORT
        struct nvi_mpu_port nmp;
+       struct nvi_mpu_inf inf;
        unsigned int i;
        u64 q30;
        u8 config_boot;
@@ -1396,8 +1402,6 @@ static int akm_id_dev(struct akm_state *st, const char *name)
        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))
@@ -1426,73 +1430,84 @@ static int akm_id_dev(struct akm_state *st, const char *name)
                        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 */
@@ -1509,13 +1524,10 @@ static int akm_id_dev(struct akm_state *st, const char *name)
                        /* 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;
 }
@@ -1596,6 +1608,7 @@ static int akm_probe(struct i2c_client *client,
        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__);
@@ -1658,15 +1671,21 @@ static int akm_probe(struct i2c_client *client,
                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);
                }
        }
 
index 6b61cc8..8bf7f7e 100644 (file)
  * 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. */
@@ -60,7 +51,7 @@
 #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"
@@ -70,9 +61,6 @@
 #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)
@@ -95,9 +83,7 @@
 #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 */
@@ -173,15 +159,15 @@ static unsigned short bmp_i2c_addrs[] = {
 };
 
 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;
 };
@@ -234,14 +220,19 @@ struct bmp_state {
        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 */
@@ -249,15 +240,13 @@ struct bmp_state {
        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;
@@ -265,7 +254,13 @@ struct bmp_hal {
        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 */
 };
 
 
@@ -324,15 +319,30 @@ static int bmp_nvi_mpu_bypass_request(struct bmp_state *st)
        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;
@@ -343,8 +353,23 @@ static int bmp_nvi_mpu_bypass_release(struct bmp_state *st)
        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;
 }
@@ -354,12 +379,12 @@ static int bmp_mode_wr(struct bmp_state *st, u8 mode)
        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) {
@@ -370,11 +395,17 @@ static int bmp_mode_wr(struct bmp_state *st, u8 mode)
                        } 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;
@@ -391,7 +422,7 @@ static int bmp_pm(struct bmp_state *st, bool enable)
                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);
@@ -418,17 +449,16 @@ static int bmp_pm(struct bmp_state *st, bool enable)
        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;
 }
 
@@ -440,10 +470,13 @@ static int bmp_ports_free(struct bmp_state *st)
        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));
 }
@@ -452,14 +485,9 @@ static int bmp_pm_init(struct bmp_state *st)
 {
        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,
@@ -468,10 +496,10 @@ static int bmp_pm_init(struct bmp_state *st)
        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;
 
@@ -490,10 +518,9 @@ static int bmp_ports_enable(struct bmp_state *st, bool enable)
                        }
                }
        }
-#endif /* BMP_NVI_MPU_SUPPORT */
-
        return ret;
 }
+#endif /* BMP_NVI_MPU_SUPPORT */
 
 static int bmp_wr(struct bmp_state *st, u8 reg, u8 val)
 {
@@ -507,47 +534,151 @@ 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;
 }
 
@@ -556,21 +687,22 @@ static void bmp_calc_180(struct bmp_state *st)
        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
@@ -579,28 +711,29 @@ static void bmp_calc_180(struct bmp_state *st)
        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;
                }
        }
@@ -620,12 +753,13 @@ static int bmp_read_180(struct bmp_state *st)
        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);
@@ -635,75 +769,81 @@ static int bmp_read_180(struct bmp_state *st)
 
 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;
 }
 
@@ -721,16 +861,17 @@ static int bmp_push_280(struct bmp_state *st, u8 *data, s64 ts)
        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;
 }
 
@@ -784,7 +925,11 @@ static void bmp_mpu_handler_280(u8 *data, unsigned int len, s64 ts, void *p_val)
        }
 
        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;
@@ -816,19 +961,18 @@ static void bmp_mpu_handler_180(u8 *data, unsigned int len, s64 ts, void *p_val)
                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 */
@@ -850,78 +994,25 @@ static void bmp_work(struct work_struct *ws)
                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;
@@ -931,8 +1022,8 @@ static int bmp_init_hw(struct bmp_state *st)
 
        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) {
@@ -957,6 +1048,7 @@ static int bmp_init_hw(struct bmp_state *st)
 
 static int bmp_dis(struct bmp_state *st)
 {
+#if BMP_NVI_MPU_SUPPORT
        int ret = 0;
 
        if (st->mpu_en)
@@ -966,6 +1058,11 @@ static int bmp_dis(struct bmp_state *st)
        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)
@@ -1009,11 +1106,12 @@ static int bmp_enable(void *client, int snsr_id, int enable)
                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 {
@@ -1034,9 +1132,9 @@ static int bmp_batch(void *client, int snsr_id, int flags,
                     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) */
@@ -1046,14 +1144,15 @@ static int bmp_batch(void *client, int snsr_id, int flags,
        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)
@@ -1065,49 +1164,51 @@ 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;
 }
 
@@ -1138,14 +1239,13 @@ static int bmp_regs(void *client, int snsr_id, char *buf)
        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) {
@@ -1155,15 +1255,15 @@ static int bmp_regs(void *client, int snsr_id, char *buf)
                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;
 }
@@ -1173,9 +1273,14 @@ static int bmp_nvs_read(void *client, int snsr_id, char *buf)
        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;
 }
 
@@ -1267,7 +1372,7 @@ static int bmp_remove(struct i2c_client *client)
 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,
@@ -1278,12 +1383,10 @@ struct sensor_cfg bmp_cfg_dflt[] = {
                        .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,
@@ -1293,131 +1396,131 @@ struct sensor_cfg bmp_cfg_dflt[] = {
                        .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,
@@ -1425,33 +1528,42 @@ static struct bmp_hal bmp_hal_180 = {
        .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,
@@ -1462,54 +1574,60 @@ static struct bmp_scale bmp_scale_pres_280[] = {
                },
        },
        {
-               .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,
@@ -1520,49 +1638,50 @@ static struct bmp_scale bmp_scale_temp_280[] = {
                },
        },
        {
-               .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[] = {
@@ -1602,8 +1721,7 @@ 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,
@@ -1613,6 +1731,9 @@ static struct bmp_hal bmp_hal_280 = {
        .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 */
 };
 
@@ -1637,38 +1758,20 @@ static int bmp_id_hal(struct bmp_state *st)
                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;
 }
 
@@ -1705,6 +1808,8 @@ static int bmp_id_dev(struct bmp_state *st, const char *name)
 {
 #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;
@@ -1740,45 +1845,49 @@ static int bmp_id_dev(struct bmp_state *st, const char *name)
        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) {
@@ -1789,13 +1898,18 @@ static int bmp_id_dev(struct bmp_state *st, const char *name)
                }
 
                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 */
@@ -1852,7 +1966,7 @@ static int bmp_of_dt(struct bmp_state *st, struct device_node *dn)
                        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;
@@ -1860,8 +1974,14 @@ static int bmp_of_dt(struct bmp_state *st, struct device_node *dn)
                                }
                        }
                }
-       }
 
+               if (!of_property_read_u8(dn, "cmode_enable", &cfg)) {
+                       if (cfg)
+                               st->cmode = true;
+                       else
+                               st->cmode = false;
+               }
+       }
        return 0;
 }
 
@@ -1870,6 +1990,7 @@ static int bmp_probe(struct i2c_client *client,
 {
        struct bmp_state *st;
        unsigned int i;
+       unsigned int n;
        int ret;
 
        dev_info(&client->dev, "%s %s\n", id->name, __func__);
@@ -1895,7 +2016,7 @@ static int bmp_probe(struct i2c_client *client,
        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;
 
@@ -1909,26 +2030,34 @@ static int bmp_probe(struct i2c_client *client,
                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;
 }
index 7307ca7..203a8bf 100644 (file)
@@ -149,18 +149,13 @@ struct mpu_platform_data {
  *      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
@@ -190,10 +185,9 @@ struct nvi_mpu_port {
        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);
@@ -204,6 +198,17 @@ struct nvi_mpu_port {
        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
@@ -281,14 +286,6 @@ int nvi_mpu_dev_valid(struct nvi_mpu_port *nmp, u8 *data);
  *           - 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).
@@ -302,7 +299,7 @@ int nvi_mpu_dev_valid(struct nvi_mpu_port *nmp, u8 *data);
  *                 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.
@@ -396,10 +393,10 @@ int nvi_mpu_batch(int port, unsigned int period_us, unsigned int timeout_us);
 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.
@@ -408,7 +405,7 @@ int nvi_mpu_flush(int port);
  *            - -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