summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/input/misc/Kconfig1
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/compass/ak8975_input.c1619
-rw-r--r--drivers/input/misc/mpu/inv_gyro.c4210
-rw-r--r--drivers/input/misc/mpu/inv_gyro.h272
-rw-r--r--drivers/input/misc/mpu/inv_gyro_misc.c129
-rw-r--r--drivers/input/misc/mpu/inv_mpu3050.c756
-rw-r--r--drivers/input/misc/pressure/Kconfig12
-rw-r--r--drivers/input/misc/pressure/Makefile7
-rw-r--r--drivers/input/misc/pressure/bmp180.c1080
-rw-r--r--include/linux/mpu.h298
11 files changed, 5621 insertions, 2764 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 85844a2ce7d7..c2a302983440 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -645,5 +645,6 @@ config INPUT_CAPELLA_CM3218
source "drivers/input/misc/compass/Kconfig"
source "drivers/input/misc/mpu/Kconfig"
+source "drivers/input/misc/pressure/Kconfig"
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index b1086162e95f..a4e6d7d636e3 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -63,3 +63,4 @@ obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-y += compass/
obj-y += mpu/
+obj-y += pressure/
diff --git a/drivers/input/misc/compass/ak8975_input.c b/drivers/input/misc/compass/ak8975_input.c
index 29754bc25046..e89455434d73 100644
--- a/drivers/input/misc/compass/ak8975_input.c
+++ b/drivers/input/misc/compass/ak8975_input.c
@@ -1,670 +1,1215 @@
-/*
-* Copyright (C) 2012 Invensense, Inc.
-*
-* This software is licensed under the terms of the GNU General Public
-* License version 2, as published by the Free Software Foundation, and
-* may be copied, distributed, and modified under those terms.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-*/
-
-/**
- * @addtogroup DRIVERS
- * @brief Hardware drivers.
+/* Copyright (C) 2012 Invensense, Inc.
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
- * @{
- * @file ak8975_input.c
- * @brief A sysfs device driver for Invensense devices
- * @details This driver currently works for the AK8975
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#include <linux/i2c.h>
+#include <linux/input.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
+#include <linux/miscdevice.h>
#include <linux/slab.h>
-#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/input.h>
#include <linux/workqueue.h>
-
+#include <linux/regulator/consumer.h>
#include <linux/mpu.h>
-#define AK8975_DEBUG_IF 0
-#define AK8975_DEBUG_DATA 0
-
-#define AK8975_I2C_NAME "ak8975"
-
-#define SENSOR_DATA_SIZE 8
-#define YPR_DATA_SIZE 12
-#define RWBUF_SIZE 16
-
-#define ACC_DATA_FLAG 0
-#define MAG_DATA_FLAG 1
-#define ORI_DATA_FLAG 2
-#define AKM_NUM_SENSORS 3
-
-#define ACC_DATA_READY (1 << (ACC_DATA_FLAG))
-#define MAG_DATA_READY (1 << (MAG_DATA_FLAG))
-#define ORI_DATA_READY (1 << (ORI_DATA_FLAG))
-
-/*! \name AK8975 constant definition
- \anchor AK8975_Def
- Constant definitions of the AK8975.*/
-#define AK8975_MEASUREMENT_TIME_US 10000
-
-/*! \name AK8975 operation mode
- \anchor AK8975_Mode
- Defines an operation mode of the AK8975.*/
-/*! @{*/
-#define AK8975_CNTL_MODE_SNG_MEASURE 0x01
-#define AK8975_CNTL_MODE_SELF_TEST 0x08
-#define AK8975_CNTL_MODE_FUSE_ACCESS 0x0F
-#define AK8975_CNTL_MODE_POWER_DOWN 0x00
-/*! @}*/
-
-/*! \name AK8975 register address
-\anchor AK8975_REG
-Defines a register address of the AK8975.*/
-/*! @{*/
-#define AK8975_REG_WIA 0x00
-#define AK8975_REG_INFO 0x01
-#define AK8975_REG_ST1 0x02
-#define AK8975_REG_HXL 0x03
-#define AK8975_REG_HXH 0x04
-#define AK8975_REG_HYL 0x05
-#define AK8975_REG_HYH 0x06
-#define AK8975_REG_HZL 0x07
-#define AK8975_REG_HZH 0x08
-#define AK8975_REG_ST2 0x09
-#define AK8975_REG_CNTL 0x0A
-#define AK8975_REG_RSV 0x0B
-#define AK8975_REG_ASTC 0x0C
-#define AK8975_REG_TS1 0x0D
-#define AK8975_REG_TS2 0x0E
-#define AK8975_REG_I2CDIS 0x0F
-/*! @}*/
-
-/*! \name AK8975 fuse-rom address
-\anchor AK8975_FUSE
-Defines a read-only address of the fuse ROM of the AK8975.*/
-/*! @{*/
-#define AK8975_FUSE_ASAX 0x10
-#define AK8975_FUSE_ASAY 0x11
-#define AK8975_FUSE_ASAZ 0x12
-/*! @}*/
-
-#define AK8975_MAX_DELAY (100)
-#define AK8975_MIN_DELAY (10)
-
-/**
- * struct inv_gyro_state_s - Driver state variables.
- * @dev: Represents read-only node for accessing buffered data.
- * @idev: Handle to input device.
- * @sl_handle: Handle to I2C port.
- */
-struct inv_compass_state {
+
+#define AKM_NAME "akm89xx"
+#define AKM_HW_DELAY_POR_MS (50)
+#define AKM_HW_DELAY_TSM_MS (10) /* Time Single Measurement */
+#define AKM_HW_DELAY_US (100)
+#define AKM_HW_DELAY_ROM_ACCESS_US (200)
+#define AKM_POLL_DELAY_MS_DFLT (200)
+#define AKM_MPU_RETRY_COUNT (20)
+#define AKM_MPU_RETRY_DELAY_MS (20)
+#define AKM_ERR_CNT_MAX (20)
+
+#define AKM_INPUT_RESOLUTION (1)
+#define AKM_INPUT_DIVISOR (1)
+#define AKM_INPUT_DELAY_MS_MIN (AKM_HW_DELAY_TSM_MS)
+#define AKM_INPUT_POWER_UA (10000)
+#define AKM_INPUT_RANGE (4912)
+
+#define AKM_REG_WIA (0x00)
+#define AKM_WIA_ID (0x48)
+#define AKM_REG_INFO (0x01)
+#define AKM_REG_ST1 (0x02)
+#define AKM_ST1_DRDY (0x01)
+#define AKM_ST1_DOR (0x02)
+#define AKM_REG_HXL (0x03)
+#define AKM_REG_HXH (0x04)
+#define AKM_REG_HYL (0x05)
+#define AKM_REG_HYH (0x06)
+#define AKM_REG_HZL (0x07)
+#define AKM_REG_HZH (0x08)
+#define AKM_REG_ST2 (0x09)
+#define AKM_ST2_DERR (0x04)
+#define AKM_ST2_HOFL (0x08)
+#define AKM_ST2_BITM (0x10)
+#define AKM_REG_CNTL1 (0x0A)
+#define AKM_CNTL1_MODE_MASK (0x0F)
+#define AKM_CNTL1_MODE_POWERDOWN (0x00)
+#define AKM_CNTL1_MODE_SINGLE (0x01)
+#define AKM_CNTL1_MODE_CONT1 (0x02)
+#define AKM_CNTL1_MODE_CONT2 (0x06)
+#define AKM_CNTL1_MODE_SELFTEST (0x08)
+#define AKM_CNTL1_MODE_ROM_ACCESS (0x0F)
+#define AKM_CNTL1_OUTPUT_BIT16 (0x10)
+#define AKM_REG_CNTL2 (0x0B)
+#define AKM_CNTL2_SRST (0x01)
+#define AKM_REG_ASTC (0x0C)
+#define AKM_REG_TS1 (0x0D)
+#define AKM_REG_TS2 (0x0E)
+#define AKM_REG_I2CDIS (0x0F)
+#define AKM_REG_ASAX (0x10)
+#define AKM_REG_ASAY (0x11)
+#define AKM_REG_ASAZ (0x12)
+
+#define AKM8963_SCALE14 (19661)
+#define AKM8963_SCALE16 (4915)
+#define AKM8972_SCALE (19661)
+#define AKM8975_SCALE (9830)
+#define AKM8975_RANGE_X_HI (100)
+#define AKM8975_RANGE_X_LO (-100)
+#define AKM8975_RANGE_Y_HI (100)
+#define AKM8975_RANGE_Y_LO (-100)
+#define AKM8975_RANGE_Z_HI (-300)
+#define AKM8975_RANGE_Z_LO (-1000)
+#define AKM8972_RANGE_X_HI (50)
+#define AKM8972_RANGE_X_LO (-50)
+#define AKM8972_RANGE_Y_HI (50)
+#define AKM8972_RANGE_Y_LO (-50)
+#define AKM8972_RANGE_Z_HI (-100)
+#define AKM8972_RANGE_Z_LO (-500)
+#define AKM8963_RANGE_X_HI (200)
+#define AKM8963_RANGE_X_LO (-200)
+#define AKM8963_RANGE_Y_HI (200)
+#define AKM8963_RANGE_Y_LO (-200)
+#define AKM8963_RANGE_Z_HI (-800)
+#define AKM8963_RANGE_Z_LO (-3200)
+#define AXIS_X (0)
+#define AXIS_Y (1)
+#define AXIS_Z (2)
+#define WR (0)
+#define RD (1)
+
+
+/* regulator names in order of powering on */
+static char *akm_vregs[] = {
+ "vdd",
+ "vid",
+};
+
+
+struct akm_asa {
+ u8 asa[3]; /* axis sensitivity adjustment */
+ s16 range_lo[3];
+ s16 range_hi[3];
+};
+
+struct akm_inf {
struct i2c_client *i2c;
- atomic_t enable;
- atomic_t delay;
- struct mpu_platform_data plat_data;
- short i2c_addr;
- void *sl_handle;
- struct device *inv_dev;
+ struct mutex mutex_data;
struct input_dev *idev;
- struct delayed_work work;
-
- struct mutex value_mutex;
- struct mutex enable_mutex;
- short value[3];
- char asa[3]; /* axis sensitivity adjustment */
+ struct workqueue_struct *wq;
+ struct delayed_work dw;
+ struct regulator_bulk_data vreg[ARRAY_SIZE(akm_vregs)];
+ struct mpu_platform_data pdata;
+ struct akm_asa asa; /* data for calibration */
+ unsigned int compass_id; /* compass id */
+ unsigned long poll_delay_us; /* requested sampling delay (us) */
+ unsigned int resolution; /* report when new data outside this */
+ bool use_mpu; /* if device behind MPU */
+ bool initd; /* set if initialized */
+ bool enable; /* enable status */
+ bool port_en[2]; /* enable status of MPU write port */
+ int port_id[2]; /* MPU port ID */
+ u8 data_out; /* write value to trigger a sample */
+ u8 range_index; /* max_range index */
+ int xyz[3]; /* sample data */
+ bool cycle; /* cycle MPU en/dis for high speed */
+ unsigned long cycle_delay_us; /* cycle off time (us) */
+ s64 cycle_ts; /* cycle MPU disable timestamp */
};
-/* -------------------------------------------------------------------------- */
-/**
- * inv_serial_read() - Read one or more bytes from the device registers.
- * @st: Device driver instance.
- * @reg: First device register to be read from.
- * @length: Number of bytes to read.
- * @data: Data read from device.
- * NOTE: The slave register will not increment when reading from the FIFO.
- */
-static int inv_serial_read(struct inv_compass_state *st,
- unsigned char reg, unsigned short length, unsigned char *data)
-{
- struct i2c_msg msgs[2];
- int res;
- if (!data || !st->sl_handle)
- return -EINVAL;
+static int akm_i2c_rd(struct akm_inf *inf, u8 reg, u16 len, u8 *val)
+{
+ struct i2c_msg msg[2];
+
+ msg[0].addr = inf->i2c->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &reg;
+ msg[1].addr = inf->i2c->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = len;
+ msg[1].buf = val;
+ if (i2c_transfer(inf->i2c->adapter, msg, 2) != 2)
+ return -EIO;
- msgs[0].addr = st->i2c_addr;
- msgs[0].flags = 0; /* write */
- msgs[0].buf = &reg;
- msgs[0].len = 1;
-
- msgs[1].addr = st->i2c_addr;
- msgs[1].flags = I2C_M_RD;
- msgs[1].buf = data;
- msgs[1].len = length;
-
- pr_debug("%s RD%02X%02X%02X\n",
- st->idev->name, st->i2c_addr, reg, length);
- res = i2c_transfer(st->sl_handle, msgs, 2);
- if (res < 2) {
- if (res >= 0)
- res = -EIO;
- return res;
- } else
- return 0;
+ return 0;
}
-/**
- * inv_serial_single_write() - Write a byte to a device register.
- * @st: Device driver instance.
- * @reg: Device register to be written to.
- * @data: Byte to write to device.
- */
-static int inv_serial_single_write(struct inv_compass_state *st,
- unsigned char reg, unsigned char data)
+static int akm_i2c_wr(struct akm_inf *inf, u8 reg, u8 val)
{
- unsigned char tmp[2];
struct i2c_msg msg;
- int res;
+ u8 buf[2];
- if (!st->sl_handle)
- return -EINVAL;
+ buf[0] = reg;
+ buf[1] = val;
+ msg.addr = inf->i2c->addr;
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = buf;
+ if (i2c_transfer(inf->i2c->adapter, &msg, 1) != 1)
+ return -EIO;
- tmp[0] = reg;
- tmp[1] = data;
+ return 0;
+}
- msg.addr = st->i2c_addr;
- msg.flags = 0; /* write */
- msg.buf = tmp;
- msg.len = 2;
+static int akm_vreg_dis(struct akm_inf *inf, int i)
+{
+ int err = 0;
+
+ if (inf->vreg[i].ret && (inf->vreg[i].consumer != NULL)) {
+ err = regulator_disable(inf->vreg[i].consumer);
+ if (err)
+ dev_err(&inf->i2c->dev, "%s %s ERR\n",
+ __func__, inf->vreg[i].supply);
+ else
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ }
+ inf->vreg[i].ret = 0;
+ return err;
+}
- pr_debug("%s WS%02X%02X%02X\n",
- st->idev->name, st->i2c_addr, reg, data);
- res = i2c_transfer(st->sl_handle, &msg, 1);
- if (res < 1) {
- if (res == 0)
- res = -EIO;
- return res;
- } else
- return 0;
+static int akm_vreg_dis_all(struct akm_inf *inf)
+{
+ unsigned int i;
+ int err = 0;
+
+ for (i = ARRAY_SIZE(akm_vregs); i > 0; i--)
+ err |= akm_vreg_dis(inf, (i - 1));
+ return err;
}
-static int ak8975_init(struct inv_compass_state *st)
+static int akm_vreg_en(struct akm_inf *inf, int i)
{
- int result = 0;
- unsigned char serial_data[3];
+ int err = 0;
+
+ if ((!inf->vreg[i].ret) && (inf->vreg[i].consumer != NULL)) {
+ err = regulator_enable(inf->vreg[i].consumer);
+ if (!err) {
+ inf->vreg[i].ret = 1;
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ err = 1; /* flag regulator state change */
+ } else {
+ dev_err(&inf->i2c->dev, "%s %s ERR\n",
+ __func__, inf->vreg[i].supply);
+ }
+ }
+ return err;
+}
+
+static int akm_vreg_en_all(struct akm_inf *inf)
+{
+ int i;
+ int err = 0;
- result = inv_serial_single_write(st, AK8975_REG_CNTL,
- AK8975_CNTL_MODE_POWER_DOWN);
- if (result) {
- pr_err("%s, line=%d\n", __func__, __LINE__);
- return result;
+ for (i = 0; i < ARRAY_SIZE(akm_vregs); i++)
+ err |= akm_vreg_en(inf, i);
+ return err;
+}
+
+static void akm_vreg_exit(struct akm_inf *inf)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(akm_vregs); i++) {
+ if (inf->vreg[i].consumer != NULL) {
+ devm_regulator_put(inf->vreg[i].consumer);
+ inf->vreg[i].consumer = NULL;
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ }
}
- /* Wait at least 100us */
- udelay(100);
-
- result = inv_serial_single_write(st, AK8975_REG_CNTL,
- AK8975_CNTL_MODE_FUSE_ACCESS);
- if (result) {
- pr_err("%s, line=%d\n", __func__, __LINE__);
- return result;
+}
+
+static int akm_vreg_init(struct akm_inf *inf)
+{
+ unsigned int i;
+ int err = 0;
+
+ for (i = 0; i < ARRAY_SIZE(akm_vregs); i++) {
+ inf->vreg[i].supply = akm_vregs[i];
+ inf->vreg[i].ret = 0;
+ inf->vreg[i].consumer = devm_regulator_get(&inf->i2c->dev,
+ inf->vreg[i].supply);
+ if (IS_ERR(inf->vreg[i].consumer)) {
+ err |= PTR_ERR(inf->vreg[i].consumer);
+ dev_err(&inf->i2c->dev, "%s err %d for %s\n",
+ __func__, err, inf->vreg[i].supply);
+ inf->vreg[i].consumer = NULL;
+ } else {
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ }
}
+ return err;
+}
- /* Wait at least 200us */
- udelay(200);
+static int akm_pm(struct akm_inf *inf, bool enable)
+{
+ int err;
- result = inv_serial_read(st, AK8975_FUSE_ASAX, 3, serial_data);
- if (result) {
- pr_err("%s, line=%d\n", __func__, __LINE__);
- return result;
+ if (enable) {
+ err = akm_vreg_en_all(inf);
+ if (err)
+ mdelay(AKM_HW_DELAY_POR_MS);
+ } else {
+ err = akm_vreg_dis_all(inf);
}
+ if (err > 0)
+ err = 0;
+ if (err)
+ dev_err(&inf->i2c->dev, "%s enable=%x ERR=%d\n",
+ __func__, enable, err);
+ else
+ dev_dbg(&inf->i2c->dev, "%s enable=%x\n",
+ __func__, enable);
+ return err;
+}
- st->asa[0] = serial_data[0];
- st->asa[1] = serial_data[1];
- st->asa[2] = serial_data[2];
+static int akm_port_free(struct akm_inf *inf, int port)
+{
+ int err = 0;
- result = inv_serial_single_write(st, AK8975_REG_CNTL,
- AK8975_CNTL_MODE_POWER_DOWN);
- if (result) {
- pr_err("%s, line=%d\n", __func__, __LINE__);
- return result;
+ if ((inf->use_mpu) && (inf->port_id[port] >= 0)) {
+ err = nvi_mpu_port_free(inf->port_id[port]);
+ if (!err)
+ inf->port_id[port] = -1;
}
- udelay(100);
+ return err;
+}
- return result;
+static int akm_ports_free(struct akm_inf *inf)
+{
+ int err;
+
+ err = akm_port_free(inf, WR);
+ err |= akm_port_free(inf, RD);
+ return err;
+}
+
+static void akm_pm_exit(struct akm_inf *inf)
+{
+ akm_ports_free(inf);
+ akm_pm(inf, false);
+ akm_vreg_exit(inf);
+}
+
+static int akm_pm_init(struct akm_inf *inf)
+{
+ int err;
+
+ inf->initd = false;
+ inf->enable = false;
+ inf->port_en[WR] = false;
+ inf->port_en[RD] = false;
+ inf->port_id[WR] = -1;
+ inf->port_id[RD] = -1;
+ inf->poll_delay_us = (AKM_POLL_DELAY_MS_DFLT * 1000);
+ inf->cycle_delay_us = (AKM_INPUT_DELAY_MS_MIN * 1000);
+ akm_vreg_init(inf);
+ err = akm_pm(inf, true);
+ return err;
}
-static int ak8975_read(struct inv_compass_state *st, short rawfixed[3])
+static int akm_nvi_mpu_bypass_request(struct akm_inf *inf)
{
- unsigned char regs[8];
- unsigned char *stat = &regs[0];
- unsigned char *stat2 = &regs[7];
- int result = 0;
- int status = 0;
+ int i;
+ int err = 0;
- result = inv_serial_read(st, AK8975_REG_ST1, 8, regs);
- if (result) {
- pr_err("%s, line=%d\n", __func__, __LINE__);
- return result;
+ if (inf->use_mpu) {
+ for (i = 0; i < AKM_MPU_RETRY_COUNT; i++) {
+ err = nvi_mpu_bypass_request(true);
+ if ((!err) || (err == -EPERM))
+ break;
+
+ mdelay(AKM_MPU_RETRY_DELAY_MS);
+ }
+ if (err == -EPERM)
+ err = 0;
}
+ return err;
+}
- rawfixed[0] = (short)((regs[2]<<8) | regs[1]);
- rawfixed[1] = (short)((regs[4]<<8) | regs[3]);
- rawfixed[2] = (short)((regs[6]<<8) | regs[5]);
+static int akm_nvi_mpu_bypass_release(struct akm_inf *inf)
+{
+ int err = 0;
- /*
- * ST : data ready -
- * Measurement has been completed and data is ready to be read.
- */
- if (*stat & 0x01)
- status = 0;
-
- /*
- * ST2 : data error -
- * occurs when data read is started outside of a readable period;
- * data read would not be correct.
- * Valid in continuous measurement mode only.
- * In single measurement mode this error should not occour but we
- * stil account for it and return an error, since the data would be
- * corrupted.
- * DERR bit is self-clearing when ST2 register is read.
- */
- if (*stat2 & 0x04)
- status = 0x04;
- /*
- * ST2 : overflow -
- * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT.
- * This is likely to happen in presence of an external magnetic
- * disturbance; it indicates, the sensor data is incorrect and should
- * be ignored.
- * An error is returned.
- * HOFL bit clears when a new measurement starts.
- */
- if (*stat2 & 0x08)
- status = 0x08;
- /*
- * ST : overrun -
- * the previous sample was not fetched and lost.
- * Valid in continuous measurement mode only.
- * In single measurement mode this error should not occour and we
- * don't consider this condition an error.
- * DOR bit is self-clearing when ST2 or any meas. data register is
- * read.
- */
- if (*stat & 0x02) {
- /* status = INV_ERROR_COMPASS_DATA_UNDERFLOW; */
- status = 0;
+ if (inf->use_mpu)
+ err = nvi_mpu_bypass_release();
+ return err;
+}
+
+static int akm_wr(struct akm_inf *inf, u8 reg, u8 val)
+{
+ int err = 0;
+
+ err = akm_nvi_mpu_bypass_request(inf);
+ if (!err) {
+ err = akm_i2c_wr(inf, AKM_REG_CNTL1, AKM_CNTL1_MODE_POWERDOWN);
+ udelay(AKM_HW_DELAY_US);
+ err |= akm_i2c_wr(inf, reg, val);
+ akm_nvi_mpu_bypass_release(inf);
}
+ return err;
+}
- /*
- * trigger next measurement if:
- * - stat is non zero;
- * - if stat is zero and stat2 is non zero.
- * Won't trigger if data is not ready and there was no error.
- */
- if (*stat != 0x00 || *stat2 != 0x00) {
- result = inv_serial_single_write(st, AK8975_REG_CNTL,
- AK8975_CNTL_MODE_SNG_MEASURE);
- if (result) {
- pr_err("%s, line=%d\n", __func__, __LINE__);
- return result;
+static int akm_port_enable(struct akm_inf *inf, int port, bool enable)
+{
+ int err = 0;
+
+ if (enable != inf->port_en[port]) {
+ err = nvi_mpu_enable(inf->port_id[port], enable, false);
+ if (!err)
+ inf->port_en[port] = enable;
+ }
+ return err;
+}
+
+static int akm_ports_enable(struct akm_inf *inf, bool enable)
+{
+ int err;
+
+ err = akm_port_enable(inf, RD, enable);
+ err |= akm_port_enable(inf, WR, enable);
+ return err;
+}
+
+static int akm_mode_wr(struct akm_inf *inf, bool reset, u8 range, u8 mode)
+{
+ u8 mode_old;
+ u8 mode_new;
+ u8 val;
+ int i;
+ int err = 0;
+
+ mode_new = mode;
+ if (range)
+ mode |= AKM_CNTL1_OUTPUT_BIT16;
+ if ((mode == inf->data_out) && (!reset))
+ return err;
+
+ mode_old = inf->data_out & AKM_CNTL1_MODE_MASK;
+ if (inf->use_mpu)
+ err = akm_ports_enable(inf, false);
+ else
+ cancel_delayed_work_sync(&inf->dw);
+ if (err)
+ return err;
+
+ if (reset) {
+ if (inf->compass_id == COMPASS_ID_AK8963) {
+ err = akm_nvi_mpu_bypass_request(inf);
+ if (!err) {
+ err = akm_wr(inf, AKM_REG_CNTL2,
+ AKM_CNTL2_SRST);
+ for (i = 0; i < AKM_HW_DELAY_POR_MS; i++) {
+ mdelay(1);
+ err = akm_i2c_rd(inf, AKM_REG_CNTL2,
+ 1, &val);
+ if (err)
+ continue;
+
+ if (!(val & AKM_CNTL2_SRST))
+ break;
+ }
+ akm_nvi_mpu_bypass_release(inf);
+ }
}
}
+ inf->range_index = range;
+ inf->data_out = mode;
+ if (inf->use_mpu) {
+ if ((mode_old > AKM_CNTL1_MODE_SINGLE) ||
+ (mode_new > AKM_CNTL1_MODE_SINGLE))
+ err = akm_wr(inf, AKM_REG_CNTL1, mode);
+ if (mode_new <= AKM_CNTL1_MODE_SINGLE) {
+ err |= nvi_mpu_data_out(inf->port_id[WR], mode);
+ if (mode_new)
+ err |= akm_ports_enable(inf, true);
+ } else {
+ err |= akm_port_enable(inf, RD, true);
+ }
+ } else {
+ err = akm_wr(inf, AKM_REG_CNTL1, mode);
+ if (mode_new)
+ queue_delayed_work(inf->wq, &inf->dw,
+ usecs_to_jiffies(inf->poll_delay_us));
+ }
+ return err;
+}
+
+static int akm_delay(struct akm_inf *inf, unsigned long delay_us)
+{
+ u8 mode;
+ int err = 0;
+
+ if (inf->use_mpu)
+ err |= nvi_mpu_delay_us(inf->port_id[RD], delay_us);
+ if (!err) {
+ if (inf->compass_id == COMPASS_ID_AK8963) {
+ if (delay_us == (AKM_INPUT_DELAY_MS_MIN * 1000))
+ mode = AKM_CNTL1_MODE_CONT2;
+ else
+ mode = AKM_CNTL1_MODE_SINGLE;
+ err = akm_mode_wr(inf, false, inf->range_index, mode);
+ } else {
+ if ((delay_us == (AKM_INPUT_DELAY_MS_MIN * 1000)) &&
+ inf->cycle_delay_us)
+ inf->cycle = true;
+ else
+ inf->cycle = false;
+ }
+ }
+ return err;
+}
+
+static int akm_init_hw(struct akm_inf *inf)
+{
+ u8 val[8];
+ int err;
+ int err_t;
+
+ err_t = akm_nvi_mpu_bypass_request(inf);
+ if (!err_t) {
+ err_t = akm_wr(inf, AKM_REG_CNTL1, AKM_CNTL1_MODE_ROM_ACCESS);
+ udelay(AKM_HW_DELAY_ROM_ACCESS_US);
+ err_t |= akm_i2c_rd(inf, AKM_REG_ASAX, 3, inf->asa.asa);
+ /* we can autodetect AK8963 with BITM */
+ inf->compass_id = 0;
+ err = akm_wr(inf, AKM_REG_CNTL1, (AKM_CNTL1_MODE_SINGLE |
+ AKM_CNTL1_OUTPUT_BIT16));
+ if (!err) {
+ mdelay(AKM_HW_DELAY_TSM_MS);
+ err = akm_i2c_rd(inf, AKM_REG_ST2, 1, val);
+ if ((!err) && (val[0] & AKM_CNTL1_OUTPUT_BIT16))
+ inf->compass_id = COMPASS_ID_AK8963;
+ }
+ akm_nvi_mpu_bypass_release(inf);
+ if (!inf->compass_id)
+ inf->compass_id = inf->pdata.sec_slave_id;
+ if (inf->compass_id == COMPASS_ID_AK8963) {
+ inf->asa.range_lo[AXIS_X] = AKM8963_RANGE_X_LO;
+ inf->asa.range_hi[AXIS_X] = AKM8963_RANGE_X_HI;
+ inf->asa.range_lo[AXIS_Y] = AKM8963_RANGE_Y_LO;
+ inf->asa.range_hi[AXIS_Y] = AKM8963_RANGE_Y_HI;
+ inf->asa.range_lo[AXIS_Z] = AKM8963_RANGE_Z_LO;
+ inf->asa.range_hi[AXIS_Z] = AKM8963_RANGE_Z_HI;
+ inf->range_index = 1;
+ } else if (inf->compass_id == COMPASS_ID_AK8972) {
+ inf->asa.range_lo[AXIS_X] = AKM8972_RANGE_X_LO;
+ inf->asa.range_hi[AXIS_X] = AKM8972_RANGE_X_HI;
+ inf->asa.range_lo[AXIS_Y] = AKM8972_RANGE_Y_LO;
+ inf->asa.range_hi[AXIS_Y] = AKM8972_RANGE_Y_HI;
+ inf->asa.range_lo[AXIS_Z] = AKM8972_RANGE_Z_LO;
+ inf->asa.range_hi[AXIS_Z] = AKM8972_RANGE_Z_HI;
+ inf->range_index = 0;
+ } else { /* default COMPASS_ID_AK8975 */
+ inf->compass_id = COMPASS_ID_AK8975;
+ inf->asa.range_lo[AXIS_X] = AKM8975_RANGE_X_LO;
+ inf->asa.range_hi[AXIS_X] = AKM8975_RANGE_X_HI;
+ inf->asa.range_lo[AXIS_Y] = AKM8975_RANGE_Y_LO;
+ inf->asa.range_hi[AXIS_Y] = AKM8975_RANGE_Y_HI;
+ inf->asa.range_lo[AXIS_Z] = AKM8975_RANGE_Z_LO;
+ inf->asa.range_hi[AXIS_Z] = AKM8975_RANGE_Z_HI;
+ inf->range_index = 0;
+ }
+ }
+ if (!err_t)
+ inf->initd = true;
+ else
+ dev_err(&inf->i2c->dev, "%s ERR %d", __func__, err_t);
+ return err_t;
+}
+
+static void akm_calc(struct akm_inf *inf, u8 *data)
+{
+ int x;
+ int y;
+ int z;
+
+ /* data[1] = AKM_REG_HXL
+ * data[2] = AKM_REG_HXH
+ * data[3] = AKM_REG_HYL
+ * data[4] = AKM_REG_HYH
+ * data[5] = AKM_REG_HZL
+ * data[6] = AKM_REG_HZH
+ */
+ x = (int)((data[2] << 8) | data[1]);
+ y = (int)((data[4] << 8) | data[3]);
+ z = (int)((data[6] << 8) | data[5]);
+ x = ((x * (inf->asa.asa[AXIS_X] + 128)) >> 8);
+ y = ((y * (inf->asa.asa[AXIS_Y] + 128)) >> 8);
+ z = ((z * (inf->asa.asa[AXIS_Z] + 128)) >> 8);
+ mutex_lock(&inf->mutex_data);
+ inf->xyz[AXIS_X] = x;
+ inf->xyz[AXIS_Y] = y;
+ inf->xyz[AXIS_Z] = z;
+ mutex_unlock(&inf->mutex_data);
+}
+
+static void akm_report(struct akm_inf *inf, u8 *data, s64 ts)
+{
+ akm_calc(inf, data);
+ input_report_rel(inf->idev, REL_X, inf->xyz[AXIS_X]);
+ input_report_rel(inf->idev, REL_Y, inf->xyz[AXIS_Y]);
+ input_report_rel(inf->idev, REL_Z, inf->xyz[AXIS_Z]);
+ input_report_rel(inf->idev, REL_MISC, (unsigned int)(ts >> 32));
+ input_report_rel(inf->idev, REL_WHEEL,
+ (unsigned int)(ts & 0xffffffff));
+ input_sync(inf->idev);
+}
- if (status)
- pr_err("%s, line=%d, status=%d\n", __func__, __LINE__, status);
+static int akm_read_sts(struct akm_inf *inf, u8 *data)
+{
+ int err = -1; /* assume something wrong */
+ /* data[0] = AKM_REG_ST1
+ * data[7] = AKM_REG_ST2
+ * data[8] = AKM_REG_CNTL1
+ */
+ if ((data[0] & AKM_ST1_DRDY) && (!(data[7] &
+ (AKM_ST2_HOFL | AKM_ST2_DERR))))
+ err = 1; /* data ready to be reported */
+ else if ((data[8] & AKM_CNTL1_MODE_MASK) == (inf->data_out &
+ AKM_CNTL1_MODE_MASK))
+ err = 0; /* still processing */
+ return err;
+}
- return status;
+static s64 akm_timestamp_ns(void)
+{
+ struct timespec ts;
+ s64 ns;
+
+ ktime_get_ts(&ts);
+ ns = timespec_to_ns(&ts);
+ return ns;
+}
+
+static int akm_read(struct akm_inf *inf)
+{
+ long long timestamp1;
+ long long timestamp2;
+ u8 data[9];
+ int err;
+
+ timestamp1 = akm_timestamp_ns();
+ err = akm_i2c_rd(inf, AKM_REG_ST1, 9, data);
+ timestamp2 = akm_timestamp_ns();
+ if (err)
+ return err;
+
+ err = akm_read_sts(inf, data);
+ if (err > 0) {
+ timestamp2 = (timestamp2 - timestamp1) / 2;
+ timestamp1 += timestamp2;
+ akm_report(inf, data, timestamp1);
+ if ((inf->data_out & AKM_CNTL1_MODE_MASK) ==
+ AKM_CNTL1_MODE_SINGLE)
+ akm_i2c_wr(inf, AKM_REG_CNTL1, inf->data_out);
+ } else if (err < 0) {
+ dev_err(&inf->i2c->dev, "%s ERR\n", __func__);
+ akm_mode_wr(inf, true, inf->range_index,
+ inf->data_out & AKM_CNTL1_MODE_MASK);
+ }
+ return err;
+}
+
+static void akm_mpu_handler(u8 *data, unsigned int len, s64 ts, void *p_val)
+{
+ struct akm_inf *inf;
+ int err;
+
+ inf = (struct akm_inf *)p_val;
+ if (inf->enable) {
+ if (inf->cycle && (!inf->port_en[WR])) {
+ ts -= inf->cycle_ts;
+ if (ts > (inf->cycle_delay_us * 1000))
+ akm_port_enable(inf, WR, true);
+ return;
+ }
+ err = akm_read_sts(inf, data);
+ if (err > 0) {
+ akm_report(inf, data, ts);
+ if (inf->cycle) {
+ akm_port_enable(inf, WR, false);
+ inf->cycle_ts = ts;
+ }
+ }
+ }
}
-static void ak8975_work_func(struct work_struct *work)
+static int akm_id(struct akm_inf *inf)
{
- struct inv_compass_state *st =
- container_of((struct delayed_work *)work,
- struct inv_compass_state, work);
- unsigned long delay = msecs_to_jiffies(atomic_read(&st->delay));
- short c[3];
- c[0] = c[1] = c[2] = 0;
- if (0 == ak8975_read(st, c)) {
- c[0] = ((c[0] * (st->asa[0] + 128)) >> 8);
- c[1] = ((c[1] * (st->asa[1] + 128)) >> 8);
- c[2] = ((c[2] * (st->asa[2] + 128)) >> 8);
- input_report_rel(st->idev, REL_X, c[0]);
- input_report_rel(st->idev, REL_Y, c[1]);
- input_report_rel(st->idev, REL_Z, c[2]);
- input_sync(st->idev);
+ struct nvi_mpu_port nmp;
+ u8 config_boot;
+ u8 val = 0;
+ int err;
+
+ config_boot = inf->pdata.config & NVI_CONFIG_BOOT_MASK;
+ if (config_boot == NVI_CONFIG_BOOT_AUTO) {
+ nmp.addr = inf->i2c->addr | 0x80;
+ nmp.reg = AKM_REG_WIA;
+ nmp.ctrl = 1;
+ err = nvi_mpu_dev_valid(&nmp, &val);
+ /* see mpu.h for possible return values */
+ if ((err == -EAGAIN) || (err == -EBUSY))
+ return -EAGAIN;
+
+ if (((!err) && (val == AKM_WIA_ID)) || (err == -EIO))
+ config_boot = NVI_CONFIG_BOOT_MPU;
}
+ if (config_boot == NVI_CONFIG_BOOT_MPU) {
+ inf->use_mpu = true;
+ nmp.addr = inf->i2c->addr | 0x80;
+ nmp.reg = AKM_REG_ST1;
+ nmp.ctrl = 9;
+ nmp.data_out = 0;
+ nmp.delay_ms = 0;
+ nmp.delay_us = inf->poll_delay_us;
+ nmp.shutdown_bypass = false;
+ nmp.handler = &akm_mpu_handler;
+ nmp.ext_driver = (void *)inf;
+ err = nvi_mpu_port_alloc(&nmp);
+ if (err < 0)
+ return err;
+
+ inf->port_id[RD] = err;
+ nmp.addr = inf->i2c->addr;
+ nmp.reg = AKM_REG_CNTL1;
+ nmp.ctrl = 1;
+ nmp.data_out = inf->data_out;
+ nmp.delay_ms = AKM_HW_DELAY_TSM_MS;
+ nmp.delay_us = 0;
+ nmp.shutdown_bypass = false;
+ nmp.handler = NULL;
+ nmp.ext_driver = NULL;
+ err = nvi_mpu_port_alloc(&nmp);
+ if (err < 0) {
+ akm_ports_free(inf);
+ } else {
+ inf->port_id[WR] = err;
+ err = 0;
+ }
+ return err;
+ }
+
+ /* NVI_CONFIG_BOOT_EXTERNAL */
+ inf->use_mpu = false;
+ err = akm_i2c_rd(inf, AKM_REG_WIA, 1, &val);
+ if ((!err) && (val == AKM_WIA_ID))
+ return 0;
- mutex_lock(&st->value_mutex);
- st->value[0] = c[0];
- st->value[1] = c[1];
- st->value[2] = c[2];
- mutex_unlock(&st->value_mutex);
- schedule_delayed_work(&st->work, delay);
+ return -ENODEV;
}
-static ssize_t ak8975_value_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static void akm_work(struct work_struct *ws)
{
- struct inv_compass_state *st = dev_get_drvdata(dev);
- short c[3];
+ struct akm_inf *inf;
- mutex_lock(&st->value_mutex);
- c[0] = st->value[0];
- c[1] = st->value[1];
- c[2] = st->value[2];
- mutex_unlock(&st->value_mutex);
- return sprintf(buf, "%d, %d, %d\n", c[0], c[1], c[2]);
+ inf = container_of(ws, struct akm_inf, dw.work);
+ akm_read(inf);
+ queue_delayed_work(inf->wq, &inf->dw,
+ usecs_to_jiffies(inf->poll_delay_us));
}
-static ssize_t ak8975_scale_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static int akm_enable(struct akm_inf *inf, bool enable)
{
- return sprintf(buf, "%ld\n", 9830L * 32768L);
+ int err = 0;
+
+ akm_pm(inf, true);
+ if (!inf->initd)
+ err = akm_init_hw(inf);
+ if (!err) {
+ if (enable) {
+ inf->data_out = AKM_CNTL1_MODE_SINGLE;
+ err = akm_delay(inf, inf->poll_delay_us);
+ err |= akm_mode_wr(inf, true, inf->range_index,
+ inf->data_out & AKM_CNTL1_MODE_MASK);
+ if (!err)
+ inf->enable = true;
+ } else {
+ inf->enable = false;
+ err = akm_mode_wr(inf, false, inf->range_index,
+ AKM_CNTL1_MODE_POWERDOWN);
+ if (!err)
+ akm_pm(inf, false);
+ }
+ }
+ return err;
+}
+
+static ssize_t akm_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct akm_inf *inf;
+ unsigned int enable;
+ bool en;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtouint(buf, 10, &enable);
+ if (err)
+ return -EINVAL;
+
+ if (enable)
+ en = true;
+ else
+ en = false;
+ dev_dbg(&inf->i2c->dev, "%s: %x", __func__, en);
+ err = akm_enable(inf, en);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d", __func__, en, err);
+ return err;
+ }
+
+ return count;
}
-static ssize_t ak8975_reset_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+
+static ssize_t akm_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_compass_state *st = dev_get_drvdata(dev);
- int result;
- result = ak8975_init(st);
- return sprintf(buf, "%d\n", result);
+ struct akm_inf *inf;
+ unsigned int enable = 0;
+
+ inf = dev_get_drvdata(dev);
+ if (inf->enable)
+ enable = 1;
+ return sprintf(buf, "%u\n", enable);
}
-static ssize_t ak8975_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t akm_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_compass_state *st = dev_get_drvdata(dev);
- return sprintf(buf, "%d\n", atomic_read(&st->enable));
+ struct akm_inf *inf;
+ unsigned long delay_us;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtoul(buf, 10, &delay_us);
+ if (err)
+ return -EINVAL;
+
+ dev_dbg(&inf->i2c->dev, "%s: %lu\n", __func__, delay_us);
+ if (delay_us < (AKM_INPUT_DELAY_MS_MIN * 1000))
+ delay_us = (AKM_INPUT_DELAY_MS_MIN * 1000);
+ if ((inf->enable) && (delay_us != inf->poll_delay_us))
+ err = akm_delay(inf, delay_us);
+ if (!err) {
+ inf->poll_delay_us = delay_us;
+ } else {
+ dev_err(&inf->i2c->dev, "%s: %lu ERR=%d\n",
+ __func__, delay_us, err);
+ return err;
+ }
+
+ return count;
}
-static ssize_t ak8975_rate_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t akm_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_compass_state *st = dev_get_drvdata(dev);
- /* transform delay in ms to rate */
- return sprintf(buf, "%d\n", 1000 / atomic_read(&st->delay));
+ struct akm_inf *inf;
+
+ inf = dev_get_drvdata(dev);
+ if (inf->enable)
+ return sprintf(buf, "%lu\n", inf->poll_delay_us);
+
+ return sprintf(buf, "%u\n", (AKM_INPUT_DELAY_MS_MIN * 1000));
}
-static ssize_t akm8975_matrix_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t akm_resolution_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_compass_state *st = dev_get_drvdata(dev);
- signed char *m;
- m = st->plat_data.orientation;
- return sprintf(buf,
- "%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
- m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
-}
-
-static ssize_t ak8975_rate_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned long data;
- int error;
- struct inv_compass_state *st = dev_get_drvdata(dev);
-
- error = kstrtoul(buf, 10, &data);
- if (error)
- return error;
- /* transform rate to delay in ms */
- data = 1000 / data;
- if (data > AK8975_MAX_DELAY)
- data = AK8975_MAX_DELAY;
- if (data < AK8975_MIN_DELAY)
- data = AK8975_MIN_DELAY;
- atomic_set(&st->delay, (unsigned int) data);
+ struct akm_inf *inf;
+ unsigned int resolution;
+
+ inf = dev_get_drvdata(dev);
+ if (kstrtouint(buf, 10, &resolution))
+ return -EINVAL;
+
+ dev_dbg(&inf->i2c->dev, "%s %u", __func__, resolution);
+ inf->resolution = resolution;
return count;
}
-static void ak8975_set_enable(struct device *dev, int enable)
+static ssize_t akm_resolution_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_compass_state *st = dev_get_drvdata(dev);
- int result = 0;
- int pre_enable = atomic_read(&st->enable);
+ struct akm_inf *inf;
+ unsigned int resolution;
+
+ inf = dev_get_drvdata(dev);
+ if (inf->enable)
+ resolution = inf->resolution;
+ else
+ resolution = AKM_INPUT_RESOLUTION;
+ return sprintf(buf, "%u\n", resolution);
+}
- mutex_lock(&st->enable_mutex);
- if (enable) {
- if (pre_enable == 0) {
- result = inv_serial_single_write(st, AK8975_REG_CNTL,
- AK8975_CNTL_MODE_SNG_MEASURE);
- if (result)
- pr_err("%s, line=%d\n", __func__, __LINE__);
- schedule_delayed_work(&st->work,
- msecs_to_jiffies(atomic_read(&st->delay)));
- atomic_set(&st->enable, 1);
+static ssize_t akm_max_range_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct akm_inf *inf;
+ u8 range_index;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &range_index);
+ if (err)
+ return -EINVAL;
+
+ dev_dbg(&inf->i2c->dev, "%s %u", __func__, range_index);
+ if (inf->compass_id == COMPASS_ID_AK8963) {
+ if (range_index > 1)
+ return -EINVAL;
+
+ if (inf->enable) {
+ err = akm_mode_wr(inf, false, range_index,
+ inf->data_out & AKM_CNTL1_MODE_MASK);
+ if (err)
+ return err;
+ } else {
+ inf->range_index = range_index;
}
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static ssize_t akm_max_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct akm_inf *inf;
+ unsigned int range;
+ inf = dev_get_drvdata(dev);
+ if (inf->enable) {
+ range = inf->range_index;
} else {
- if (pre_enable == 1) {
- cancel_delayed_work_sync(&st->work);
- atomic_set(&st->enable, 0);
- result = inv_serial_single_write(st, AK8975_REG_CNTL,
- AK8975_CNTL_MODE_POWER_DOWN);
- if (result)
- pr_err("%s, line=%d\n", __func__, __LINE__);
- mdelay(1); /* wait at least 100us */
+ if (inf->compass_id == COMPASS_ID_AK8963) {
+ if (inf->range_index)
+ range = AKM8963_SCALE16;
+ else
+ range = AKM8963_SCALE14;
+ } else if (inf->compass_id == COMPASS_ID_AK8972) {
+ range = AKM8972_SCALE;
+ } else {
+ range = AKM8975_SCALE;
}
}
- mutex_unlock(&st->enable_mutex);
+ return sprintf(buf, "%u\n", range);
}
-static ssize_t ak8975_enable_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t akm_cycle_delay_us_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- unsigned long data;
- int error;
+ struct akm_inf *inf;
+ unsigned long cycle_delay_us;
+ int err;
- error = kstrtoul(buf, 10, &data);
- if (error)
- return error;
- if (data == 0 || data == 1)
- ak8975_set_enable(dev, data);
+ inf = dev_get_drvdata(dev);
+ err = kstrtoul(buf, 10, &cycle_delay_us);
+ if (err)
+ return -EINVAL;
+ dev_dbg(&inf->i2c->dev, "%s %lu", __func__, cycle_delay_us);
+ inf->cycle_delay_us = cycle_delay_us;
return count;
}
-static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
- ak8975_enable_show, ak8975_enable_store);
-static DEVICE_ATTR(value, S_IRUGO, ak8975_value_show, NULL);
-static DEVICE_ATTR(scale, S_IRUGO, ak8975_scale_show, NULL);
-static DEVICE_ATTR(reset, S_IRUGO, ak8975_reset_show, NULL);
-static DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, ak8975_rate_show,
- ak8975_rate_store);
-static DEVICE_ATTR(compass_matrix, S_IRUGO, akm8975_matrix_show, NULL);
+static ssize_t akm_cycle_delay_us_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct akm_inf *inf = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lu\n", inf->cycle_delay_us);
+}
+
+static ssize_t akm_divisor_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct akm_inf *inf;
+
+ inf = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", AKM_INPUT_DIVISOR);
+}
+
+static ssize_t akm_microamp_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct akm_inf *inf;
-static struct attribute *ak8975_attributes[] = {
+ inf = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", AKM_INPUT_POWER_UA);
+}
+
+static ssize_t akm_magnetic_field_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct akm_inf *inf;
+ int x;
+ int y;
+ int z;
+
+ inf = dev_get_drvdata(dev);
+ if (inf->enable) {
+ mutex_lock(&inf->mutex_data);
+ x = inf->xyz[AXIS_X];
+ y = inf->xyz[AXIS_Y];
+ z = inf->xyz[AXIS_Z];
+ mutex_unlock(&inf->mutex_data);
+ return sprintf(buf, "%d, %d, %d\n", x, y, z);
+ }
+
+ return -EPERM;
+}
+
+static ssize_t akm_orientation_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct akm_inf *inf;
+ signed char *m;
+
+ inf = dev_get_drvdata(dev);
+ m = inf->pdata.orientation;
+ return sprintf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+ m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
+}
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWOTH,
+ akm_enable_show, akm_enable_store);
+static DEVICE_ATTR(delay, S_IRUGO | S_IWUSR | S_IWOTH,
+ akm_delay_show, akm_delay_store);
+static DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR | S_IWOTH,
+ akm_resolution_show, akm_resolution_store);
+static DEVICE_ATTR(max_range, S_IRUGO | S_IWUSR | S_IWOTH,
+ akm_max_range_show, akm_max_range_store);
+static DEVICE_ATTR(cycle_delay_us, S_IRUGO | S_IWUSR | S_IWOTH,
+ akm_cycle_delay_us_show, akm_cycle_delay_us_store);
+static DEVICE_ATTR(divisor, S_IRUGO,
+ akm_divisor_show, NULL);
+static DEVICE_ATTR(microamp, S_IRUGO,
+ akm_microamp_show, NULL);
+static DEVICE_ATTR(magnetic_field, S_IRUGO,
+ akm_magnetic_field_show, NULL);
+static DEVICE_ATTR(orientation, S_IRUGO,
+ akm_orientation_show, NULL);
+
+static struct attribute *akm_attrs[] = {
&dev_attr_enable.attr,
- &dev_attr_value.attr,
- &dev_attr_scale.attr,
- &dev_attr_reset.attr,
- &dev_attr_rate.attr,
- &dev_attr_compass_matrix.attr,
+ &dev_attr_delay.attr,
+ &dev_attr_resolution.attr,
+ &dev_attr_max_range.attr,
+ &dev_attr_divisor.attr,
+ &dev_attr_microamp.attr,
+ &dev_attr_magnetic_field.attr,
+ &dev_attr_orientation.attr,
+ &dev_attr_cycle_delay_us.attr,
NULL
};
-static struct attribute_group ak8975_attribute_group = {
- .name = "ak8975",
- .attrs = ak8975_attributes
+static struct attribute_group akm_attr_group = {
+ .name = AKM_NAME,
+ .attrs = akm_attrs
};
+static int akm_sysfs_create(struct akm_inf *inf)
+{
+ int err;
-/**
- * inv_setup_input() - internal setup input device.
- * @st: Device driver instance.
- * @**idev_in pointer to input device
- * @*client i2c client
- * @*name name of the input device.
- */
-static int inv_setup_input(struct inv_compass_state *st,
- struct input_dev **idev_in, struct i2c_client *client,
- unsigned char *name) {
- int result;
- struct input_dev *idev;
- idev = input_allocate_device();
- if (!idev) {
- result = -ENOMEM;
- return result;
- }
- /* Setup input device. */
- idev->name = name;
+ err = sysfs_create_group(&inf->idev->dev.kobj, &akm_attr_group);
+ return err;
+}
- idev->id.bustype = BUS_I2C;
- idev->id.product = 'S';
- idev->id.vendor = ('I'<<8) | 'S';
- idev->id.version = 1;
- idev->dev.parent = &client->dev;
- /* Open and close method. */
- idev->open = NULL;
- idev->close = NULL;
+static void akm_input_close(struct input_dev *idev)
+{
+ struct akm_inf *inf;
- __set_bit(EV_REL, idev->evbit);
- input_set_capability(idev, EV_REL, REL_X);
- input_set_capability(idev, EV_REL, REL_Y);
- input_set_capability(idev, EV_REL, REL_Z);
+ inf = input_get_drvdata(idev);
+ if (inf != NULL)
+ akm_enable(inf, false);
+}
- input_set_capability(idev, EV_REL, REL_MISC);
- input_set_capability(idev, EV_REL, REL_WHEEL);
+static int akm_input_create(struct akm_inf *inf)
+{
+ int err;
- input_set_drvdata(idev, st);
- result = input_register_device(idev);
- if (result)
- input_free_device(idev);
+ inf->idev = input_allocate_device();
+ if (!inf->idev) {
+ err = -ENOMEM;
+ dev_err(&inf->i2c->dev, "%s ERR %d\n", __func__, err);
+ return err;
+ }
- *idev_in = idev;
- return result;
+ inf->idev->name = AKM_NAME;
+ inf->idev->dev.parent = &inf->i2c->dev;
+ inf->idev->close = akm_input_close;
+ input_set_drvdata(inf->idev, inf);
+ input_set_capability(inf->idev, EV_REL, REL_X);
+ input_set_capability(inf->idev, EV_REL, REL_Y);
+ input_set_capability(inf->idev, EV_REL, REL_Z);
+ input_set_capability(inf->idev, EV_REL, REL_MISC);
+ input_set_capability(inf->idev, EV_REL, REL_WHEEL);
+ err = input_register_device(inf->idev);
+ if (err) {
+ input_free_device(inf->idev);
+ inf->idev = NULL;
+ }
+ return err;
}
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static int ak8975_mod_probe(struct i2c_client *client,
- const struct i2c_device_id *devid)
+static int akm_remove(struct i2c_client *client)
{
- struct mpu_platform_data *pdata;
- struct inv_compass_state *st;
- struct input_dev *idev;
- int result = 0;
-
- dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
+ struct akm_inf *inf;
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- result = -ENODEV;
- goto out_no_free;
+ inf = i2c_get_clientdata(client);
+ if (inf != NULL) {
+ if (inf->idev) {
+ input_unregister_device(inf->idev);
+ input_free_device(inf->idev);
+ }
+ if (inf->wq)
+ destroy_workqueue(inf->wq);
+ akm_pm_exit(inf);
+ if (&inf->mutex_data)
+ mutex_destroy(&inf->mutex_data);
+ kfree(inf);
}
+ dev_info(&client->dev, "%s\n", __func__);
+ return 0;
+}
+
+static void akm_shutdown(struct i2c_client *client)
+{
+ akm_remove(client);
+}
- pdata = (struct mpu_platform_data *)dev_get_platdata(&client->dev);
- if (!pdata) {
- dev_err(&client->adapter->dev,
- "Missing platform data for slave %s\n", devid->name);
- result = -EFAULT;
- goto out_no_free;
+static int akm_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ struct akm_inf *inf;
+ struct mpu_platform_data *pd;
+ int err;
+
+ dev_info(&client->dev, "%s\n", __func__);
+ inf = kzalloc(sizeof(*inf), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(inf)) {
+ dev_err(&client->dev, "%s kzalloc ERR\n", __func__);
+ return -ENOMEM;
}
- st = kzalloc(sizeof(*st), GFP_KERNEL);
- if (!st) {
- result = -ENOMEM;
- goto out_no_free;
+ inf->i2c = client;
+ i2c_set_clientdata(client, inf);
+ pd = (struct mpu_platform_data *)dev_get_platdata(&client->dev);
+ if (pd == NULL)
+ dev_err(&client->dev, "%s No %s platform data ERR\n",
+ __func__, devid->name);
+ else
+ inf->pdata = *pd;
+ akm_pm_init(inf);
+ err = akm_id(inf);
+ akm_pm(inf, false);
+ if (err == -EAGAIN)
+ goto akm_probe_again;
+ else if (err)
+ goto akm_probe_err;
+
+ mutex_init(&inf->mutex_data);
+ err = akm_input_create(inf);
+ if (err)
+ goto akm_probe_err;
+
+ inf->wq = create_singlethread_workqueue(AKM_NAME);
+ if (!inf->wq) {
+ dev_err(&client->dev, "%s workqueue ERR\n", __func__);
+ err = -ENOMEM;
+ goto akm_probe_err;
}
- i2c_set_clientdata(client, st);
- st->i2c = client;
- mutex_init(&st->value_mutex);
- mutex_init(&st->enable_mutex);
- atomic_set(&st->delay, 100);
- st->sl_handle = client->adapter;
- st->plat_data = *pdata;
- st->i2c_addr = client->addr;
- INIT_DELAYED_WORK(&st->work, ak8975_work_func);
- result = inv_setup_input(st, &idev, client, "INV_AK8975");
- if (result)
- goto out_free_memory;
- st->idev = idev;
- result = sysfs_create_group(&st->idev->dev.kobj,
- &ak8975_attribute_group);
- if (result < 0)
- goto error_sysfs;
-
- result = ak8975_init(st);
- if (result < 0)
- goto error_sysfs;
-
- return result;
-error_sysfs:
- input_unregister_device(st->idev);
-out_free_memory:
- kfree(st);
-out_no_free:
- dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
- return result;
-
-}
-
-static int ak8975_mod_remove(struct i2c_client *client)
-{
- struct inv_compass_state *st =
- i2c_get_clientdata(client);
-
- dev_dbg(&client->adapter->dev, "%s\n", __func__);
- ak8975_set_enable(&st->idev->dev, 0);
- sysfs_remove_group(&st->idev->dev.kobj, &ak8975_attribute_group);
- input_unregister_device(st->idev);
- kfree(st);
+ INIT_DELAYED_WORK(&inf->dw, akm_work);
+ err = akm_sysfs_create(inf);
+ if (err)
+ goto akm_probe_err;
+
return 0;
+
+akm_probe_err:
+ dev_err(&client->dev, "%s ERR %d\n", __func__, err);
+akm_probe_again:
+ akm_remove(client);
+ return err;
}
-static const struct i2c_device_id ak8975_mod_id[] = {
- {"ak8975", COMPASS_ID_AK8975},
+static const struct i2c_device_id akm_i2c_device_id[] = {
+ {AKM_NAME, 0},
+ {"ak8963", 0},
+ {"ak8972", 0},
+ {"ak8975", 0},
{}
};
-MODULE_DEVICE_TABLE(i2c, ak8975_mod_id);
+MODULE_DEVICE_TABLE(i2c, akm_i2c_device_id);
-static struct i2c_driver ak8975_mod_driver = {
- .class = I2C_CLASS_HWMON,
- .probe = ak8975_mod_probe,
- .remove = ak8975_mod_remove,
- .id_table = ak8975_mod_id,
+static struct i2c_driver akm_driver = {
+ .class = I2C_CLASS_HWMON,
+ .probe = akm_probe,
+ .remove = akm_remove,
.driver = {
- .owner = THIS_MODULE,
- .name = "ak8975_mod",
- },
- .address_list = normal_i2c,
+ .name = AKM_NAME,
+ .owner = THIS_MODULE,
+ },
+ .id_table = akm_i2c_device_id,
+ .shutdown = akm_shutdown,
};
-static int __init ak8975_mod_init(void)
+static int __init akm_init(void)
{
- int res = i2c_add_driver(&ak8975_mod_driver);
- pr_info("%s: Probe name %s\n", __func__, "ak8975_mod");
- if (res)
- pr_err("%s failed\n", __func__);
- return res;
+ return i2c_add_driver(&akm_driver);
}
-static void __exit ak8975_mod_exit(void)
+static void __exit akm_exit(void)
{
- pr_info("%s\n", __func__);
- i2c_del_driver(&ak8975_mod_driver);
+ i2c_del_driver(&akm_driver);
}
-module_init(ak8975_mod_init);
-module_exit(ak8975_mod_exit);
+module_init(akm_init);
+module_exit(akm_exit);
-MODULE_AUTHOR("Invensense Corporation");
-MODULE_DESCRIPTION("Driver for AK8975 sensor with input subsystem");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("ak8975_mod");
+MODULE_DESCRIPTION("AKM driver");
-/**
- * @}
- */
diff --git a/drivers/input/misc/mpu/inv_gyro.c b/drivers/input/misc/mpu/inv_gyro.c
index edee7ab4b47c..cfa76ab46865 100644
--- a/drivers/input/misc/mpu/inv_gyro.c
+++ b/drivers/input/misc/mpu/inv_gyro.c
@@ -35,13 +35,22 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kfifo.h>
+#include <linux/regulator/consumer.h>
#include <linux/byteorder/generic.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
#include <linux/spinlock.h>
+#include <linux/mpu.h>
#include "inv_gyro.h"
+
+/* regulator names in order of powering on */
+static char *nvi_vregs[] = {
+ "vdd",
+ "vlogic",
+};
+
static struct inv_reg_map_s chip_reg = {
.who_am_i = 0x75,
.sample_rate_div = 0x19,
@@ -65,6 +74,7 @@ static struct inv_reg_map_s chip_reg = {
.mem_r_w = 0x6F,
.prgm_strt_addrh = 0x70
};
+
static const struct inv_hw_s hw_info[INV_NUM_PARTS] = {
{119, "ITG3500"},
{ 63, "MPU3050"},
@@ -72,6 +82,25 @@ static const struct inv_hw_s hw_info[INV_NUM_PARTS] = {
{118, "MPU9150"}
};
+static unsigned long nvi_lpf_us_tbl[] = {
+ 3906, /* 256Hz */
+ 5319, /* 188Hz */
+ 10204, /* 98Hz */
+ 23810, /* 42Hz */
+ 50000, /* 20Hz */
+ 100000, /* 10Hz */
+ /* 200000, 5Hz */
+};
+
+static unsigned long nvi_lpa_delay_us_tbl[] = {
+ 800000,
+ 200000,
+ 50000,
+ /* 25000, */
+};
+
+static struct inv_gyro_state_s *inf_local;
+
s64 get_time_ns(void)
{
struct timespec ts;
@@ -94,12 +123,12 @@ int inv_i2c_read_base(struct inv_gyro_state_s *st, unsigned short i2c_addr,
struct i2c_msg msgs[2];
int res;
+ if (st->shutdown)
+ return 0;
+
if (!data)
return -EINVAL;
- if (st->i2c_shutdown)
- return -ENODEV;
-
msgs[0].addr = i2c_addr;
msgs[0].flags = 0; /* write */
msgs[0].buf = &reg;
@@ -110,8 +139,9 @@ int inv_i2c_read_base(struct inv_gyro_state_s *st, unsigned short i2c_addr,
msgs[1].buf = data;
msgs[1].len = length;
- pr_debug("%s RD%02X%02X%02X\n", st->hw->name, i2c_addr, reg, length);
res = i2c_transfer(st->sl_handle, msgs, 2);
+ pr_debug("%s RD%02X%02X%02X res=%d\n",
+ st->hw_s->name, i2c_addr, reg, length, res);
if (res < 2) {
if (res >= 0)
res = -EIO;
@@ -135,8 +165,8 @@ int inv_i2c_single_write_base(struct inv_gyro_state_s *st,
struct i2c_msg msg;
int res;
- if (st->i2c_shutdown)
- return -ENODEV;
+ if (st->shutdown)
+ return 0;
tmp[0] = reg;
tmp[1] = data;
@@ -146,8 +176,9 @@ int inv_i2c_single_write_base(struct inv_gyro_state_s *st,
msg.buf = tmp;
msg.len = 2;
- pr_debug("%s WS%02X%02X%02X\n", st->hw->name, i2c_addr, reg, data);
res = i2c_transfer(st->sl_handle, &msg, 1);
+ pr_debug("%s WS%02X%02X%02X res=%d\n",
+ st->hw_s->name, i2c_addr, reg, data, res);
if (res < 1) {
if (res == 0)
res = -EIO;
@@ -156,1410 +187,2221 @@ int inv_i2c_single_write_base(struct inv_gyro_state_s *st,
return 0;
}
-/**
- * inv_clear_kfifo() - clear time stamp fifo
- * @st: Device driver instance.
- */
-void inv_clear_kfifo(struct inv_gyro_state_s *st)
+
+
+/* Register SMPLRT_DIV (0x19) */
+static int nvi_smplrt_div_wr(struct inv_gyro_state_s *inf,
+ unsigned char smplrt_div)
{
- unsigned long flags;
- spin_lock_irqsave(&st->time_stamp_lock, flags);
- kfifo_reset(&st->trigger.timestamps);
- spin_unlock_irqrestore(&st->time_stamp_lock, flags);
+ int err = 0;
+
+ if (smplrt_div != inf->hw.smplrt_div) {
+ err = inv_i2c_single_write(inf, inf->reg->sample_rate_div,
+ smplrt_div);
+ if (!err)
+ inf->hw.smplrt_div = smplrt_div;
+ }
+ return err;
}
-static int set_power_itg(struct inv_gyro_state_s *st, unsigned char power_on)
+/* Register CONFIG (0x1A) */
+static int nvi_config_wr(struct inv_gyro_state_s *inf, unsigned char lpf)
{
- struct inv_reg_map_s *reg;
- unsigned char data;
- int result;
+ int err = 0;
- reg = st->reg;
- if (power_on)
- data = 0;
- else
- data = BIT_SLEEP;
- data |= (st->chip_config.lpa_mode << 5);
- if (st->chip_config.gyro_enable) {
- result = inv_i2c_single_write(st,
- reg->pwr_mgmt_1, data | INV_CLK_PLL);
- if (result)
- return result;
+ if (lpf != inf->hw.config) {
+ err = inv_i2c_single_write(inf, inf->reg->lpf, lpf);
+ if (!err)
+ inf->hw.config = lpf;
+ }
+ return err;
+}
- st->chip_config.clk_src = INV_CLK_PLL;
- } else {
- result = inv_i2c_single_write(st,
- reg->pwr_mgmt_1, data | INV_CLK_INTERNAL);
- if (result)
- return result;
+/* Register GYRO_CONFIG (0x1B) */
+static int nvi_gyro_config_wr(struct inv_gyro_state_s *inf, unsigned char fsr)
+{
+ unsigned char val;
+ int err = 0;
- st->chip_config.clk_src = INV_CLK_INTERNAL;
+ if (fsr != inf->hw.gyro_config) {
+ val = (fsr << 3);
+ err = inv_i2c_single_write(inf, inf->reg->gyro_config, val);
+ if (!err) {
+ inf->hw.gyro_config = val;
+ err = 1; /* flag change made */
+ }
}
+ return err;
+}
- if (power_on) {
- mdelay(POWER_UP_TIME);
- data = 0;
- if (0 == st->chip_config.accl_enable)
- data |= BIT_PWR_ACCL_STBY;
- if (0 == st->chip_config.gyro_enable)
- data |= BIT_PWR_GYRO_STBY;
- data |= (st->chip_config.lpa_freq << 6);
- result = inv_i2c_single_write(st, reg->pwr_mgmt_2, data);
- if (result)
- return result;
+/* Register ACCEL_CONFIG (0x1C) */
+static int nvi_accel_config_wr(struct inv_gyro_state_s *inf,
+ unsigned char fsr, unsigned char hpf)
+{
+ unsigned char val;
+ int err = 0;
- mdelay(POWER_UP_TIME);
- st->chip_config.is_asleep = 0;
- } else {
- st->chip_config.is_asleep = 1;
+ val = (fsr << 3) | hpf;
+ if (val != inf->hw.accl_config) {
+ err = inv_i2c_single_write(inf, inf->reg->accl_config,
+ val);
+ if (!err) {
+ inf->hw.accl_config = val;
+ err = 1; /* flag change made */
+ if (hpf != 7)
+ inf->mot_enable = false;
+ }
}
- return 0;
+ return err;
}
-/**
- * inv_set_power_state() - Turn device on/off.
- * @st: Device driver instance.
- * @power_on: 1 to turn on, 0 to suspend.
- */
-int inv_set_power_state(struct inv_gyro_state_s *st, unsigned char power_on)
+/* Register MOT_THR (0x1F) */
+static int nvi_mot_thr_wr(struct inv_gyro_state_s *inf, unsigned char mot_thr)
{
- int ret;
- if (!power_on)
- disable_irq(st->trigger.irq);
+ int err = 0;
- if (INV_MPU3050 == st->chip_type)
- ret = set_power_mpu3050(st, power_on);
- else
- ret = set_power_itg(st, power_on);
+ if (mot_thr != inf->hw.mot_thr) {
+ err = inv_i2c_single_write(inf, REG_MOT_THR, mot_thr);
+ if (!err)
+ inf->hw.mot_thr = mot_thr;
+ }
+ return err;
+}
- if (power_on)
- enable_irq(st->trigger.irq);
- return ret;
+/* Register MOT_DUR (0x20) */
+static int nvi_mot_dur_wr(struct inv_gyro_state_s *inf, unsigned char mot_dur)
+{
+ int err = 0;
+
+ if (mot_dur != inf->hw.mot_dur) {
+ err = inv_i2c_single_write(inf, REG_MOT_DUR, mot_dur);
+ if (!err)
+ inf->hw.mot_dur = mot_dur;
+ }
+ return err;
}
-/**
- * reset_fifo_itg() - Reset FIFO related registers.
- * @st: Device driver instance.
- */
-static int reset_fifo_itg(struct inv_gyro_state_s *st)
+/* Register FIFO_EN (0x23) */
+static int nvi_fifo_en_wr(struct inv_gyro_state_s *inf, unsigned char fifo_en)
+{
+ int err = 0;
+
+ if (fifo_en != inf->hw.fifo_en) {
+ err = inv_i2c_single_write(inf, inf->reg->fifo_en, fifo_en);
+ if (!err)
+ inf->hw.fifo_en = fifo_en;
+ }
+ return err;
+}
+
+/* Register I2C_MST_CTRL (0x24) */
+static int nvi_i2c_mst_ctrl_wr(struct inv_gyro_state_s *inf,
+ bool port3_fifo_en)
{
- struct inv_reg_map_s *reg;
- int result;
unsigned char val;
+ int err = 0;
- reg = st->reg;
- /* disable interrupt */
- result = inv_i2c_single_write(st, reg->int_enable, 0);
- if (result) {
- pr_err("%s failed\n", __func__);
- return result;
+ val = inf->aux.clock_i2c;
+ val |= BIT_WAIT_FOR_ES | BIT_I2C_MST_P_NSR;
+ if (port3_fifo_en)
+ val |= BIT_SLV3_FIFO_EN;
+ if (val != inf->hw.i2c_mst_ctrl) {
+ err = inv_i2c_single_write(inf, REG_I2C_MST_CTRL, val);
+ if (!err)
+ inf->hw.i2c_mst_ctrl = val;
}
+ return err;
+}
- /* disable the sensor output to FIFO */
- result = inv_i2c_single_write(st, reg->fifo_en, 0);
- if (result)
- goto reset_fifo_fail;
+/* Register I2C_SLV4_CTRL (0x34) */
+static int nvi_i2c_slv4_ctrl_wr(struct inv_gyro_state_s *inf, bool slv4_en)
+{
+ unsigned char val;
+ int err = 0;
- /* disable fifo reading */
- result = inv_i2c_single_write(st, reg->user_ctrl, 0);
- if (result)
- goto reset_fifo_fail;
+ val = inf->aux.delay_hw;
+ val |= (inf->aux.port[AUX_PORT_SPECIAL].nmp.ctrl &
+ BITS_I2C_SLV_REG_DIS);
+ if (slv4_en)
+ val |= BIT_SLV_EN;
+ if (val != inf->hw.i2c_slv4_ctrl) {
+ err = inv_i2c_single_write(inf, REG_I2C_SLV4_CTRL, val);
+ if (!err)
+ inf->hw.i2c_slv4_ctrl = val;
+ }
+ return err;
+}
- if (st->chip_config.dmp_on) {
- val = (BIT_FIFO_RST | BIT_DMP_RST);
- if (st->chip_config.compass_enable)
- val |= BIT_I2C_MST_RST;
- result = inv_i2c_single_write(st, reg->user_ctrl, val);
- if (result)
- goto reset_fifo_fail;
+/* Register INT_PIN_CFG (0x37) */
+static int nvi_int_pin_cfg_wr(struct inv_gyro_state_s *inf, unsigned char val)
+{
+ int err = 0;
- mdelay(POWER_UP_TIME);
- st->last_isr_time = get_time_ns();
- result = inv_i2c_single_write(st, reg->int_enable,
- BIT_DMP_INT_EN);
- if (result)
- return result;
+ if (val != inf->hw.int_pin_cfg) {
+ err = inv_i2c_single_write(inf, REG_INT_PIN_CFG, val);
+ if (!err)
+ inf->hw.int_pin_cfg = val;
+ }
+ return err;
+}
- val = (BIT_DMP_EN | BIT_FIFO_EN);
- if (st->chip_config.compass_enable)
- val |= BIT_I2C_MST_EN;
- result = inv_i2c_single_write(st, reg->user_ctrl, val);
- if (result)
- goto reset_fifo_fail;
+/* Register INT_ENABLE (0x38) */
+static int nvi_int_enable_wr(struct inv_gyro_state_s *inf, bool enable)
+{
+ unsigned char val = 0;
+ int err = 0;
- } else {
- /* reset FIFO and possibly reset I2C*/
- val = BIT_FIFO_RST;
- if (st->chip_config.compass_enable)
- val |= BIT_I2C_MST_RST;
- result = inv_i2c_single_write(st, reg->user_ctrl, val);
- if (result)
- goto reset_fifo_fail;
-
- mdelay(POWER_UP_TIME);
- st->last_isr_time = get_time_ns();
- /* enable interrupt */
- if (st->chip_config.accl_fifo_enable ||
- st->chip_config.gyro_fifo_enable ||
- st->chip_config.compass_enable){
- result = inv_i2c_single_write(st, reg->int_enable,
- BIT_DATA_RDY_EN);
- if (result)
- return result;
+ if (enable) {
+ if ((inf->hw.user_ctrl & BIT_I2C_MST_EN) ||
+ inf->chip_config.gyro_enable) {
+ val = BIT_DATA_RDY_EN;
+ } else if (inf->chip_config.accl_enable) {
+ if (inf->mot_enable && (!inf->mot_cnt)) {
+ val = BIT_MOT_EN;
+ if (inf->mot_dbg)
+ pr_info("%s motion detect on",
+ __func__);
+ } else {
+ val = BIT_DATA_RDY_EN;
+ }
}
+ }
+ if ((val != inf->hw.int_enable) && (inf->pm > NVI_PM_OFF)) {
+ err = inv_i2c_single_write(inf, inf->reg->int_enable, val);
+ if (!err)
+ inf->hw.int_enable = val;
+ }
+ return err;
+}
- /* enable FIFO reading and I2C master interface*/
- val = BIT_FIFO_EN;
- if (st->chip_config.compass_enable)
- val |= BIT_I2C_MST_EN;
- result = inv_i2c_single_write(st, reg->user_ctrl, val);
- if (result)
- goto reset_fifo_fail;
+/* Register I2C_MST_DELAY_CTRL (0x67) */
+static int nvi_i2c_mst_delay_ctrl_wr(struct inv_gyro_state_s *inf,
+ unsigned char i2c_mst_delay_ctrl)
+{
+ int err = 0;
- /* enable sensor output to FIFO */
- val = 0;
- if (st->chip_config.gyro_fifo_enable)
- val |= BITS_GYRO_OUT;
- if (st->chip_config.accl_fifo_enable)
- val |= BIT_ACCEL_OUT;
- result = inv_i2c_single_write(st, reg->fifo_en, val);
- if (result)
- goto reset_fifo_fail;
+ if (i2c_mst_delay_ctrl != inf->hw.i2c_mst_delay_ctrl) {
+ err = inv_i2c_single_write(inf, REG_I2C_MST_DELAY_CTRL,
+ i2c_mst_delay_ctrl);
+ if (!err)
+ inf->hw.i2c_mst_delay_ctrl = i2c_mst_delay_ctrl;
}
+ return err;
+}
- return 0;
+/* Register MOT_DETECT_CTRL (0x69) */
+static int nvi_mot_detect_ctrl_wr(struct inv_gyro_state_s *inf,
+ unsigned char val)
+{
+ int err = 0;
-reset_fifo_fail:
- if (st->chip_config.dmp_on)
- val = BIT_DMP_INT_EN;
- else
- val = BIT_DATA_RDY_EN;
- inv_i2c_single_write(st, reg->int_enable, val);
- pr_err("%s failed\n", __func__);
- return result;
+ if (val != inf->hw.mot_detect_ctrl) {
+ err = inv_i2c_single_write(inf, REG_MOT_DETECT_CTRL, val);
+ if (!err)
+ inf->hw.mot_detect_ctrl = val;
+ }
+ return err;
}
-/**
- * inv_reset_fifo() - Reset FIFO related registers.
- * @st: Device driver instance.
- */
-int inv_reset_fifo(struct inv_gyro_state_s *st)
+/* Register USER_CTRL (0x6A) */
+static int nvi_user_ctrl_reset_wr(struct inv_gyro_state_s *inf,
+ unsigned char val)
{
- if (INV_MPU3050 == st->chip_type)
- return reset_fifo_mpu3050(st);
- else
- return reset_fifo_itg(st);
+ int i;
+ int err;
+ int err_t;
+
+ err_t = inv_i2c_single_write(inf, inf->reg->user_ctrl, val);
+ for (i = 0; i < POWER_UP_TIME; i++) {
+ val = -1;
+ err = inv_i2c_read(inf, inf->reg->user_ctrl, 1, &val);
+ if (!(val & (BIT_FIFO_RST | BIT_I2C_MST_RST)))
+ break;
+
+ mdelay(1);
+ }
+ err_t |= err;
+ inf->hw.user_ctrl = val;
+ return err_t;
}
-/**
- * set_inv_enable() - Reset FIFO related registers.
- * @st: Device driver instance.
- * @fifo_enable: enable/disable
- */
-int set_inv_enable(struct inv_gyro_state_s *st, unsigned long enable)
+/* Register USER_CTRL (0x6A) */
+static int nvi_user_ctrl_en_wr(struct inv_gyro_state_s *inf,
+ bool fifo_enable, bool i2c_enable)
{
- struct inv_reg_map_s *reg;
- int result;
+ unsigned char val;
+ bool en;
+ int i;
+ int err = 0;
- if (st->chip_config.is_asleep)
- return -EINVAL;
+ if (inf->lpa_enable)
+ fifo_enable = false;
+ val = 0;
+ if (fifo_enable) {
+ for (i = 0; i < (AUX_PORT_SPECIAL - 1); i++) {
+ if (inf->aux.port[i].fifo_en && inf->aux.port[i].hw_en)
+ val |= (1 << i);
+ }
+ if (inf->chip_config.gyro_fifo_enable)
+ val |= (inf->chip_config.gyro_enable << 4);
+ if (inf->chip_config.accl_fifo_enable)
+ val |= BIT_ACCEL_OUT;
+ if (inf->chip_config.temp_fifo_enable)
+ val |= BIT_TEMP_FIFO_EN;
+ if (inf->aux.port[3].fifo_en && inf->aux.port[3].hw_en)
+ en = true;
+ else
+ en = false;
+ err |= nvi_i2c_mst_ctrl_wr(inf, en);
+ if (val || en)
+ en = true;
+ else
+ en = false;
+ } else {
+ err |= nvi_i2c_mst_ctrl_wr(inf, false);
+ en = false;
+ }
+ err |= nvi_fifo_en_wr(inf, val);
+ val = 0;
+ if (fifo_enable && en)
+ val |= BIT_FIFO_EN;
+ if (i2c_enable && inf->aux.enable)
+ val |= BIT_I2C_MST_EN;
+ if (val != inf->hw.user_ctrl) {
+ err |= inv_i2c_single_write(inf, inf->reg->user_ctrl, val);
+ if (!err)
+ inf->hw.user_ctrl = val;
+ }
+ return err;
+}
- reg = st->reg;
- if (enable) {
- result = inv_reset_fifo(st);
- if (result)
- return result;
+/* Register PWR_MGMT_1 (0x6B) */
+static int nvi_pwr_mgmt_1_wr(struct inv_gyro_state_s *inf, unsigned char pm1)
+{
+ unsigned char val;
+ int i;
+ int err;
+
+ for (i = 0; i < POWER_UP_TIME; i++) {
+ inv_i2c_single_write(inf, inf->reg->pwr_mgmt_1, pm1);
+ val = -1;
+ err = inv_i2c_read(inf, inf->reg->pwr_mgmt_1, 1, &val);
+ if (!val)
+ break;
+
+ mdelay(1);
+ }
+ inf->hw.pwr_mgmt_1 = val;
+ return err;
+}
- inv_clear_kfifo(st);
- st->chip_config.enable = 1;
+static bool nvi_lpa_able(struct inv_gyro_state_s *inf)
+{
+ bool lpa_enable;
+ int i;
+ if (inf->mot_enable) {
+ lpa_enable = true;
+ } else if (inf->chip_config.lpa_delay_us) {
+ if (inf->chip_config.accl_delay_us <
+ inf->chip_config.lpa_delay_us)
+ lpa_enable = false;
+ else
+ lpa_enable = true;
} else {
- result = inv_i2c_single_write(st, reg->fifo_en, 0);
- if (result)
- return result;
+ lpa_enable = false;
+ }
+ for (i = 0; i < ARRAY_SIZE(nvi_lpa_delay_us_tbl); i++) {
+ if (inf->chip_config.accl_delay_us >= nvi_lpa_delay_us_tbl[i])
+ break;
+ }
+ inf->lpa_hw = i;
+ return lpa_enable;
+}
- result = inv_i2c_single_write(st, reg->int_enable, 0);
- if (result)
- return result;
+static int nvi_vreg_dis(struct inv_gyro_state_s *inf, unsigned int i)
+{
+ int err = 0;
- /* disable fifo reading */
- if (INV_MPU3050 != st->chip_type) {
- result = inv_i2c_single_write(st, reg->user_ctrl, 0);
- if (result)
- return result;
+ if (inf->vreg[i].ret && (inf->vreg[i].consumer != NULL)) {
+ err = regulator_disable(inf->vreg[i].consumer);
+ if (!err) {
+ inf->vreg[i].ret = 0;
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ } else {
+ dev_err(&inf->i2c->dev, "%s %s ERR\n",
+ __func__, inf->vreg[i].supply);
}
+ }
+ return err;
+}
+
+static int nvi_vreg_dis_all(struct inv_gyro_state_s *inf)
+{
+ unsigned int i;
+ int err = 0;
+
+ for (i = ARRAY_SIZE(nvi_vregs); i > 0; i--)
+ err |= nvi_vreg_dis(inf, (i - 1));
+ return err;
+}
+
+static int nvi_vreg_en(struct inv_gyro_state_s *inf, unsigned int i)
+{
+ int err = 0;
- st->chip_config.enable = 0;
+ if ((!inf->vreg[i].ret) && (inf->vreg[i].consumer != NULL)) {
+ err = regulator_enable(inf->vreg[i].consumer);
+ if (!err) {
+ inf->vreg[i].ret = 1;
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ err = 1; /* flag regulator state change */
+ } else {
+ dev_err(&inf->i2c->dev, "%s %s ERR\n",
+ __func__, inf->vreg[i].supply);
+ }
}
+ return err;
+}
- return 0;
+static int nvi_vreg_en_all(struct inv_gyro_state_s *inf)
+{
+ unsigned i;
+ int err = 0;
+
+ for (i = 0; i < ARRAY_SIZE(nvi_vregs); i++)
+ err |= nvi_vreg_en(inf, i);
+ return err;
}
-static void inv_input_close(struct input_dev *d)
+static void nvi_vreg_exit(struct inv_gyro_state_s *inf)
{
- struct inv_gyro_state_s *st;
+ int i;
- st = input_get_drvdata(d);
- set_inv_enable(st, 0);
- inv_set_power_state(st, 0);
+ for (i = 0; i < ARRAY_SIZE(nvi_vregs); i++) {
+ if (inf->vreg[i].consumer != NULL) {
+ devm_regulator_put(inf->vreg[i].consumer);
+ inf->vreg[i].consumer = NULL;
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ }
+ }
}
-/**
- * inv_setup_input() - internal setup input device.
- * @st: Device driver instance.
- * @**idev_in pointer to input device
- * @*client i2c client
- * @*name name of the input device.
- */
-static int inv_setup_input(struct inv_gyro_state_s *st,
- struct input_dev **idev_in,
- struct i2c_client *client, unsigned char *name)
+static int nvi_vreg_init(struct inv_gyro_state_s *inf)
{
- int result;
- struct input_dev *idev;
+ unsigned int i;
+ int err = 0;
- idev = input_allocate_device();
- if (!idev) {
- result = -ENOMEM;
- return result;
+ for (i = 0; i < ARRAY_SIZE(nvi_vregs); i++) {
+ inf->vreg[i].supply = nvi_vregs[i];
+ inf->vreg[i].ret = 0;
+ inf->vreg[i].consumer = devm_regulator_get(&inf->i2c->dev,
+ inf->vreg[i].supply);
+ if (IS_ERR(inf->vreg[i].consumer)) {
+ err = PTR_ERR(inf->vreg[i].consumer);
+ dev_err(&inf->i2c->dev, "%s ERR %d for %s\n",
+ __func__, err, inf->vreg[i].supply);
+ inf->vreg[i].consumer = NULL;
+ } else {
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ }
}
+ return err;
+}
- /* Setup input device. */
- idev->name = name;
- idev->id.bustype = BUS_I2C;
- idev->id.product = 'S';
- idev->id.vendor = ('I'<<8) | 'S';
- idev->id.version = 1;
- idev->dev.parent = &client->dev;
- /* Open and close method. */
- if (strcmp(name, "INV_DMP") && strcmp(name, "INV_COMPASS"))
- idev->close = inv_input_close;
- input_set_capability(idev, EV_REL, REL_X);
- input_set_capability(idev, EV_REL, REL_Y);
- input_set_capability(idev, EV_REL, REL_Z);
- input_set_capability(idev, EV_REL, REL_RX);
- input_set_capability(idev, EV_REL, REL_RY);
- input_set_capability(idev, EV_REL, REL_RZ);
- input_set_capability(idev, EV_REL, REL_MISC);
- input_set_capability(idev, EV_REL, REL_WHEEL);
- input_set_drvdata(idev, st);
- result = input_register_device(idev);
- if (result)
- input_free_device(idev);
- *idev_in = idev;
- return result;
+static int nvi_pm_wr_on(struct inv_gyro_state_s *inf, u8 pm1, u8 pm2)
+{
+ unsigned char val;
+ int i;
+ int err;
+ int err_t = 0;
+
+ err = nvi_vreg_en_all(inf);
+ if (err) {
+ err_t |= nvi_pwr_mgmt_1_wr(inf, 0);
+ err_t |= inv_i2c_single_write(inf, inf->reg->pwr_mgmt_1,
+ BIT_RESET);
+ for (i = 0; i < POWER_UP_TIME; i++) {
+ val = -1;
+ err = inv_i2c_read(inf, inf->reg->pwr_mgmt_1, 1, &val);
+ if (!(val & BIT_RESET))
+ break;
+
+ mdelay(1);
+ }
+ err_t |= err;
+ err_t |= nvi_pwr_mgmt_1_wr(inf, 0);
+ err_t |= nvi_user_ctrl_reset_wr(inf, (BIT_FIFO_RST |
+ BIT_I2C_MST_RST));
+ for (i = 0; i < AUX_PORT_MAX; i++) {
+ inf->aux.port[i].hw_valid = false;
+ inf->aux.port[i].hw_en = false;
+ }
+ memset(&inf->hw, 0, sizeof(struct nvi_hw));
+ inf->sample_delay_us = 0;
+ inf->mot_enable = false;
+ } else {
+ err_t |= nvi_pwr_mgmt_1_wr(inf, 0);
+ }
+ if (pm2 != inf->hw.pwr_mgmt_2) {
+ err = inv_i2c_single_write(inf, inf->reg->pwr_mgmt_2, pm2);
+ if (err)
+ err_t |= err;
+ else
+ inf->hw.pwr_mgmt_2 = pm2;
+ }
+ if (pm1 != inf->hw.pwr_mgmt_1) {
+ err = inv_i2c_single_write(inf, inf->reg->pwr_mgmt_1, pm1);
+ if (err)
+ err_t |= err;
+ else
+ inf->hw.pwr_mgmt_1 = pm1;
+ }
+ return err_t;
}
-/**
- * inv_init_config() - Initialize hardware, disable FIFO.
- * @st: Device driver instance.
- * Initial configuration:
- * FSR: +/- 2000DPS
- * DLPF: 42Hz
- * FIFO rate: 50Hz
- * Clock source: Gyro PLL
- */
-static int inv_init_config(struct inv_gyro_state_s *st)
+static int nvi_pm_wr(struct inv_gyro_state_s *inf, int pm, int stby)
{
- struct inv_reg_map_s *reg;
- int result;
+ int err = 0;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ if ((pm == inf->pm) && (stby == inf->stby))
+ return err;
- reg = st->reg;
- result = set_inv_enable(st, 0);
- if (result)
- return result;
+ switch (pm) {
+ case NVI_PM_OFF_FORCE:
+ case NVI_PM_OFF:
+ err = nvi_pm_wr_on(inf, BIT_SLEEP, stby);
+ err |= nvi_vreg_dis_all(inf);
+ break;
- result = inv_i2c_single_write(st, reg->gyro_config,
- INV_FSR_2000DPS << 3);
- if (result)
- return result;
+ case NVI_PM_STDBY:
+ err = nvi_pm_wr_on(inf, BIT_SLEEP, stby);
+ break;
- st->chip_config.fsr = INV_FSR_2000DPS;
- result = inv_i2c_single_write(st, reg->lpf, INV_FILTER_42HZ);
- if (result)
- return result;
+ case NVI_PM_ON_CYCLE:
+ err = nvi_pm_wr_on(inf, BIT_CYCLE, stby);
+ break;
- st->chip_config.lpf = INV_FILTER_42HZ;
- result = inv_i2c_single_write(st, reg->sample_rate_div, 19);
- if (result)
- return result;
+ case NVI_PM_ON:
+ err = nvi_pm_wr_on(inf, INV_CLK_INTERNAL, stby);
+ break;
- st->chip_config.fifo_rate = 50;
- st->irq_dur_us = 20*1000;
- st->chip_config.enable = 0;
- st->chip_config.dmp_on = 0;
- st->compass_divider = 0;
- st->compass_counter = 0;
- st->chip_config.compass_enable = 0;
- st->chip_config.firmware_loaded = 0;
- st->chip_config.prog_start_addr = DMP_START_ADDR;
- st->chip_config.gyro_enable = 1;
- st->chip_config.gyro_fifo_enable = 1;
- if (INV_ITG3500 != st->chip_type) {
- st->chip_config.accl_enable = 1;
- st->chip_config.accl_fifo_enable = 1;
- st->chip_config.accl_fs = INV_FS_02G;
- result = inv_i2c_single_write(st, reg->accl_config,
- (INV_FS_02G << 3));
- if (result)
- return result;
+ case NVI_PM_ON_FULL:
+ err = nvi_pm_wr_on(inf, INV_CLK_PLL, stby);
+ break;
- } else {
- st->chip_config.accl_enable = 0;
- st->chip_config.accl_fifo_enable = 0;
+ default:
+ err = -EINVAL;
+ break;
}
- return 0;
+ if (err < 0) {
+ dev_err(&inf->i2c->dev, "%s requested pm=%d ERR=%d\n",
+ __func__, pm, err);
+ pm = NVI_PM_ERR;
+ } else {
+ inf->stby = stby;
+ }
+ inf->pm = pm;
+ dev_dbg(&inf->i2c->dev, "%s pm=%d stby=%x\n", __func__, pm, stby);
+ if (err > 0)
+ err = 0;
+ return err;
}
-/**
- * inv_raw_gyro_show() - Read gyro data directly from registers.
- */
-static ssize_t inv_raw_gyro_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static int nvi_pm(struct inv_gyro_state_s *inf, int pm_req)
{
- struct inv_gyro_state_s *st;
- struct inv_reg_map_s *reg;
- int result;
- unsigned char data[6];
-
- st = dev_get_drvdata(dev);
- reg = st->reg;
- if (st->chip_config.is_asleep)
- return -EPERM;
-
- if (0 == st->chip_config.gyro_enable)
- return -EPERM;
+ bool irq;
+ int stby;
+ int pm;
+ int err;
- result = inv_i2c_read(st, reg->raw_gyro, 6, data);
- if (result) {
- printk(KERN_ERR "Could not read raw registers.\n");
- return result;
+ nvi_int_enable_wr(inf, false);
+ inf->lpa_enable = false;
+ if ((pm_req == NVI_PM_OFF_FORCE) || (pm_req == NVI_PM_OFF)) {
+ stby = 0x3F;
+ pm = NVI_PM_OFF_FORCE;
+ } else {
+ stby = ((~inf->chip_config.accl_enable) & 0x07) << 3;
+ stby |= (~inf->chip_config.gyro_enable) & 0x07;
+ if (inf->chip_config.gyro_enable ||
+ (inf->hw.user_ctrl & BIT_I2C_MST_EN)) {
+ if (inf->chip_config.gyro_enable)
+ pm = NVI_PM_ON_FULL;
+ else
+ pm = NVI_PM_ON;
+ } else if (inf->chip_config.accl_enable) {
+ if (nvi_lpa_able(inf)) {
+ inf->lpa_enable = true;
+ stby |= (inf->lpa_hw << 6);
+ pm = NVI_PM_ON_CYCLE;
+ } else {
+ pm = NVI_PM_ON;
+ }
+ } else if (inf->chip_config.enable || inf->aux.bypass_lock) {
+ pm = NVI_PM_STDBY;
+ } else {
+ pm = NVI_PM_OFF;
+ }
+ }
+ if (pm_req > pm)
+ pm = pm_req;
+ err = nvi_pm_wr(inf, pm, stby);
+ if (pm_req == NVI_PM_AUTO) {
+ nvi_user_ctrl_en_wr(inf, true, true);
+ irq = true;
+ } else {
+ irq = false;
}
+ nvi_int_enable_wr(inf, irq);
+ return err;
+}
- return sprintf(buf, "%d %d %d %lld\n",
- (signed short)(be16_to_cpup((short *)&data[0])),
- (signed short)(be16_to_cpup((short *)&data[2])),
- (signed short)(be16_to_cpup((short *)&data[4])),
- get_time_ns());
+static void nvi_pm_exit(struct inv_gyro_state_s *inf)
+{
+ nvi_pm(inf, NVI_PM_OFF_FORCE);
+ nvi_vreg_exit(inf);
}
-/**
- * inv_raw_accl_show() - Read accel data directly from registers.
- */
-static ssize_t inv_raw_accl_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static int nvi_pm_init(struct inv_gyro_state_s *inf)
{
- struct inv_gyro_state_s *st;
- struct inv_reg_map_s *reg;
- int result;
- unsigned char data[6];
+ int err = 0;
- st = dev_get_drvdata(dev);
- reg = st->reg;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ nvi_vreg_init(inf);
+ inf->pm = NVI_PM_ERR;
+ inf->stby = 0;
+ err = nvi_pm(inf, NVI_PM_ON_FULL);
+ return err;
+}
- if (0 == st->chip_config.accl_enable)
- return -EPERM;
+static int nvi_motion_detect_enable(struct inv_gyro_state_s *inf, u8 mot_thr)
+{
+ int err;
+ int err_t = 0;
+
+ if (mot_thr) {
+ err = nvi_accel_config_wr(inf, inf->chip_config.accl_fsr, 0);
+ if (err < 0)
+ err_t |= err;
+ err_t |= nvi_config_wr(inf, 0);
+ if (!inf->hw.mot_dur)
+ err_t |= nvi_mot_dur_wr(inf, 1);
+ err_t |= nvi_mot_detect_ctrl_wr(inf, inf->chip_config.mot_ctrl);
+ err_t |= nvi_mot_thr_wr(inf, mot_thr);
+ mdelay(5);
+ err = nvi_accel_config_wr(inf, inf->chip_config.accl_fsr, 7);
+ if (err < 0)
+ err_t |= err;
+ if (!err_t)
+ inf->mot_enable = true;
+ } else {
+ err = nvi_accel_config_wr(inf, inf->chip_config.accl_fsr, 0);
+ if (err < 0)
+ err_t |= err;
+ }
+ return err_t;
+}
- result = inv_i2c_read(st, reg->raw_accl, 6, data);
- if (result) {
- printk(KERN_ERR "Could not read raw registers.\n");
- return result;
+static int nvi_aux_delay(struct inv_gyro_state_s *inf,
+ int port, unsigned int delay_ms)
+{
+ unsigned char val;
+ unsigned char i;
+ unsigned int ms;
+ unsigned int delay_new;
+ int delay_rtn;
+ int err;
+
+ if (port != AUX_PORT_BYPASS)
+ inf->aux.port[port].nmp.delay_ms = delay_ms;
+ /* determine valid delays by ports enabled */
+ delay_new = 0;
+ delay_rtn = 0;
+ for (i = 0; i < AUX_PORT_MAX; i++) {
+ if (delay_rtn < inf->aux.port[i].nmp.delay_ms)
+ delay_rtn = inf->aux.port[i].nmp.delay_ms;
+ if (inf->aux.port[i].hw_en) {
+ if (delay_new < inf->aux.port[i].nmp.delay_ms)
+ delay_new = inf->aux.port[i].nmp.delay_ms;
+ }
+ }
+ if (!(inf->hw.user_ctrl & BIT_I2C_MST_EN)) {
+ /* delay will execute when re-enabled */
+ if (delay_ms)
+ return delay_rtn;
+ else
+ return 0;
}
- return sprintf(buf, "%d %d %d %lld\n",
- ((signed short)(be16_to_cpup((short *)&data[0]))*
- st->chip_info.multi),
- ((signed short)(be16_to_cpup((short *)&data[2]))*
- st->chip_info.multi),
- ((signed short)(be16_to_cpup((short *)&data[4]))*
- st->chip_info.multi),
- get_time_ns());
+ /* HW global delay */
+ for (i = 1; i < (BITS_I2C_MST_DLY - 1); i++) {
+ ms = (inf->sample_delay_us - (inf->sample_delay_us /
+ (i + 1))) * 1000;
+ if (ms >= delay_new)
+ break;
+ }
+ inf->aux.delay_hw = i;
+ err = nvi_i2c_slv4_ctrl_wr(inf, inf->aux.port[AUX_PORT_SPECIAL].hw_en);
+ /* HW port delay enable */
+ val = BIT_DELAY_ES_SHADOW;
+ for (i = 0; i < AUX_PORT_MAX; i++) {
+ if (inf->aux.port[i].nmp.delay_ms)
+ val |= (1 << i);
+ }
+ nvi_i2c_mst_delay_ctrl_wr(inf, val);
+ if (delay_ms)
+ return delay_rtn;
+ else
+ return 0;
}
-/**
- * inv_temperature_show() - Read temperature data directly from registers.
- */
-static ssize_t inv_temperature_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static int nvi_global_delay(struct inv_gyro_state_s *inf)
{
- struct inv_gyro_state_s *st;
- struct inv_reg_map_s *reg;
- int result;
- unsigned char data[2];
+ unsigned long delay_us;
+ unsigned long delay_min;
+ unsigned char val;
+ int i;
+ int err = 0;
- st = dev_get_drvdata(dev);
- reg = st->reg;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ /* find the fastest polling of all the devices */
+ delay_us = -1;
+ for (i = 0; i < AUX_PORT_MAX; i++) {
+ if (inf->aux.port[i].enable && inf->aux.port[i].nmp.delay_us) {
+ if (inf->aux.port[i].nmp.delay_us < delay_us)
+ delay_us = inf->aux.port[i].nmp.delay_us;
+ }
+ }
+ if (inf->chip_config.gyro_enable && inf->chip_config.gyro_delay_us) {
+ if (inf->chip_config.gyro_delay_us < delay_us)
+ delay_us = inf->chip_config.gyro_delay_us;
+ }
+ if (inf->chip_config.accl_enable && inf->chip_config.accl_delay_us) {
+ if (inf->chip_config.accl_delay_us < delay_us)
+ delay_us = inf->chip_config.accl_delay_us;
+ }
+ if (delay_us == -1)
+ delay_us = NVI_DELAY_DEFAULT; /* default if nothing found */
+ /* find what the fastest the external devices will let MPU go */
+ delay_min = 0;
+ for (i = 0; i < AUX_PORT_MAX; i++) {
+ if (inf->aux.port[i].enable) {
+ if (inf->aux.port[i].nmp.delay_ms > delay_min)
+ delay_min = inf->aux.port[i].nmp.delay_ms;
+ }
+ }
+ if (!delay_min)
+ /* default if nothing found */
+ delay_min = inf->chip_config.min_delay_us;
+ else
+ delay_min *= 1000L; /* ms => us */
+ /* set the limits */
+ if (delay_us < delay_min)
+ delay_us = delay_min;
+ if (delay_us > MAX_FIFO_RATE)
+ delay_us = MAX_FIFO_RATE;
+ /* program if new value */
+ if (delay_us != inf->sample_delay_us) {
+ dev_dbg(&inf->i2c->dev, "%s %lu\n", __func__, delay_us);
+ inf->sample_delay_us = delay_us;
+ inf->irq_dur_us = delay_us;
+ delay_us <<= 1;
+ for (val = 1; val < ARRAY_SIZE(nvi_lpf_us_tbl); val++) {
+ if (delay_us < nvi_lpf_us_tbl[val])
+ break;
+ }
+ err |= nvi_config_wr(inf, val);
+ if (val)
+ delay_min = 1000;
+ else
+ delay_min = 8000;
+ val = inf->sample_delay_us / delay_min - 1;
+ err |= nvi_smplrt_div_wr(inf, val);
+ inf->last_isr_time = get_time_ns();
+ }
+ nvi_aux_delay(inf, AUX_PORT_BYPASS, 0);
+ return err;
+}
- result = inv_i2c_read(st, reg->temperature, 2, data);
- if (result) {
- printk(KERN_ERR "Could not read temperature register.\n");
- return result;
+static void nvi_aux_dbg(struct inv_gyro_state_s *inf, char *tag, int val)
+{
+ struct nvi_mpu_port *n;
+ struct aux_port *p;
+ struct aux_ports *a;
+ unsigned char data[4];
+ int i;
+
+ if (!inf->aux.dbg)
+ return;
+
+ pr_info("%s %s %d\n", __func__, tag, val);
+ for (i = 0; i < AUX_PORT_MAX; i++) {
+ inv_i2c_read(inf, (REG_I2C_SLV0_ADDR + (i * 3)), 3, data);
+ inv_i2c_read(inf, (REG_I2C_SLV0_DO + i), 1, &data[3]);
+ pr_info("PT=%d AD=%x RG=%x CL=%x DO=%x\n",
+ i, data[0], data[1], data[2], data[3]);
+ n = &inf->aux.port[i].nmp;
+ pr_info("PT=%d AD=%x RG=%x CL=%x DO=%x MS=%u US=%lu SB=%x\n",
+ i, n->addr, n->reg, n->ctrl, n->data_out, n->delay_ms,
+ n->delay_us, n->shutdown_bypass);
+ p = &inf->aux.port[i];
+ pr_info("PT=%d OF=%u EN=%x FE=%x HE=%x HD=%x HV=%x NS=%lld\n",
+ i, p->ext_data_offset, p->enable, p->fifo_en, p->hw_en,
+ p->hw_do, p->hw_valid, p->delay_ns);
+ }
+ a = &inf->aux;
+ pr_info("EN=%x GE=%x MD=%x GD=%lu DN=%u BE=%x BL=%d SB=%d\n",
+ a->enable, (inf->hw.user_ctrl & BIT_I2C_MST_EN),
+ (inf->hw.i2c_slv4_ctrl & BITS_I2C_MST_DLY),
+ inf->sample_delay_us, a->ext_data_n,
+ (inf->hw.int_pin_cfg & BIT_BYPASS_EN), a->bypass_lock,
+ atomic_read(&inf->mutex.count));
+}
+
+static void nvi_aux_read(struct inv_gyro_state_s *inf)
+{
+ struct aux_port *ap;
+ long long timestamp1;
+ long long timestamp2;
+ unsigned int i;
+ unsigned int len;
+ u8 *p;
+ int err;
+
+ if ((inf->aux.ext_data_n == 0) ||
+ (!(inf->hw.user_ctrl & BIT_I2C_MST_EN)))
+ return;
+
+ timestamp1 = get_time_ns();
+ err = inv_i2c_read(inf, REG_EXT_SENS_DATA_00,
+ inf->aux.ext_data_n,
+ (unsigned char *)&inf->aux.ext_data);
+ if (err)
+ return;
+
+ timestamp2 = get_time_ns();
+ timestamp1 = timestamp1 + ((timestamp2 - timestamp1) / 2);
+ for (i = 0; i < AUX_PORT_SPECIAL; i++) {
+ ap = &inf->aux.port[i];
+ if ((ap->nmp.addr & BIT_I2C_READ) &&
+ (ap->nmp.handler != NULL)) {
+ if ((unsigned long)(timestamp2 - ap->delay_ns)
+ >= (ap->nmp.delay_us * 1000)) {
+ ap->delay_ns = timestamp2;
+ p = &inf->aux.ext_data[ap->ext_data_offset];
+ len = ap->nmp.ctrl & BITS_I2C_SLV_CTRL_LEN;
+ ap->nmp.handler(p, len, timestamp1,
+ ap->nmp.ext_driver);
+ }
+ }
}
+}
- return sprintf(buf, "%d %lld\n",
- (signed short)(be16_to_cpup((short *)&data[0])),
- get_time_ns());
+static void nvi_aux_ext_data_offset(struct inv_gyro_state_s *inf)
+{
+ int i;
+ unsigned short offset;
+
+ offset = 0;
+ for (i = 0; i < AUX_PORT_SPECIAL; i++) {
+ if ((inf->aux.port[i].hw_en) && (inf->aux.port[i].nmp.addr &
+ BIT_I2C_READ)) {
+ inf->aux.port[i].ext_data_offset = offset;
+ offset += (inf->aux.port[i].nmp.ctrl &
+ BITS_I2C_SLV_CTRL_LEN);
+ }
+ }
+ if (offset > AUX_EXT_DATA_REG_MAX) {
+ offset = AUX_EXT_DATA_REG_MAX;
+ dev_err(&inf->i2c->dev,
+ "%s ERR MPU slaves exceed data storage\n", __func__);
+ }
+ inf->aux.ext_data_n = offset;
+ return;
}
-static int inv_set_lpf(struct inv_gyro_state_s *st, int rate)
+static int nvi_aux_port_do(struct inv_gyro_state_s *inf,
+ int port, u8 data_out)
{
- short hz[6] = {188, 98, 42, 20, 10, 5};
- int d[6] = {INV_FILTER_188HZ, INV_FILTER_98HZ,
- INV_FILTER_42HZ, INV_FILTER_20HZ,
- INV_FILTER_10HZ, INV_FILTER_5HZ};
- int i, h, data, result;
- struct inv_reg_map_s *reg;
+ unsigned char reg;
+ int err;
- reg = st->reg;
- h = (rate >> 1);
- i = 0;
- while ((h < hz[i]) && (i < 6))
- i++;
- data = d[i];
- if (INV_MPU3050 == st->chip_type) {
- if (st->mpu_slave != NULL) {
- result = st->mpu_slave->set_lpf(st, rate);
- if (result)
- return result;
- }
+ if (port == AUX_PORT_SPECIAL)
+ reg = REG_I2C_SLV4_DO;
+ else
+ reg = (REG_I2C_SLV0_DO + port);
+ err = inv_i2c_single_write(inf, reg, data_out);
+ return err;
+}
- result = inv_i2c_single_write(st, reg->lpf,
- data | (st->chip_config.fsr << 3));
+static int nvi_aux_port_data_out(struct inv_gyro_state_s *inf,
+ int port, u8 data_out)
+{
+ int err;
+ err = nvi_aux_port_do(inf, port, data_out);
+ if (!err) {
+ inf->aux.port[port].nmp.data_out = data_out;
+ inf->aux.port[port].hw_do = true;
} else {
- result = inv_i2c_single_write(st, reg->lpf, data);
+ inf->aux.port[port].hw_do = false;
}
+ return err;
+}
- if (result)
- return result;
+static int nvi_aux_port_wr(struct inv_gyro_state_s *inf, int port)
+{
+ struct aux_port *ap;
+ int err;
- st->chip_config.lpf = data;
- return 0;
+ ap = &inf->aux.port[port];
+ err = inv_i2c_single_write(inf, (REG_I2C_SLV0_ADDR + (port * 3)),
+ ap->nmp.addr);
+ err |= inv_i2c_single_write(inf, (REG_I2C_SLV0_REG + (port * 3)),
+ ap->nmp.reg);
+ err |= nvi_aux_port_do(inf, port, ap->nmp.data_out);
+ return err;
}
-/**
- * inv_fifo_rate_store() - Set fifo rate.
- */
-static ssize_t inv_fifo_rate_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int nvi_aux_port_en(struct inv_gyro_state_s *inf,
+ int port, bool en)
{
- unsigned long fifo_rate;
- unsigned char data;
- int result;
- struct inv_gyro_state_s *st;
- struct inv_reg_map_s *reg;
+ struct aux_port *ap;
+ unsigned char reg;
+ unsigned char val;
+ int err = 0;
- st = dev_get_drvdata(dev);
- reg = st->reg;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ inf->aux.ext_data_n = 0;
+ ap = &inf->aux.port[port];
+ if ((!ap->hw_valid) && en) {
+ err = nvi_aux_port_wr(inf, port);
+ if (!err) {
+ ap->hw_valid = true;
+ ap->hw_do = true;
+ }
+ }
+ if ((!ap->hw_do) && en)
+ nvi_aux_port_data_out(inf, port, ap->nmp.data_out);
+ if (port == AUX_PORT_SPECIAL) {
+ err = nvi_i2c_slv4_ctrl_wr(inf, en);
+ } else {
+ reg = (REG_I2C_SLV0_CTRL + (port * 3));
+ if (en)
+ val = (ap->nmp.ctrl | BIT_SLV_EN);
+ else
+ val = 0;
+ err = inv_i2c_single_write(inf, reg, val);
+ }
+ if (!err) {
+ ap->hw_en = en;
+ nvi_aux_ext_data_offset(inf);
+ }
+ return err;
+}
- if (kstrtoul(buf, 10, &fifo_rate))
- return -EINVAL;
+static int nvi_aux_enable(struct inv_gyro_state_s *inf, bool enable)
+{
+ bool en;
+ unsigned int i;
+ int err;
- if ((fifo_rate < MIN_FIFO_RATE) || (fifo_rate > MAX_FIFO_RATE))
- return -EINVAL;
+ if (inf->hw.int_pin_cfg & BIT_BYPASS_EN)
+ enable = false;
- if (fifo_rate == st->chip_config.fifo_rate)
- return count;
-
- if (st->has_compass) {
- data = 10*fifo_rate/ONE_K_HZ;
- if (data > 0)
- data -= 1;
- st->compass_divider = data;
- st->compass_counter = 0;
- /* I2C_MST_DLY is set according to sample rate,
- AKM cannot be read or set at sample rate higher than 100Hz*/
- result = inv_i2c_single_write(st, REG_I2C_SLV4_CTRL, data);
- if (result)
- return result;
+ en = false;
+ if (enable) {
+ /* global enable is honored only if a port is enabled */
+ for (i = 0; i < AUX_PORT_MAX; i++) {
+ if (inf->aux.port[i].enable) {
+ en = true;
+ break;
+ }
+ }
+ if (en == (inf->hw.user_ctrl & BIT_I2C_MST_EN)) {
+ /* if already on then just update delays */
+ nvi_global_delay(inf);
+ }
}
+ inf->aux.enable = en;
+ if ((inf->hw.user_ctrl & BIT_I2C_MST_EN) == en)
+ return 0;
- data = ONE_K_HZ / fifo_rate - 1;
- result = inv_i2c_single_write(st, reg->sample_rate_div, data);
- if (result)
- return result;
-
- st->chip_config.fifo_rate = fifo_rate;
- result = inv_set_lpf(st, fifo_rate);
- if (result)
- return result;
-
- st->irq_dur_us = (data + 1) * ONE_K_HZ;
- st->last_isr_time = get_time_ns();
- return count;
+ if (en) {
+ for (i = 0; i < AUX_PORT_MAX; i++) {
+ if (inf->aux.port[i].enable)
+ err |= nvi_aux_port_en(inf, i, true);
+ }
+ nvi_motion_detect_enable(inf, 0);
+ } else {
+ for (i = 0; i < AUX_PORT_MAX; i++) {
+ if (inf->aux.port[i].hw_valid)
+ nvi_aux_port_en(inf, i, false);
+ }
+ }
+ err = nvi_global_delay(inf);
+ err |= nvi_user_ctrl_en_wr(inf, true, en);
+ return err;
}
-/**
- * inv_power_state_store() - Turn device on/off.
- */
-static ssize_t inv_power_state_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int nvi_aux_port_enable(struct inv_gyro_state_s *inf,
+ int port, bool enable, bool fifo_enable)
{
- int result;
- unsigned long power_state;
- struct inv_gyro_state_s *st;
+ struct aux_port *ap;
+ int err;
- st = dev_get_drvdata(dev);
- if (kstrtoul(buf, 10, &power_state))
- return -EINVAL;
-
- if (!power_state == st->chip_config.is_asleep)
- return count;
+ ap = &inf->aux.port[port];
+ ap->enable = enable;
+ ap->fifo_en = false;
+ if (enable && (inf->hw.int_pin_cfg & BIT_BYPASS_EN))
+ return 0;
- result = inv_set_power_state(st, power_state);
- return count;
+ err = nvi_aux_port_en(inf, port, enable);
+ err |= nvi_aux_enable(inf, true);
+ return err;
}
-/**
- * inv_enable_store() - Enable/disable chip operation.
- */
-static ssize_t inv_enable_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int nvi_reset(struct inv_gyro_state_s *inf,
+ bool reset_fifo, bool reset_i2c)
{
- unsigned long enable;
- struct inv_gyro_state_s *st;
- int result;
+ unsigned long flags;
+ unsigned char val;
+ int i;
+ int err;
+
+ err = nvi_int_enable_wr(inf, false);
+ val = 0;
+ if (reset_i2c) {
+ /* nvi_aux_bypass_enable(inf, false)? */
+ err |= nvi_aux_enable(inf, false);
+ for (i = 0; i < AUX_PORT_MAX; i++) {
+ inf->aux.port[i].hw_valid = false;
+ inf->aux.port[i].hw_en = false;
+ }
+ inf->aux.need_reset = false;
+ val |= BIT_I2C_MST_RST;
+ }
+ if (reset_fifo)
+ val |= BIT_FIFO_RST;
+ err |= nvi_user_ctrl_en_wr(inf, ~reset_fifo, ~reset_i2c);
+ val |= inf->hw.user_ctrl;
+ err |= nvi_user_ctrl_reset_wr(inf, val);
+ if (reset_fifo) {
+ spin_lock_irqsave(&inf->time_stamp_lock, flags);
+ kfifo_reset(&inf->trigger.timestamps);
+ spin_unlock_irqrestore(&inf->time_stamp_lock, flags);
+ inf->last_isr_time = get_time_ns();
+ }
+ if (reset_i2c)
+ err |= nvi_aux_enable(inf, true);
+ else
+ err |= nvi_user_ctrl_en_wr(inf, true, true);
+ err |= nvi_int_enable_wr(inf, true);
+ return err;
+}
- st = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EPERM;
+static int nvi_aux_port_free(struct inv_gyro_state_s *inf, int port)
+{
+ bool hw_valid;
+ int err = 0;
- if (kstrtoul(buf, 10, &enable))
- return -EINVAL;
+ hw_valid = inf->aux.port[port].hw_valid;
+ memset(&inf->aux.port[port], 0, sizeof(struct aux_port));
+ if (hw_valid) {
+ nvi_aux_port_wr(inf, port);
+ nvi_aux_port_en(inf, port, false);
+ nvi_aux_enable(inf, false);
+ nvi_aux_enable(inf, true);
+ if (port != AUX_PORT_SPECIAL)
+ inf->aux.need_reset = true;
+ }
+ return err;
+}
- if (!enable == !st->chip_config.enable)
- return count;
+static int nvi_aux_port_alloc(struct inv_gyro_state_s *inf,
+ struct nvi_mpu_port *nmp, int port)
+{
+ int i;
- result = set_inv_enable(st, enable);
- if (result)
- return result;
+ if (inf->aux.need_reset)
+ nvi_reset(inf, false, true);
+ if (port < 0) {
+ for (i = 0; i < AUX_PORT_SPECIAL; i++) {
+ if (inf->aux.port[i].nmp.addr == 0)
+ break;
+ }
+ if (i == AUX_PORT_SPECIAL)
+ return -ENODEV;
+ } else {
+ if (inf->aux.port[port].nmp.addr == 0)
+ i = port;
+ else
+ return -ENODEV;
+ }
- return count;
+ memset(&inf->aux.port[i], 0, sizeof(struct aux_port));
+ memcpy(&inf->aux.port[i].nmp, nmp, sizeof(struct nvi_mpu_port));
+ return i;
}
-/**
- * inv_accl_fifo_enable_store() - Enable/disable accl fifo output.
- */
-static ssize_t inv_accl_fifo_enable_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int nvi_aux_bypass_enable(struct inv_gyro_state_s *inf, bool enable)
{
- unsigned long data, en;
- int result;
- struct inv_gyro_state_s *st;
+ unsigned char val;
+ int err;
- st = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EPERM;
+ if ((bool)(inf->hw.int_pin_cfg & BIT_BYPASS_EN) == enable)
+ return 0;
- if (st->chip_config.enable)
- return -EPERM;
+ val = inf->hw.int_pin_cfg;
+ if (enable) {
+ err = nvi_aux_enable(inf, false);
+ if (!err) {
+ val |= BIT_BYPASS_EN;
+ err = nvi_int_pin_cfg_wr(inf, val);
+ }
+ } else {
+ val &= ~BIT_BYPASS_EN;
+ err = nvi_int_pin_cfg_wr(inf, val);
+ if (!err)
+ nvi_aux_enable(inf, true);
+ }
+ return err;
+}
- result = kstrtoul(buf, 10, &data);
- if (result)
- return -EINVAL;
+static int nvi_aux_bypass_request(struct inv_gyro_state_s *inf, bool enable)
+{
+ int err = 0;
- if (data)
- en = 1;
- else
- en = 0;
- if (en == st->chip_config.accl_fifo_enable)
- return count;
+ if ((bool)(inf->hw.int_pin_cfg & BIT_BYPASS_EN) == enable) {
+ inf->aux.bypass_lock++;
+ } else {
+ if (inf->aux.bypass_lock) {
+ err = -EBUSY;
+ } else {
+ err = nvi_aux_bypass_enable(inf, enable);
+ if (err)
+ dev_err(&inf->i2c->dev, "%s ERR=%d\n",
+ __func__, err);
+ else
+ inf->aux.bypass_lock++;
+ }
+ }
+ return err;
+}
- if (en && (0 == st->chip_config.accl_enable)) {
- result = inv_set_power_state(st, 0);
- if (result)
- return result;
+static int nvi_aux_bypass_release(struct inv_gyro_state_s *inf)
+{
+ int err;
- st->chip_config.accl_enable = en;
- result = inv_set_power_state(st, 1);
- if (result)
- return result;
+ if (inf->aux.bypass_lock)
+ inf->aux.bypass_lock--;
+ if (!inf->aux.bypass_lock) {
+ err = nvi_aux_bypass_enable(inf, false);
+ if (err)
+ dev_err(&inf->i2c->dev, "%s ERR=%d\n", __func__, err);
}
-
- st->chip_config.accl_fifo_enable = en;
- return count;
+ return 0;
}
-/**
- * inv_gyro_fifo_enable_store() - Enable/disable gyro fifo output.
- */
-ssize_t inv_gyro_fifo_enable_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int nvi_aux_dev_valid(struct inv_gyro_state_s *inf,
+ struct nvi_mpu_port *nmp, u8 *data)
{
- unsigned long data, en;
- int result;
- struct inv_gyro_state_s *st;
+ unsigned char val;
+ int i;
+ int err;
+
+ /* turn off bypass */
+ err = nvi_aux_bypass_request(inf, false);
+ if (err)
+ return -EBUSY;
+
+ /* grab the special port */
+ err = nvi_aux_port_alloc(inf, nmp, AUX_PORT_SPECIAL);
+ if (err != AUX_PORT_SPECIAL) {
+ nvi_aux_bypass_release(inf);
+ return -EBUSY;
+ }
- st = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EPERM;
+ /* enable it */
+ inf->aux.port[AUX_PORT_SPECIAL].nmp.delay_ms = 0;
+ err = nvi_aux_port_enable(inf, AUX_PORT_SPECIAL, true, false);
+ if (err) {
+ nvi_aux_port_free(inf, AUX_PORT_SPECIAL);
+ nvi_aux_bypass_release(inf);
+ return -EBUSY;
+ }
- if (st->chip_config.enable)
- return -EPERM;
+ /* now turn off all the other ports for fastest response */
+ for (i = 0; i < AUX_PORT_SPECIAL; i++) {
+ if (inf->aux.port[i].hw_valid)
+ nvi_aux_port_en(inf, i, false);
+ }
+ /* start reading the results */
+ for (i = 0; i < AUX_DEV_VALID_READ_MAX; i++) {
+ mdelay(1);
+ val = 0;
+ err = inv_i2c_read(inf, REG_I2C_MST_STATUS, 1, &val);
+ if (err)
+ continue;
- result = kstrtoul(buf, 10, &data);
- if (result)
- return -EINVAL;
+ if (val & 0x50)
+ break;
+ }
+ /* these will restore all previously disabled ports */
+ nvi_aux_bypass_release(inf);
+ nvi_aux_port_free(inf, AUX_PORT_SPECIAL);
+ if (i == AUX_DEV_VALID_READ_MAX)
+ return -ENODEV;
- if (data)
- en = 1;
- else
- en = 0;
- if (en == st->chip_config.gyro_fifo_enable)
- return count;
+ if (val & 0x10) /* NACK */
+ return -EIO;
- if (en && (0 == st->chip_config.gyro_enable)) {
- result = inv_set_power_state(st, 0);
- if (result)
- return result;
+ if (nmp->addr & BIT_I2C_READ) {
+ err = inv_i2c_read(inf, REG_I2C_SLV4_DI, 1, &val);
+ if (err)
+ return -EBUSY;
- st->chip_config.gyro_enable = en;
- result = inv_set_power_state(st, 1);
- if (result)
- return result;
+ *data = (u8)val;
+ dev_info(&inf->i2c->dev, "%s MPU read 0x%x from device 0x%x\n",
+ __func__, val, (nmp->addr & ~BIT_I2C_READ));
+ } else {
+ dev_info(&inf->i2c->dev, "%s MPU found device 0x%x\n",
+ __func__, (nmp->addr & ~BIT_I2C_READ));
}
-
- st->chip_config.gyro_fifo_enable = en;
- return count;
+ return 0;
}
-/**
- * inv_gyro_enable_store() - Enable/disable gyro.
- */
-ssize_t inv_gyro_enable_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int nvi_aux_mpu_call_pre(struct inv_gyro_state_s *inf, int port)
{
- unsigned long data, en;
- struct inv_gyro_state_s *st;
- int result;
-
- st = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EPERM;
+ if ((port < 0) || (port >= AUX_PORT_SPECIAL))
+ return -EINVAL;
- if (st->chip_config.enable)
+ if (inf->shutdown)
return -EPERM;
- result = kstrtoul(buf, 10, &data);
- if (result)
+ if (!inf->aux.port[port].nmp.addr)
return -EINVAL;
- if (data)
- en = 1;
- else
- en = 0;
- if (en == st->chip_config.gyro_enable)
- return count;
-
- if (0 == en)
- st->chip_config.gyro_fifo_enable = 0;
- result = inv_set_power_state(st, 0);
- if (result)
- return result;
-
- st->chip_config.gyro_enable = en;
- result = inv_set_power_state(st, 1);
- if (result) {
- st->chip_config.gyro_enable ^= 1;
- return result;
- }
+ mutex_lock(&inf->mutex);
+ return 0;
+}
- return count;
+static int nvi_aux_mpu_call_post(struct inv_gyro_state_s *inf,
+ char *tag, int err)
+{
+ if (err < 0)
+ err = -EBUSY;
+ mutex_unlock(&inf->mutex);
+ nvi_aux_dbg(inf, tag, err);
+ return err;
}
-/**
- * inv_accl_enable_store() - Enable/disable accl.
+/* See the mpu.h file for details on the nvi_mpu_ calls.
*/
-static ssize_t inv_accl_enable_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+int nvi_mpu_dev_valid(struct nvi_mpu_port *nmp, u8 *data)
{
- unsigned long data, en;
- struct inv_gyro_state_s *st;
- int result;
-
- st = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EPERM;
+ struct inv_gyro_state_s *inf;
+ int err;
- if (st->chip_config.enable)
- return -EPERM;
+ inf = inf_local;
+ if (inf != NULL) {
+ if (inf->aux.dbg)
+ pr_info("%s\n", __func__);
+ } else {
+ pr_debug("%s\n", __func__);
+ return -EAGAIN;
+ }
- result = kstrtoul(buf, 10, &data);
- if (result)
+ if (nmp == NULL)
return -EINVAL;
- if (data)
- en = 1;
- else
- en = 0;
- if (en == st->chip_config.accl_enable)
- return count;
-
- if (0 == en)
- st->chip_config.accl_fifo_enable = 0;
- result = inv_set_power_state(st, 0);
- if (result)
- return result;
+ if ((nmp->addr & BIT_I2C_READ) && (data == NULL))
+ return -EINVAL;
- st->chip_config.accl_enable = en;
- result = inv_set_power_state(st, 1);
- if (result) {
- st->chip_config.accl_enable ^= 1;
- return result;
- }
+ if (inf->shutdown)
+ return -EPERM;
- return count;
+ mutex_lock(&inf->mutex);
+ nvi_pm(inf, NVI_PM_ON);
+ err = nvi_aux_dev_valid(inf, nmp, data);
+ nvi_pm(inf, NVI_PM_AUTO);
+ mutex_unlock(&inf->mutex);
+ nvi_aux_dbg(inf, "nvi_mpu_dev_valid err: ", err);
+ return err;
}
+EXPORT_SYMBOL(nvi_mpu_dev_valid);
-/**
- * inv_gyro_fs_store() - Change the gyro full-scale range (and scale factor).
- */
-static ssize_t inv_gyro_fs_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+int nvi_mpu_port_alloc(struct nvi_mpu_port *nmp)
{
- unsigned long fsr;
- int result;
- struct inv_gyro_state_s *st;
- struct inv_reg_map_s *reg;
+ struct inv_gyro_state_s *inf;
+ int err;
- st = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EPERM;
+ inf = inf_local;
+ if (inf != NULL) {
+ if (inf->aux.dbg)
+ pr_info("%s\n", __func__);
+ } else {
+ pr_debug("%s\n", __func__);
+ return -EAGAIN;
+ }
- result = kstrtoul(buf, 10, &fsr);
- if (result)
+ if (nmp == NULL)
return -EINVAL;
- if (fsr > 3)
+ if (!(nmp->ctrl & BITS_I2C_SLV_CTRL_LEN))
return -EINVAL;
- if (fsr == st->chip_config.fsr)
- return count;
+ if (inf->shutdown)
+ return -EPERM;
- reg = st->reg;
- if (INV_MPU3050 == st->chip_type)
- result = inv_i2c_single_write(st, reg->lpf,
- (fsr << 3) | st->chip_config.lpf);
- else
- result = inv_i2c_single_write(st, reg->gyro_config,
- fsr << 3);
- if (result)
- return result;
+ mutex_lock(&inf->mutex);
+ nvi_pm(inf, NVI_PM_ON);
+ err = nvi_aux_port_alloc(inf, nmp, -1);
+ nvi_pm(inf, NVI_PM_AUTO);
+ err = nvi_aux_mpu_call_post(inf, "nvi_mpu_port_alloc err/port: ", err);
+ return err;
+}
+EXPORT_SYMBOL(nvi_mpu_port_alloc);
- st->chip_config.fsr = fsr;
- return count;
+int nvi_mpu_port_free(int port)
+{
+ struct inv_gyro_state_s *inf;
+ int err;
+
+ inf = inf_local;
+ if (inf != NULL) {
+ if (inf->aux.dbg)
+ pr_info("%s port %d\n", __func__, port);
+ } else {
+ pr_debug("%s port %d\n", __func__, port);
+ return -EAGAIN;
+ }
+
+ err = nvi_aux_mpu_call_pre(inf, port);
+ if (err)
+ return err;
+
+ nvi_pm(inf, NVI_PM_ON);
+ err = nvi_aux_port_free(inf, port);
+ nvi_pm(inf, NVI_PM_AUTO);
+ err = nvi_aux_mpu_call_post(inf, "nvi_mpu_port_free err: ", err);
+ return err;
}
+EXPORT_SYMBOL(nvi_mpu_port_free);
-/**
- * inv_accl_fs_store() - Configure the accelerometer's scale range.
- */
-ssize_t inv_accl_fs_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+int nvi_mpu_enable(int port, bool enable, bool fifo_enable)
{
- unsigned long fs;
- int result;
- struct inv_gyro_state_s *st;
- struct inv_reg_map_s *reg;
+ struct inv_gyro_state_s *inf;
+ int err;
- st = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EPERM;
+ inf = inf_local;
+ if (inf != NULL) {
+ if (inf->aux.dbg)
+ pr_info("%s port %d: %x\n", __func__, port, enable);
+ } else {
+ pr_debug("%s port %d: %x\n", __func__, port, enable);
+ return -EAGAIN;
+ }
- if (kstrtoul(buf, 10, &fs))
- return -EINVAL;
+ err = nvi_aux_mpu_call_pre(inf, port);
+ if (err)
+ return err;
- if (fs > 3)
- return -EINVAL;
+ nvi_pm(inf, NVI_PM_ON);
+ err = nvi_aux_port_enable(inf, port, enable, fifo_enable);
+ nvi_pm(inf, NVI_PM_AUTO);
+ err = nvi_aux_mpu_call_post(inf, "nvi_mpu_enable err: ", err);
+ return err;
+}
+EXPORT_SYMBOL(nvi_mpu_enable);
- if (fs == st->chip_config.accl_fs)
- return count;
+int nvi_mpu_delay_ms(int port, u8 delay_ms)
+{
+ struct inv_gyro_state_s *inf;
+ int err;
- reg = st->reg;
- if ((INV_MPU3050 == st->chip_type) && (st->mpu_slave != NULL))
- result = st->mpu_slave->set_fs(st, fs);
- else
- result = inv_i2c_single_write(st, reg->accl_config, (fs << 3));
- if (result)
- return result;
+ inf = inf_local;
+ if (inf != NULL) {
+ if (inf->aux.dbg)
+ pr_info("%s port %d: %u\n", __func__, port, delay_ms);
+ } else {
+ pr_debug("%s port %d: %u\n", __func__, port, delay_ms);
+ return -EAGAIN;
+ }
- /* reset fifo because the data could be mixed with old bad data */
- st->chip_config.accl_fs = fs;
- return count;
+ err = nvi_aux_mpu_call_pre(inf, port);
+ if (err)
+ return err;
+
+ if (inf->aux.port[port].hw_en) {
+ err = nvi_aux_delay(inf, port, delay_ms);
+ nvi_global_delay(inf);
+ } else {
+ inf->aux.port[port].nmp.delay_ms = delay_ms;
+ }
+ err = nvi_aux_mpu_call_post(inf, "nvi_mpu_delay_ms err: ", err);
+ return err;
}
+EXPORT_SYMBOL(nvi_mpu_delay_ms);
-/**
- * inv_firmware_loaded_store() - calling this function will change
- * firmware load
- */
-static ssize_t inv_firmware_loaded_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+int nvi_mpu_delay_us(int port, unsigned long delay_us)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- unsigned long data, result;
+ struct inv_gyro_state_s *inf;
+ int err;
- result = kstrtoul(buf, 10, &data);
- if (result)
- return result;
+ inf = inf_local;
+ if (inf != NULL) {
+ if (inf->aux.dbg)
+ pr_info("%s port %d: %lu\n", __func__, port, delay_us);
+ } else {
+ pr_debug("%s port %d: %lu\n", __func__, port, delay_us);
+ return -EAGAIN;
+ }
- if (data != 0)
- return -EINVAL;
+ err = nvi_aux_mpu_call_pre(inf, port);
+ if (err)
+ return err;
- st->chip_config.firmware_loaded = 0;
- st->chip_config.dmp_on = 0;
- return count;
+ inf->aux.port[port].nmp.delay_us = delay_us;
+ if (inf->aux.port[port].hw_en)
+ err = nvi_global_delay(inf);
+ err = nvi_aux_mpu_call_post(inf, "nvi_mpu_delay_us err: ", err);
+ return err;
}
+EXPORT_SYMBOL(nvi_mpu_delay_us);
-/**
- * inv_lpa_mode_store() - store current low power settings
- */
-static ssize_t inv_lpa_mode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+int nvi_mpu_data_out(int port, u8 data_out)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- unsigned long result, lpa_mode;
- unsigned char d;
- struct inv_reg_map_s *reg;
+ struct inv_gyro_state_s *inf;
+ int err = 0;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ inf = inf_local;
+ if (inf == NULL)
+ return -EAGAIN;
- result = kstrtoul(buf, 10, &lpa_mode);
- if (result)
- return result;
+ err = nvi_aux_mpu_call_pre(inf, port);
+ if (err)
+ return err;
- reg = st->reg;
- result = inv_i2c_read(st, reg->pwr_mgmt_1, 1, &d);
- if (result)
- return result;
+ if (inf->aux.port[port].hw_en) {
+ err = nvi_aux_port_data_out(inf, port, data_out);
+ } else {
+ inf->aux.port[port].nmp.data_out = data_out;
+ inf->aux.port[port].hw_do = false;
+ }
+ if (err < 0)
+ err = -EBUSY;
+ mutex_unlock(&inf->mutex);
+ return err;
+}
+EXPORT_SYMBOL(nvi_mpu_data_out);
- d &= ~BIT_CYCLE;
- if (lpa_mode)
- d |= BIT_CYCLE;
- result = inv_i2c_single_write(st, reg->pwr_mgmt_1, d);
- if (result)
- return result;
+int nvi_mpu_bypass_request(bool enable)
+{
+ struct inv_gyro_state_s *inf;
+ int err;
- st->chip_config.lpa_mode = lpa_mode;
- return count;
+ inf = inf_local;
+ if (inf != NULL) {
+ if (inf->aux.dbg)
+ pr_info("%s\n", __func__);
+ } else {
+ pr_debug("%s\n", __func__);
+ return -EAGAIN;
+ }
+
+ if (inf->shutdown)
+ return -EPERM;
+
+ mutex_lock(&inf->mutex);
+ nvi_pm(inf, NVI_PM_ON);
+ err = nvi_aux_bypass_request(inf, enable);
+ nvi_pm(inf, NVI_PM_AUTO);
+ err = nvi_aux_mpu_call_post(inf, "nvi_mpu_bypass_request err: ", err);
+ return err;
}
+EXPORT_SYMBOL(nvi_mpu_bypass_request);
-/**
- * inv_lpa_freq_store() - store current low power frequency setting.
- */
-static ssize_t inv_lpa_freq_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+int nvi_mpu_bypass_release(void)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- unsigned long result, lpa_freq;
- unsigned char d;
- struct inv_reg_map_s *reg;
+ struct inv_gyro_state_s *inf;
+ int err;
- if (st->chip_config.is_asleep)
+ inf = inf_local;
+ if (inf != NULL) {
+ if (inf->aux.dbg)
+ pr_info("%s\n", __func__);
+ } else {
+ pr_debug("%s\n", __func__);
+ return -EAGAIN;
+ }
+
+ if (inf->shutdown)
return -EPERM;
- result = kstrtoul(buf, 10, &lpa_freq);
- if (result)
- return result;
+ mutex_lock(&inf->mutex);
+ nvi_pm(inf, NVI_PM_ON);
+ err = nvi_aux_bypass_release(inf);
+ nvi_pm(inf, NVI_PM_AUTO);
+ err = nvi_aux_mpu_call_post(inf, "nvi_mpu_bypass_release err: ", err);
+ return err;
+}
+EXPORT_SYMBOL(nvi_mpu_bypass_release);
+
+
+static int nvi_gyro_enable(struct inv_gyro_state_s *inf,
+ unsigned char enable, unsigned char fifo_enable)
+{
+ unsigned char enable_old;
+ unsigned char fifo_enable_old;
+ int err;
+ int err_t;
+
+ enable_old = inf->chip_config.gyro_enable;
+ fifo_enable_old = inf->chip_config.gyro_fifo_enable;
+ inf->chip_config.gyro_fifo_enable = fifo_enable;
+ inf->chip_config.gyro_enable = enable;
+ err_t = nvi_pm(inf, NVI_PM_ON_FULL);
+ if (enable != enable_old) {
+ if (enable) {
+ err = nvi_gyro_config_wr(inf,
+ inf->chip_config.gyro_fsr);
+ if (err < 0)
+ err_t |= err;
+ nvi_motion_detect_enable(inf, 0);
+ }
+ nvi_global_delay(inf);
+ }
+ if (fifo_enable_old != fifo_enable)
+ err_t = nvi_reset(inf, true, false);
+ if (err_t) {
+ inf->chip_config.gyro_enable = enable_old;
+ inf->chip_config.gyro_fifo_enable = fifo_enable_old;
+ }
+ err_t |= nvi_pm(inf, NVI_PM_AUTO);
+ return err_t;
+}
+
+static int nvi_accl_enable(struct inv_gyro_state_s *inf,
+ unsigned char enable, unsigned char fifo_enable)
+{
+ unsigned char enable_old;
+ unsigned char fifo_enable_old;
+ int err;
+ int err_t;
+
+ enable_old = inf->chip_config.accl_enable;
+ fifo_enable_old = inf->chip_config.accl_fifo_enable;
+ inf->chip_config.accl_fifo_enable = fifo_enable;
+ inf->chip_config.accl_enable = enable;
+ err_t = nvi_pm(inf, NVI_PM_ON);
+ if (enable != enable_old) {
+ if (enable) {
+ err = nvi_accel_config_wr(inf,
+ inf->chip_config.accl_fsr, 0);
+ if (err < 0)
+ err_t |= err;
+ }
+ nvi_global_delay(inf);
+ }
+ if (fifo_enable_old != fifo_enable)
+ err_t = nvi_reset(inf, true, false);
+ if (err_t) {
+ inf->chip_config.accl_enable = enable_old;
+ inf->chip_config.accl_fifo_enable = fifo_enable_old;
+ }
+ err_t |= nvi_pm(inf, NVI_PM_AUTO);
+ return err_t;
+}
- if (lpa_freq > 3)
+
+static ssize_t nvi_gyro_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned char enable;
+ unsigned char fifo_enable;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &enable);
+ if (err)
return -EINVAL;
- reg = st->reg;
- result = inv_i2c_read(st, reg->pwr_mgmt_2, 1, &d);
- if (result)
- return result;
+ if (enable > 7)
+ return -EINVAL;
- d &= ~BIT_LPA_FREQ;
- d |= (unsigned char)(lpa_freq << 6);
- result = inv_i2c_single_write(st, reg->pwr_mgmt_2, d);
- if (result)
- return result;
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, enable);
+ if (enable != inf->chip_config.gyro_enable) {
+ if (enable)
+ fifo_enable = inf->chip_config.gyro_fifo_enable;
+ else
+ fifo_enable = 0;
+ err = nvi_gyro_enable(inf, enable, fifo_enable);
+ }
+ mutex_unlock(&inf->mutex);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n",
+ __func__, enable, err);
+ return err;
+ }
- st->chip_config.lpa_freq = lpa_freq;
return count;
}
-/**
- * inv_compass_en_store() - calling this function will store compass
- * enable
- */
-static ssize_t inv_compass_en_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ssize_t nvi_gyro_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st;
- unsigned long data, result, en;
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
- st = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EPERM;
+ return sprintf(buf, "%u\n", inf->chip_config.gyro_enable);
+}
- if (st->chip_config.enable)
- return -EPERM;
+ssize_t nvi_gyro_fifo_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned char fifo_enable;
+ unsigned char enable;
+ int err;
- result = kstrtoul(buf, 10, &data);
- if (result)
- return result;
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &fifo_enable);
+ if (err)
+ return -EINVAL;
- if (data)
- en = 1;
- else
- en = 0;
- if (en == st->chip_config.compass_enable)
- return count;
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, fifo_enable);
+ enable = inf->chip_config.gyro_enable;
+ if (fifo_enable) {
+ fifo_enable = 1;
+ if (!enable)
+ enable = 7;
+ }
+ if (fifo_enable != inf->chip_config.gyro_fifo_enable)
+ err = nvi_gyro_enable(inf, enable, fifo_enable);
+ mutex_unlock(&inf->mutex);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n",
+ __func__, fifo_enable, err);
+ return err;
+ }
- st->chip_config.compass_enable = en;
return count;
}
-/**
- * inv_compass_scale_store() - show current compass scale settings
- */
-static ssize_t inv_compass_scale_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ssize_t nvi_gyro_fifo_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st;
- unsigned long data, result, en;
- char d;
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
- st = dev_get_drvdata(dev);
- if (COMPASS_ID_AK8963 != st->plat_data.sec_slave_id)
- return count;
+ return sprintf(buf, "%u\n", inf->chip_config.gyro_fifo_enable);
+}
- if (st->chip_config.is_asleep)
- return -EPERM;
+static ssize_t inv_gyro_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned long gyro_delay_us;
+ unsigned long gyro_delay_us_old;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtoul(buf, 10, &gyro_delay_us);
+ if (err)
+ return err;
+
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %lu\n", __func__, gyro_delay_us);
+ if (gyro_delay_us < NVI_INPUT_GYRO_DELAY_US_MIN)
+ gyro_delay_us = NVI_INPUT_GYRO_DELAY_US_MIN;
+ if (gyro_delay_us != inf->chip_config.gyro_delay_us) {
+ gyro_delay_us_old = inf->chip_config.gyro_delay_us;
+ inf->chip_config.gyro_delay_us = gyro_delay_us;
+ if (inf->chip_config.gyro_enable) {
+ err = nvi_global_delay(inf);
+ if (err)
+ inf->chip_config.gyro_delay_us =
+ gyro_delay_us_old;
+ }
+ }
+ mutex_unlock(&inf->mutex);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %lu ERR=%d\n",
+ __func__, gyro_delay_us, err);
+ return err;
+ }
- result = kstrtoul(buf, 10, &data);
- if (result)
- return result;
+ return count;
+}
- if (data)
- en = 1;
- else
- en = 0;
- if (st->compass_scale == en)
- return count;
+static ssize_t nvi_gyro_resolution_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned int resolution;
- st->compass_scale = en;
- d = (1 | (st->compass_scale << 4));
- result = inv_i2c_single_write(st, REG_I2C_SLV1_DO, d);
- if (result)
- return result;
+ inf = dev_get_drvdata(dev);
+ if (kstrtouint(buf, 10, &resolution))
+ return -EINVAL;
+ dev_dbg(&inf->i2c->dev, "%s %u", __func__, resolution);
+ inf->chip_config.gyro_resolution = resolution;
return count;
}
-/**
- * inv_flick_lower_store() - calling this function will store current
- * flick lower bound
- */
-static ssize_t inv_flick_lower_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t nvi_gyro_resolution_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- int result, data, out;
- unsigned char *p;
+ struct inv_gyro_state_s *inf;
+ unsigned int resolution;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ inf = dev_get_drvdata(dev);
+ if (inf->chip_config.gyro_enable)
+ resolution = inf->chip_config.gyro_resolution;
+ else
+ resolution = GYRO_INPUT_RESOLUTION;
+ return sprintf(buf, "%u\n", resolution);
+}
- result = kstrtol(buf, 10, (long unsigned int *)&data);
- if (result)
- return result;
+static ssize_t nvi_gyro_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct inv_gyro_state_s *inf;
- out = cpu_to_be32p(&data);
- p = (unsigned char *)&out;
- result = mem_w_key(KEY_FLICK_LOWER, 4, p);
- if (result)
- return result;
+ inf = dev_get_drvdata(dev);
+ if (inf->chip_config.gyro_enable)
+ return sprintf(buf, "%lu\n", inf->sample_delay_us);
- st->flick.lower = data;
- return count;
+ return sprintf(buf, "%d\n", NVI_INPUT_GYRO_DELAY_US_MIN);
}
-/**
- * inv_flick_upper_store() - calling this function will store current
- * flick upper bound
- */
-static ssize_t inv_flick_upper_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t nvi_gyro_max_range_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- unsigned int result, data, out;
- unsigned char *p;
+ struct inv_gyro_state_s *inf;
+ unsigned char fsr;
+ int err;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &fsr);
+ if (err)
+ return -EINVAL;
- result = kstrtoul(buf, 10, (long unsigned int *)&data);
- if (result)
- return result;
+ if (fsr > 3)
+ return -EINVAL;
- out = cpu_to_be32p(&data);
- p = (unsigned char *)&out;
- result = mem_w_key(KEY_FLICK_UPPER, 4, p);
- if (result)
- return result;
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, fsr);
+ if (fsr != inf->chip_config.gyro_fsr) {
+ if (inf->chip_config.gyro_enable) {
+ err = nvi_gyro_config_wr(inf, fsr);
+ if (err > 0)
+ /* reset fifo to purge old data */
+ nvi_reset(inf, true, false);
+ }
+ if (err >= 0)
+ inf->chip_config.gyro_fsr = fsr;
+ }
+ mutex_unlock(&inf->mutex);
+ if (err < 0) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n", __func__, fsr, err);
+ return err;
+ }
- st->flick.upper = data;
return count;
}
-/**
- * inv_flick_counter_store() - calling this function will store current
- * flick counter value
- */
-static ssize_t inv_flick_counter_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ssize_t nvi_gyro_max_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- unsigned int result, data, out;
- unsigned char *p;
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
+ unsigned int range;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ if (inf->chip_config.gyro_enable)
+ range = inf->chip_config.gyro_fsr;
+ else
+ range = (1 << inf->chip_config.gyro_fsr) * 250;
+ return sprintf(buf, "%u\n", range);
+}
- result = kstrtoul(buf, 10, (long unsigned int *)&data);
- if (result)
- return result;
+static ssize_t nvi_accl_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned char enable;
+ unsigned char fifo_enable;
+ int err;
- out = cpu_to_be32p(&data);
- p = (unsigned char *)&out;
- result = mem_w_key(KEY_FLICK_COUNTER, 4, p);
- if (result)
- return result;
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &enable);
+ if (err)
+ return -EINVAL;
+
+ if (enable > 7)
+ return -EINVAL;
+
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, enable);
+ if (enable != inf->chip_config.accl_enable) {
+ if (enable)
+ fifo_enable = inf->chip_config.accl_fifo_enable;
+ else
+ fifo_enable = 0;
+ err = nvi_accl_enable(inf, enable, fifo_enable);
+ }
+ mutex_unlock(&inf->mutex);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n",
+ __func__, enable, err);
+ return err;
+ }
- st->flick.counter = data;
return count;
}
-/**
- * inv_flick_int_on_store() - calling this function will store current
- * flick interrupt on value
- */
-static ssize_t inv_flick_int_on_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ssize_t nvi_accl_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- unsigned long result, data;
- unsigned char d[4];
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EPERM;
+ return sprintf(buf, "%u\n", inf->chip_config.accl_enable);
+}
- result = kstrtoul(buf, 10, &data);
- if (result)
- return result;
+static ssize_t nvi_accl_fifo_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned char fifo_enable;
+ unsigned char enable;
+ int err;
- if (data)
- /* Use interrupt to signal when gesture was observed */
- d[0] = DIND40+4;
- else
- d[0] = DINAA0+8;
- result = mem_w_key(KEY_CGNOTICE_INTR, 1, d);
- if (result)
- return result;
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &fifo_enable);
+ if (err)
+ return -EINVAL;
+
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, fifo_enable);
+ enable = inf->chip_config.accl_enable;
+ if (fifo_enable) {
+ fifo_enable = 1;
+ if (!enable)
+ enable = 7;
+ }
+ if (fifo_enable != inf->chip_config.accl_fifo_enable)
+ err = nvi_accl_enable(inf, enable, fifo_enable);
+ mutex_unlock(&inf->mutex);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n",
+ __func__, fifo_enable, err);
+ return err;
+ }
- st->flick.int_on = data;
return count;
}
-/**
- * inv_flick_axis_store() - calling this function will store current
- * flick axis value
- */
-static ssize_t inv_flick_axis_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ssize_t nvi_accl_fifo_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- unsigned long result, data;
- unsigned char d[4];
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EPERM;
-
- result = kstrtoul(buf, 10, &data);
- if (result)
- return result;
+ return sprintf(buf, "%u\n", inf->chip_config.accl_fifo_enable);
+}
- if (data == 0)
- d[0] = DINBC2;
- else if (data == 2)
- d[2] = DINBC6;
- else
- d[0] = DINBC4;
- result = mem_w_key(KEY_CFG_FLICK_IN, 1, d);
- if (result)
- return result;
+static ssize_t nvi_accl_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned long accl_delay_us;
+ unsigned long accl_delay_us_old;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtoul(buf, 10, &accl_delay_us);
+ if (err)
+ return err;
+
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %lu\n", __func__, accl_delay_us);
+ if (accl_delay_us < NVI_INPUT_ACCL_DELAY_US_MIN)
+ accl_delay_us = NVI_INPUT_ACCL_DELAY_US_MIN;
+ if (accl_delay_us != inf->chip_config.accl_delay_us) {
+ accl_delay_us_old = inf->chip_config.accl_delay_us;
+ inf->chip_config.accl_delay_us = accl_delay_us;
+ if (inf->chip_config.accl_enable) {
+ err = nvi_global_delay(inf);
+ if (err)
+ inf->chip_config.accl_delay_us =
+ accl_delay_us_old;
+ else
+ nvi_pm(inf, NVI_PM_AUTO);
+ }
+ }
+ mutex_unlock(&inf->mutex);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %lu ERR=%d\n",
+ __func__, accl_delay_us, err);
+ return err;
+ }
- st->flick.axis = data;
return count;
}
-/**
- * inv_flick_msg_on_store() - calling this function will store current
- * flick message on value
- */
-static ssize_t inv_flick_msg_on_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ssize_t nvi_accl_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- unsigned int result, data, out;
- unsigned char *p;
-
- if (st->chip_config.is_asleep)
- return -EPERM;
-
- result = kstrtoul(buf, 10, (long unsigned int *)&data);
- if (result)
- return result;
+ struct inv_gyro_state_s *inf;
- if (data)
- data = DATA_MSG_ON;
- out = cpu_to_be32p(&data);
- p = (unsigned char *)&out;
- result = mem_w_key(KEY_FLICK_MSG, 4, p);
- if (result)
- return result;
+ inf = dev_get_drvdata(dev);
+ if (inf->chip_config.accl_enable)
+ return sprintf(buf, "%lu\n", inf->sample_delay_us);
- st->flick.msg_on = data;
- return count;
+ return sprintf(buf, "%d\n", NVI_INPUT_ACCL_DELAY_US_MIN);
}
-/**
- * inv_pedometer_steps_store() - calling this function will store current
- * pedometer steps into MPU memory
- */
-static ssize_t inv_pedometer_steps_store(struct device *dev,
+static ssize_t nvi_accl_resolution_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- unsigned int result, data, out;
- unsigned char *p;
+ struct inv_gyro_state_s *inf;
+ unsigned int resolution;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ inf = dev_get_drvdata(dev);
+ if (kstrtouint(buf, 10, &resolution))
+ return -EINVAL;
- result = kstrtoul(buf, 10, (long unsigned int *)&data);
- if (result)
- return result;
+ dev_dbg(&inf->i2c->dev, "%s %u", __func__, resolution);
+ inf->chip_config.accl_resolution = resolution;
+ return count;
+}
- out = cpu_to_be32p(&data);
- p = (unsigned char *)&out;
- result = mem_w_key(KEY_D_PEDSTD_STEPCTR, 4, p);
- if (result)
- return result;
+static ssize_t nvi_accl_resolution_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned int resolution;
- return count;
+ inf = dev_get_drvdata(dev);
+ if (inf->chip_config.accl_enable)
+ resolution = inf->chip_config.accl_resolution;
+ else
+ resolution = ACCL_INPUT_RESOLUTION;
+ return sprintf(buf, "%u\n", resolution);
}
-/**
- * inv_pedometer_time_store() - calling this function will store current
- * pedometer time into MPU memory
- */
-static ssize_t inv_pedometer_time_store(struct device *dev,
+static ssize_t nvi_accl_max_range_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- unsigned int result, data, out;
- unsigned char *p;
+ struct inv_gyro_state_s *inf;
+ unsigned char fsr;
+ int err;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &fsr);
+ if (err)
+ return -EINVAL;
- result = kstrtoul(buf, 10, (long unsigned int *)&data);
- if (result)
- return result;
+ if (fsr > 3)
+ return -EINVAL;
- out = cpu_to_be32p(&data);
- p = (unsigned char *)&out;
- result = mem_w_key(KEY_D_PEDSTD_TIMECTR, 4, p);
- if (result)
- return result;
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, fsr);
+ if (fsr != inf->chip_config.accl_fsr) {
+ if (inf->chip_config.accl_enable) {
+ err = nvi_accel_config_wr(inf, fsr, 0);
+ if (err > 0)
+ /* reset fifo to purge old data */
+ nvi_reset(inf, true, false);
+ nvi_pm(inf, NVI_PM_AUTO);
+ }
+ if (err >= 0)
+ inf->chip_config.accl_fsr = fsr;
+ }
+ mutex_unlock(&inf->mutex);
+ if (err < 0) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n", __func__, fsr, err);
+ return err;
+ }
return count;
}
-/**
- * inv_key_store() - calling this function will store authenticate key
- */
-static ssize_t inv_key_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ssize_t nvi_accl_max_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- unsigned int result, data, out;
- unsigned char *p, d[4];
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
+ unsigned int range;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ if (inf->chip_config.accl_enable)
+ range = inf->chip_config.accl_fsr;
+ else
+ range = 0x4000 >> inf->chip_config.accl_fsr;
+ return sprintf(buf, "%u\n", range);
+}
- result = kstrtoul(buf, 10, (long unsigned int *)&data);
- if (result)
- return result;
+static ssize_t nvi_lpa_delay_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned long lpa_delay_us;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtoul(buf, 10, &lpa_delay_us);
+ if (err)
+ return err;
+
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %lu\n", __func__, lpa_delay_us);
+ inf->chip_config.lpa_delay_us = lpa_delay_us;
+ err = nvi_pm(inf, NVI_PM_AUTO);
+ mutex_unlock(&inf->mutex);
+ if (err)
+ dev_err(&inf->i2c->dev, "%s: %lu ERR=%d\n",
+ __func__, lpa_delay_us, err);
+ return count;
+}
- out = cpu_to_be32p(&data);
- p = (unsigned char *)&out;
- result = mem_w(D_AUTH_IN, 4, p);
- if (result)
- return result;
+static ssize_t nvi_lpa_delay_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lu\n", inf->chip_config.lpa_delay_us);
+}
+
+static ssize_t nvi_motion_thr_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned char mot_thr;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &mot_thr);
+ if (err)
+ return -EINVAL;
+
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %u\n", __func__, mot_thr);
+ nvi_pm(inf, NVI_PM_ON);
+ err = nvi_motion_detect_enable(inf, mot_thr);
+ err |= nvi_pm(inf, NVI_PM_AUTO);
+ mutex_unlock(&inf->mutex);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %u ERR=%d\n",
+ __func__, mot_thr, err);
+ return err;
+ }
- result = mpu_memory_read(st->sl_handle, st->i2c_addr,
- D_AUTH_IN, 4, d);
return count;
}
-/**
- * inv_gyro_fs_show() - Get the current gyro full-scale range.
- */
-static ssize_t inv_gyro_fs_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_motion_thr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf;
+ unsigned char mot_thr;
- return sprintf(buf, "%d\n", (1 << st->chip_config.fsr)*250);
+ inf = dev_get_drvdata(dev);
+ if (inf->mot_enable)
+ mot_thr = inf->hw.mot_thr;
+ else
+ mot_thr = 0;
+ return sprintf(buf, "%u\n", mot_thr);
}
-/**
- * inv_accl_fs_show() - Get the current gyro full-scale range.
- */
-ssize_t inv_accl_fs_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_motion_dur_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf;
+ unsigned char mot_dur;
+ int err;
- return sprintf(buf, "%d\n", 2 << st->chip_config.accl_fs);
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &mot_dur);
+ if (err)
+ return -EINVAL;
+
+ dev_dbg(&inf->i2c->dev, "%s: %u\n", __func__, mot_dur);
+ inf->chip_config.mot_dur = mot_dur;
+ return count;
}
-/**
- * inv_clk_src_show() - Show the device's clock source.
- */
-static ssize_t inv_clk_src_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_motion_dur_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", inf->chip_config.mot_dur);
+}
- switch (st->chip_config.clk_src) {
- case INV_CLK_INTERNAL:
- return sprintf(buf, "INTERNAL\n");
+static ssize_t nvi_motion_ctrl_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned char mot_ctrl;
+ int err;
- case INV_CLK_PLL:
- return sprintf(buf, "Gyro PLL\n");
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &mot_ctrl);
+ if (err)
+ return -EINVAL;
- default:
- return sprintf(buf, "Oh no!\n");
- }
+ dev_dbg(&inf->i2c->dev, "%s: %u\n", __func__, mot_ctrl);
+ inf->chip_config.mot_ctrl = mot_ctrl;
+ return count;
}
-/**
- * inv_fifo_rate_show() - Get the current sampling rate.
- */
-static ssize_t inv_fifo_rate_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_motion_ctrl_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
- return sprintf(buf, "%d\n", st->chip_config.fifo_rate);
+ return sprintf(buf, "%u\n", inf->chip_config.mot_ctrl);
}
-/**
- * inv_enable_show() - Check if the chip are enabled.
- */
-static ssize_t inv_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_motion_count_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf;
+ unsigned int mot_cnt;
+ int err;
- return sprintf(buf, "%d\n", st->chip_config.enable);
+ inf = dev_get_drvdata(dev);
+ err = kstrtouint(buf, 10, &mot_cnt);
+ if (err)
+ return -EINVAL;
+
+ dev_dbg(&inf->i2c->dev, "%s: %u\n", __func__, mot_cnt);
+ inf->chip_config.mot_cnt = mot_cnt;
+ return count;
}
-/**
- * inv_gyro_fifo_enable_show() - Check if gyro FIFO are enabled.
- */
-ssize_t inv_gyro_fifo_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_motion_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
- return sprintf(buf, "%d\n", st->chip_config.gyro_fifo_enable);
+ return sprintf(buf, "%u\n", inf->chip_config.mot_cnt);
}
-/**
- * inv_accl_fifo_enable_show() - Check if accl FIFO are enabled.
- */
-ssize_t inv_accl_fifo_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf;
+ unsigned char enable;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &enable);
+ if (err)
+ return -EINVAL;
- return sprintf(buf, "%d\n", st->chip_config.accl_fifo_enable);
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %u\n", __func__, enable);
+ if (enable)
+ enable = 1;
+ if (enable != inf->chip_config.enable) {
+ inf->chip_config.enable = enable;
+ err = nvi_pm(inf, NVI_PM_AUTO);
+ }
+ mutex_unlock(&inf->mutex);
+ if (err)
+ dev_err(&inf->i2c->dev, "%s: %u ERR=%d\n",
+ __func__, enable, err);
+ return count;
}
-/**
- * inv_gyro_enable_show() - Check if the FIFO and ring buffer are enabled.
- */
-ssize_t inv_gyro_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ssize_t nvi_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
- return sprintf(buf, "%d\n", st->chip_config.gyro_enable);
+ return sprintf(buf, "%u\n", inf->chip_config.enable);
}
/**
- * inv_accl_enable_show() - Check if the FIFO and ring buffer are enabled.
+ * inv_raw_gyro_show() - Read gyro data directly from registers.
*/
-ssize_t inv_accl_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t inv_raw_gyro_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *st;
+ struct inv_reg_map_s *reg;
+ int result;
+ unsigned char data[6];
+
+ st = dev_get_drvdata(dev);
+ reg = st->reg;
+ if (0 == st->chip_config.gyro_enable)
+ return -EPERM;
+
+ result = inv_i2c_read(st, reg->raw_gyro, 6, data);
+ if (result) {
+ printk(KERN_ERR "Could not read raw registers.\n");
+ return result;
+ }
- return sprintf(buf, "%d\n", st->chip_config.accl_enable);
+ return sprintf(buf, "%d %d %d %lld\n",
+ (signed short)(be16_to_cpup((short *)&data[0])),
+ (signed short)(be16_to_cpup((short *)&data[2])),
+ (signed short)(be16_to_cpup((short *)&data[4])),
+ get_time_ns());
}
/**
- * inv_power_state_show() - Check if the device is on or in sleep mode.
+ * inv_raw_accl_show() - Read accel data directly from registers.
*/
-static ssize_t inv_power_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t inv_raw_accl_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *st;
+ struct inv_reg_map_s *reg;
+ int result;
+ unsigned char data[6];
- if (st->chip_config.is_asleep)
- return sprintf(buf, "0\n");
+ st = dev_get_drvdata(dev);
+ reg = st->reg;
+ if (0 == st->chip_config.accl_enable)
+ return -EPERM;
- else
- return sprintf(buf, "1\n");
+ result = inv_i2c_read(st, reg->raw_accl, 6, data);
+ if (result) {
+ printk(KERN_ERR "Could not read raw registers.\n");
+ return result;
+ }
+
+ return sprintf(buf, "%d %d %d %lld\n",
+ ((signed short)(be16_to_cpup((short *)&data[0]))*
+ st->chip_info.multi),
+ ((signed short)(be16_to_cpup((short *)&data[2]))*
+ st->chip_info.multi),
+ ((signed short)(be16_to_cpup((short *)&data[4]))*
+ st->chip_info.multi),
+ get_time_ns());
}
/**
@@ -1572,7 +2414,6 @@ static ssize_t inv_temp_scale_show(struct device *dev,
if (INV_MPU3050 == st->chip_type)
return sprintf(buf, "280\n");
-
else
return sprintf(buf, "340\n");
}
@@ -1587,71 +2428,50 @@ static ssize_t inv_temp_offset_show(struct device *dev,
if (INV_MPU3050 == st->chip_type)
return sprintf(buf, "-13200\n");
-
else
return sprintf(buf, "-521\n");
}
-/**
- * inv_lpa_mode_show() - show current low power settings
- */
-static ssize_t inv_lpa_mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t inv_temperature_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf;
+ ssize_t rtn;
- return sprintf(buf, "%d\n", st->chip_config.lpa_mode);
+ inf = dev_get_drvdata(dev);
+ mutex_lock(&inf->mutex_temp);
+ rtn = sprintf(buf, "%d %lld\n", inf->temp_val, inf->temp_ts);
+ mutex_unlock(&inf->mutex_temp);
+ return rtn;
}
/**
- * inv_lpa_freq_show() - show current low power frequency setting
+ * inv_key_store() - calling this function will store authenticate key
*/
-static ssize_t inv_lpa_freq_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t inv_key_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ unsigned int result, data, out;
+ unsigned char *p, d[4];
- switch (st->chip_config.lpa_freq) {
- case 0:
- return sprintf(buf, "1.25\n");
-
- case 1:
- return sprintf(buf, "5\n");
-
- case 2:
- return sprintf(buf, "20\n");
-
- case 3:
- return sprintf(buf, "40\n");
+ if (st->chip_config.enable)
+ return -EPERM;
- default:
- return sprintf(buf, "0\n");
- }
-}
+ result = kstrtoul(buf, 10, (long unsigned int *)&data);
+ if (result)
+ return result;
-/**
- * inv_compass_scale_show() - show current compass scale settings
- */
-static ssize_t inv_compass_scale_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- long scale;
-
- if (COMPASS_ID_AK8975 == st->plat_data.sec_slave_id)
- scale = DATA_AKM8975_SCALE;
- else if (COMPASS_ID_AK8972 == st->plat_data.sec_slave_id)
- scale = DATA_AKM8972_SCALE;
- else if (COMPASS_ID_AK8963 == st->plat_data.sec_slave_id)
- if (st->compass_scale)
- scale = DATA_AKM8963_SCALE1;
- else
- scale = DATA_AKM8963_SCALE0;
- else
- return -EINVAL;
+ out = cpu_to_be32p(&data);
+ p = (unsigned char *)&out;
+ result = mem_w(D_AUTH_IN, 4, p);
+ if (result)
+ return result;
- scale *= (1L << 15);
- return sprintf(buf, "%ld\n", scale);
+ result = mpu_memory_read(st->sl_handle, st->i2c_addr,
+ D_AUTH_IN, 4, d);
+ return count;
}
/**
@@ -1666,7 +2486,7 @@ static ssize_t inv_reg_dump_show(struct device *dev,
ssize_t bytes_printed = 0;
struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- for (ii = 0; ii < st->hw->num_reg; ii++) {
+ for (ii = 0; ii < st->hw_s->num_reg; ii++) {
/* don't read fifo r/w register */
if (ii == st->reg->fifo_r_w)
data = 0;
@@ -1679,49 +2499,11 @@ static ssize_t inv_reg_dump_show(struct device *dev,
}
/**
- * inv_self_test_show() - self test result. 0 for fail; 1 for success.
- * calling this function will trigger self test
- * and return test result.
+ * inv_gyro_orientation_show() - show orientation matrix
*/
-static ssize_t inv_self_test_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int result;
- int bias[3];
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
-
- if (INV_MPU3050 == st->chip_type) {
- bias[0] = bias[1] = bias[2] = 0;
- result = 0;
- } else {
- result = inv_hw_self_test(st, bias);
- }
- return sprintf(buf, "%d, %d, %d, %d\n",
- bias[0], bias[1], bias[2], result);
-}
-
-/**
- * inv_get_accl_bias_show() - show accl bias value
- */
-static ssize_t inv_get_accl_bias_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int result;
- int bias[3];
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
-
- result = inv_get_accl_bias(st, bias);
- if (result)
- return -EINVAL;
-
- return sprintf(buf, "%d, %d, %d\n", bias[0], bias[1], bias[2]);
-}
-
-/**
- * inv_gyro_matrix_show() - show orientation matrix
- */
-static ssize_t inv_gyro_matrix_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t inv_gyro_orientation_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct inv_gyro_state_s *st = dev_get_drvdata(dev);
signed char *m;
@@ -1749,25 +2531,6 @@ ssize_t inv_accl_matrix_show(struct device *dev,
}
/**
- * inv_compass_matrix_show() - show orientation matrix
- */
-static ssize_t inv_compass_matrix_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- signed char *m;
-
- if (st->plat_data.sec_slave_type == SECONDARY_SLAVE_TYPE_COMPASS)
- m = st->plat_data.secondary_orientation;
- else
- return -1;
-
- return sprintf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
- m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
-}
-
-/**
* inv_key_show() - calling this function will show the key
*
*/
@@ -1779,159 +2542,203 @@ static ssize_t inv_key_show(struct device *dev, struct device_attribute *attr,
key = st->plat_data.key;
return sprintf(buf,
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
- key[0], key[1], key[2], key[3], key[4], key[5], key[6],
- key[7], key[8], key[9], key[10], key[11], key[12],
- key[13], key[14], key[15]);
+ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ key[0], key[1], key[2], key[3], key[4], key[5], key[6],
+ key[7], key[8], key[9], key[10], key[11], key[12],
+ key[13], key[14], key[15]);
}
-/**
- * inv_firmware_loaded_show() - calling this function will show current
- * firmware load status
- */
-static ssize_t inv_firmware_loaded_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+#if DEBUG_SYSFS_INTERFACE
+static ssize_t nvi_dbg_i2c_addr_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf;
+ unsigned char dbg_i2c_addr;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 16, &dbg_i2c_addr);
+ if (err)
+ return -EINVAL;
- return sprintf(buf, "%d\n", st->chip_config.firmware_loaded);
+ inf->dbg_i2c_addr = dbg_i2c_addr;
+ return count;
}
-/**
- * inv_compass_en_show() - calling this function will show compass
- * enable status
- */
-static ssize_t inv_compass_en_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_dbg_i2c_addr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ ssize_t bytes_printed = 0;
- return sprintf(buf, "%d\n", st->chip_config.compass_enable);
+ bytes_printed += sprintf(buf + bytes_printed,
+ "%#2x\n", st->dbg_i2c_addr);
+ return bytes_printed;
}
-/**
- * inv_flick_lower_show() - calling this function will show current
- * flick lower bound
- */
-static ssize_t inv_flick_lower_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_dbg_reg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf;
+ unsigned char dbg_reg;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 16, &dbg_reg);
+ if (err)
+ return -EINVAL;
- return sprintf(buf, "%d\n", st->flick.lower);
+ inf->dbg_reg = dbg_reg;
+ return count;
}
-/**
- * inv_flick_upper_show() - calling this function will show current
- * flick upper bound
- */
-static ssize_t inv_flick_upper_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_dbg_reg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ ssize_t bytes_printed = 0;
- return sprintf(buf, "%d\n", st->flick.upper);
+ bytes_printed += sprintf(buf + bytes_printed, "%#2x\n", st->dbg_reg);
+ return bytes_printed;
}
-/**
- * inv_flick_counter_show() - calling this function will show current
- * flick counter value
- */
-static ssize_t inv_flick_counter_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_dbg_dat_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf;
+ unsigned short dbg_i2c_addr;
+ unsigned char dbg_dat;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 16, &dbg_dat);
+ if (err)
+ return -EINVAL;
- return sprintf(buf, "%d\n", st->flick.counter);
+ if (inf->dbg_i2c_addr) {
+ err = inv_i2c_single_write_base(inf, inf->dbg_i2c_addr,
+ inf->dbg_reg, dbg_dat);
+ dbg_i2c_addr = inf->dbg_i2c_addr;
+ } else {
+ err = inv_i2c_single_write(inf, inf->dbg_reg, dbg_dat);
+ dbg_i2c_addr = inf->i2c->addr;
+ }
+ pr_info("%s dev=%x reg=%x data=%x err=%d\n",
+ __func__, dbg_i2c_addr, inf->dbg_reg, dbg_dat, err);
+ return count;
}
-/**
- * inv_flick_int_on_show() - calling this function will show current
- * flick interrupt on value
- */
-static ssize_t inv_flick_int_on_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_dbg_dat_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf;
+ unsigned short dbg_i2c_addr;
+ unsigned char data;
+ ssize_t bytes_printed = 0;
- return sprintf(buf, "%d\n", st->flick.int_on);
+ inf = dev_get_drvdata(dev);
+ if (inf->dbg_i2c_addr) {
+ inv_i2c_read_base(inf, inf->dbg_i2c_addr,
+ inf->dbg_reg, 1, &data);
+ dbg_i2c_addr = inf->dbg_i2c_addr;
+ } else {
+ inv_i2c_read(inf, inf->dbg_reg, 1, &data);
+ dbg_i2c_addr = inf->i2c->addr;
+ }
+ bytes_printed += sprintf(buf + bytes_printed, "%#2x:%#2x=%#2x\n",
+ dbg_i2c_addr, inf->dbg_reg, data);
+ return bytes_printed;
}
-/**
- * inv_flick_axis_show() - calling this function will show current
- * flick axis value
- */
-static ssize_t inv_flick_axis_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_aux_dbg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf;
+ unsigned int enable;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtouint(buf, 10, &enable);
+ if (err)
+ return err;
- return sprintf(buf, "%d\n", st->flick.axis);
+ inf->aux.dbg = true;
+ nvi_aux_dbg(inf, "SNAPSHOT", 0);
+ if (enable)
+ inf->aux.dbg = true;
+ else
+ inf->aux.dbg = false;
+ return count;
}
-/**
- * inv_flick_msg_on_show() - calling this function will show current
- * flick message on value
- */
-static ssize_t inv_flick_msg_on_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nvi_aux_dbg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
- return sprintf(buf, "%d\n", st->flick.msg_on);
+ return sprintf(buf, "%x\n", inf->aux.dbg);
}
-/**
- * inv_pedometer_steps_show() - calling this function will store current
- * pedometer steps into MPU memory
- */
-static ssize_t inv_pedometer_steps_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t nvi_mot_dbg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- int result, data;
- unsigned char d[4];
+ struct inv_gyro_state_s *inf;
+ unsigned int mot_dbg;
+ int err;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ inf = dev_get_drvdata(dev);
+ err = kstrtouint(buf, 10, &mot_dbg);
+ if (err)
+ return err;
- result = mpu_memory_read(st->sl_handle, st->i2c_addr,
- inv_dmp_get_address(KEY_D_PEDSTD_STEPCTR),
- 4, d);
- if (result)
- return result;
+ if (mot_dbg)
+ inf->mot_dbg = true;
+ else
+ inf->mot_dbg = false;
+ return count;
+}
+
+static ssize_t nvi_mot_dbg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
- data = be32_to_cpup((int *)d);
- return sprintf(buf, "%d\n", data);
+ return sprintf(buf, "%x\n", inf->mot_dbg);
}
+#endif /* DEBUG_SYSFS_INTERFACE */
-/**
- * inv_pedometer_time_show() - calling this function will store current
- * pedometer steps into MPU memory
- */
-static ssize_t inv_pedometer_time_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t nvi_min_delay_us_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- int result, data;
- unsigned char d[4];
+ struct inv_gyro_state_s *inf;
+ unsigned long min_delay_us;
+ int err;
- if (st->chip_config.is_asleep)
- return -EPERM;
+ inf = dev_get_drvdata(dev);
+ err = kstrtoul(buf, 10, &min_delay_us);
+ if (err)
+ return -EINVAL;
- result = mpu_memory_read(st->sl_handle, st->i2c_addr,
- inv_dmp_get_address(KEY_D_PEDSTD_TIMECTR),
- 4, d);
- if (result)
- return result;
+ dev_dbg(&inf->i2c->dev, "%s: %lu\n", __func__, min_delay_us);
+ inf->chip_config.min_delay_us = min_delay_us;
+ return count;
+}
+
+static ssize_t nvi_min_delay_us_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct inv_gyro_state_s *inf = dev_get_drvdata(dev);
- data = be32_to_cpup((int *)d);
- return sprintf(buf, "%d\n", data);
+ return sprintf(buf, "%lu\n", inf->chip_config.min_delay_us);
}
+
static void inv_report_gyro_accl(struct inv_gyro_state_s *st, s64 t,
unsigned char *data)
{
@@ -1941,7 +2748,7 @@ static void inv_report_gyro_accl(struct inv_gyro_state_s *st, s64 t,
conf = &st->chip_config;
ind = 0;
- if (conf->accl_fifo_enable | conf->dmp_on) {
+ if (conf->accl_fifo_enable) {
x = ((data[ind] << 8)|data[ind + 1])*st->chip_info.multi;
y = ((data[ind + 2] << 8)|data[ind + 3])*st->chip_info.multi;
z = ((data[ind + 4] << 8)|data[ind + 5])*st->chip_info.multi;
@@ -1953,7 +2760,7 @@ static void inv_report_gyro_accl(struct inv_gyro_state_s *st, s64 t,
}
ind += 6;
}
- if (conf->gyro_fifo_enable | conf->dmp_on) {
+ if (conf->gyro_fifo_enable) {
x = (data[ind] << 8) | data[ind + 1];
y = (data[ind + 2] << 8) | data[ind + 3];
z = (data[ind + 4] << 8) | data[ind + 5];
@@ -1965,18 +2772,6 @@ static void inv_report_gyro_accl(struct inv_gyro_state_s *st, s64 t,
}
ind += 6;
}
- if (conf->dmp_on) {
- /* report tap information */
- if (data[ind + 1] & 1) {
- input_report_rel(st->idev_dmp, REL_RX, data[ind+3]);
- input_sync(st->idev_dmp);
- }
- /* report orientation information */
- if (data[ind + 1] & 2) {
- input_report_rel(st->idev_dmp, REL_RY, data[ind+2]);
- input_sync(st->idev_dmp);
- }
- }
if (conf->accl_fifo_enable | conf->gyro_fifo_enable) {
input_report_rel(st->idev, REL_MISC, (unsigned int)(t >> 32));
input_report_rel(st->idev, REL_WHEEL,
@@ -1985,55 +2780,6 @@ static void inv_report_gyro_accl(struct inv_gyro_state_s *st, s64 t,
}
}
-static int inv_report_compass(struct inv_gyro_state_s *st, s64 t)
-{
- short x, y, z;
- int result;
- unsigned char data[8];
-
- /*mpu_memory_read(st->sl_handle,
- st->i2c_addr,
- 14,
- 10, data);*/
- /*divider and counter is used to decrease the speed of read in
- high frequency sample rate*/
- if (st->compass_divider == st->compass_counter) {
- /*read from external sensor data register */
- result = inv_i2c_read(st, REG_EXT_SENS_DATA_00, 8, data);
- if (result)
- return result;
-
- /* data[7] is status 2 register */
- /*for AKM8975, bit 2 and 3 should be all be zero*/
- /* for AMK8963, bit 3 should be zero*/
- if ((DATA_AKM_DRDY == data[0]) &&
- (0 == (data[7] & DATA_AKM_STAT_MASK))) {
- unsigned char *sens;
- sens = st->chip_info.compass_sens;
- x = (short)((data[2] << 8) | data[1]);
- y = (short)((data[4] << 8) | data[3]);
- z = (short)((data[6] << 8) | data[5]);
- x = ((x * (sens[0] + 128)) >> 8);
- y = ((y * (sens[1] + 128)) >> 8);
- z = ((z * (sens[2] + 128)) >> 8);
- input_report_rel(st->idev_compass, REL_X, x);
- input_report_rel(st->idev_compass, REL_Y, y);
- input_report_rel(st->idev_compass, REL_Z, z);
- input_report_rel(st->idev_compass, REL_MISC,
- (unsigned int)(t >> 32));
- input_report_rel(st->idev_compass, REL_WHEEL,
- (unsigned int)(t & 0xffffffff));
- input_sync(st->idev_compass);
- }
- st->compass_counter = 0;
-
- } else if (st->compass_divider != 0) {
- st->compass_counter++;
- }
-
- return 0;
-}
-
/**
* inv_read_fifo() - Transfer data from FIFO to ring buffer.
*/
@@ -2051,40 +2797,42 @@ static irqreturn_t inv_read_fifo(int irq, void *dev_id)
st = (struct inv_gyro_state_s *)dev_id;
reg = st->reg;
- if (st->chip_config.is_asleep)
- goto end_session;
- if (!(st->chip_config.enable))
- goto end_session;
-
- if (!(st->chip_config.accl_fifo_enable |
- st->chip_config.gyro_fifo_enable |
- st->chip_config.dmp_on |
- st->chip_config.compass_enable))
- goto end_session;
-
- if (st->chip_config.dmp_on && st->flick.int_on) {
- /*dmp interrupt status */
- inv_i2c_read(st, REG_DMP_INT_STATUS, 2, data);
- if (data[0] & 8) {
- input_report_rel(st->idev_dmp, REL_RZ, data[0]);
- input_sync(st->idev_dmp);
+ timestamp = get_time_ns();
+ if ((!(st->hw.fifo_en & BIT_TEMP_FIFO_EN)) &&
+ st->chip_config.gyro_enable) {
+ result = inv_i2c_read(st, st->reg->temperature, 2, data);
+ if (!result) {
+ mutex_lock(&st->mutex_temp);
+ st->temp_val = (data[0] << 8) | data[1];
+ st->temp_ts = timestamp;
+ mutex_unlock(&st->mutex_temp);
}
}
- if (st->chip_config.lpa_mode) {
+ if (st->mot_cnt)
+ st->mot_cnt--;
+ if (st->lpa_enable || (st->hw.int_enable & BIT_MOT_EN)) {
+ if (st->hw.int_enable & BIT_MOT_EN) {
+ st->mot_cnt = st->chip_config.mot_cnt;
+ st->mot_enable = false;
+ nvi_int_enable_wr(st, true);
+ if (st->mot_dbg)
+ pr_info("%s motion detect off", __func__);
+ }
result = inv_i2c_read(st, reg->raw_accl, 6, data);
if (result)
goto end_session;
- inv_report_gyro_accl(st, get_time_ns(), data);
+ inv_report_gyro_accl(st, timestamp, data);
+ if (st->mot_enable && st->mot_dbg)
+ pr_info("%s SENDING MOTION DETECT DATA", __func__);
+ if (st->mot_enable && (!st->mot_cnt))
+ nvi_int_enable_wr(st, true);
goto end_session;
}
- if (st->chip_config.dmp_on)
- bytes_per_datum = BYTES_FOR_DMP;
- else
- bytes_per_datum = (st->chip_config.accl_fifo_enable +
- st->chip_config.gyro_fifo_enable)*BYTES_PER_SENSOR;
+ bytes_per_datum = (st->chip_config.accl_fifo_enable +
+ st->chip_config.gyro_fifo_enable)*BYTES_PER_SENSOR;
fifo_count = 0;
if (bytes_per_datum != 0) {
result = inv_i2c_read(st, reg->fifo_count_h, 2, data);
@@ -2102,22 +2850,14 @@ static irqreturn_t inv_read_fifo(int irq, void *dev_id)
goto flush_fifo;
/* Timestamp mismatch. */
- if (kfifo_len(&st->trigger.timestamps) <
- fifo_count / bytes_per_datum)
+ if (kfifo_len(&st->trigger.timestamps) < (fifo_count /
+ bytes_per_datum))
goto flush_fifo;
- if (kfifo_len(&st->trigger.timestamps) >
- fifo_count / bytes_per_datum + TIME_STAMP_TOR) {
- if (st->chip_config.dmp_on) {
- result = kfifo_to_user(&st->trigger.timestamps,
- &timestamp, sizeof(timestamp), &copied);
- if (result)
- goto flush_fifo;
-
- } else {
- goto flush_fifo;
- }
- }
+ if (kfifo_len(&st->trigger.timestamps) > (fifo_count /
+ bytes_per_datum +
+ TIME_STAMP_TOR))
+ goto flush_fifo;
}
if (bytes_per_datum == 0) {
@@ -2142,16 +2882,14 @@ static irqreturn_t inv_read_fifo(int irq, void *dev_id)
fifo_count -= bytes_per_datum;
}
- if (st->chip_config.compass_enable)
- inv_report_compass(st, timestamp);
+ nvi_aux_read(st);
end_session:
return IRQ_HANDLED;
flush_fifo:
/* Flush HW and SW FIFOs. */
- inv_reset_fifo(st);
- inv_clear_kfifo(st);
+ nvi_reset(st, true, false);
return IRQ_HANDLED;
}
@@ -2172,7 +2910,7 @@ static irqreturn_t inv_irq_handler(int irq, void *dev_id)
spin_lock(&st->time_stamp_lock);
catch_up = 0;
while ((time_since_last_irq > st->irq_dur_us*2) &&
- (catch_up < MAX_CATCH_UP) && (0 == st->chip_config.lpa_mode)) {
+ (catch_up < MAX_CATCH_UP) && (!st->lpa_enable)) {
st->last_isr_time += st->irq_dur_us * ONE_K_HZ;
result = kfifo_in(&st->trigger.timestamps,
&st->last_isr_time, 1);
@@ -2186,25 +2924,31 @@ static irqreturn_t inv_irq_handler(int irq, void *dev_id)
return IRQ_WAKE_THREAD;
}
+static int inv_pm(struct inv_gyro_state_s *inf, int pm_req)
+{
+ int err;
+
+ if (inf->nvi) {
+ err = nvi_pm(inf, pm_req);
+ } else {
+ if ((pm_req > NVI_PM_OFF) || (pm_req == NVI_PM_AUTO))
+ err = set_power_mpu3050(inf, 1);
+ else
+ err = set_power_mpu3050(inf, 0);
+ }
+ return err;
+}
+
#ifdef CONFIG_PM
static int inv_suspend(struct device *dev)
{
int result;
struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- if (inv_set_power_state(st, 0))
- dev_err(dev, "inv_set_power_state in inv_suspend failed\n");
- /* vdd is used to gate the vlogic. Disable vlogic first. */
- if (st->inv_regulator.regulator_vdd &&
- st->inv_regulator.regulator_vlogic) {
- result = regulator_disable(st->inv_regulator.regulator_vlogic);
- if (result < 0)
- dev_err(dev, "regulator_disable for vlogic failed\n");
- result = regulator_disable(st->inv_regulator.regulator_vdd);
- if (result < 0)
- dev_err(dev, "regulator_disable for vdd failed\n");
- }
- return 0;
+ result = inv_pm(st, NVI_PM_OFF_FORCE);
+ if (result)
+ dev_err(dev, "%s ERR\n", __func__);
+ return result;
}
static int inv_resume(struct device *dev)
@@ -2212,19 +2956,10 @@ static int inv_resume(struct device *dev)
int result;
struct inv_gyro_state_s *st = dev_get_drvdata(dev);
- /* vdd is used to gate the vlogic. Enable vdd first. */
- if (st->inv_regulator.regulator_vdd &&
- st->inv_regulator.regulator_vlogic) {
- result = regulator_enable(st->inv_regulator.regulator_vdd);
- if (result < 0)
- dev_err(dev, "regulator_enable for vdd failed\n");
- result = regulator_enable(st->inv_regulator.regulator_vlogic);
- if (result < 0)
- dev_err(dev, "regulator_enable for vlogic failed\n");
- }
- if (inv_set_power_state(st, 1))
- dev_err(dev, "inv_set_power_state in inv_resume failed\n");
- return 0;
+ result = inv_pm(st, NVI_PM_AUTO);
+ if (result)
+ dev_err(dev, "%s ERR\n", __func__);
+ return result;
}
static const struct dev_pm_ops inv_pm_ops = {
@@ -2233,343 +2968,235 @@ static const struct dev_pm_ops inv_pm_ops = {
};
#endif
-static DEVICE_ATTR(raw_gyro, S_IRUGO, inv_raw_gyro_show, NULL);
-static DEVICE_ATTR(raw_accl, S_IRUGO, inv_raw_accl_show, NULL);
-static DEVICE_ATTR(temperature, S_IRUGO, inv_temperature_show, NULL);
-static DEVICE_ATTR(fifo_rate, S_IRUGO | S_IWUSR, inv_fifo_rate_show,
- inv_fifo_rate_store);
-static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, inv_enable_show,
- inv_enable_store);
-static DEVICE_ATTR(gyro_fifo_enable, S_IRUGO | S_IWUSR,
- inv_gyro_fifo_enable_show, inv_gyro_fifo_enable_store);
-static DEVICE_ATTR(gyro_enable, S_IRUGO | S_IWUSR, inv_gyro_enable_show,
- inv_gyro_enable_store);
+static DEVICE_ATTR(gyro_enable, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_gyro_enable_show, nvi_gyro_enable_store);
+static DEVICE_ATTR(gyro_fifo_enable, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_gyro_fifo_enable_show, nvi_gyro_fifo_enable_store);
+static DEVICE_ATTR(gyro_delay, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_gyro_delay_show, inv_gyro_delay_store);
+static DEVICE_ATTR(gyro_resolution, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_gyro_resolution_show, nvi_gyro_resolution_store);
+static DEVICE_ATTR(gyro_max_range, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_gyro_max_range_show, nvi_gyro_max_range_store);
+static DEVICE_ATTR(gyro_orientation, S_IRUGO,
+ inv_gyro_orientation_show, NULL);
+static DEVICE_ATTR(raw_gyro, S_IRUGO,
+ inv_raw_gyro_show, NULL);
+static DEVICE_ATTR(accl_enable, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_accl_enable_show, nvi_accl_enable_store);
static DEVICE_ATTR(accl_fifo_enable, S_IRUGO | S_IWUSR,
- inv_accl_fifo_enable_show, inv_accl_fifo_enable_store);
-static DEVICE_ATTR(accl_enable, S_IRUGO | S_IWUSR, inv_accl_enable_show,
- inv_accl_enable_store);
-static DEVICE_ATTR(accl_fs, S_IRUGO | S_IWUSR, inv_accl_fs_show,
- inv_accl_fs_store);
-static DEVICE_ATTR(gyro_fs, S_IRUGO | S_IWUSR, inv_gyro_fs_show,
- inv_gyro_fs_store);
-static DEVICE_ATTR(clock_source, S_IRUGO, inv_clk_src_show, NULL);
-static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, inv_power_state_show,
- inv_power_state_store);
-static DEVICE_ATTR(firmware_loaded, S_IRUGO | S_IWUSR,
- inv_firmware_loaded_show, inv_firmware_loaded_store);
-static DEVICE_ATTR(lpa_mode, S_IRUGO | S_IWUSR, inv_lpa_mode_show,
- inv_lpa_mode_store);
-static DEVICE_ATTR(lpa_freq, S_IRUGO | S_IWUSR, inv_lpa_freq_show,
- inv_lpa_freq_store);
-static DEVICE_ATTR(compass_enable, S_IRUGO | S_IWUSR, inv_compass_en_show,
- inv_compass_en_store);
-static DEVICE_ATTR(compass_scale, S_IRUGO | S_IWUSR, inv_compass_scale_show,
- inv_compass_scale_store);
-static DEVICE_ATTR(temp_scale, S_IRUGO, inv_temp_scale_show, NULL);
-static DEVICE_ATTR(temp_offset, S_IRUGO, inv_temp_offset_show, NULL);
-static DEVICE_ATTR(reg_dump, S_IRUGO, inv_reg_dump_show, NULL);
-static DEVICE_ATTR(self_test, S_IRUGO, inv_self_test_show, NULL);
-static DEVICE_ATTR(key, S_IRUGO | S_IWUSR, inv_key_show, inv_key_store);
-static DEVICE_ATTR(gyro_matrix, S_IRUGO, inv_gyro_matrix_show, NULL);
-static DEVICE_ATTR(accl_matrix, S_IRUGO, inv_accl_matrix_show, NULL);
-static DEVICE_ATTR(compass_matrix, S_IRUGO, inv_compass_matrix_show, NULL);
-static DEVICE_ATTR(accl_bias, S_IRUGO, inv_get_accl_bias_show, NULL);
-static DEVICE_ATTR(flick_lower, S_IRUGO | S_IWUSR, inv_flick_lower_show,
- inv_flick_lower_store);
-static DEVICE_ATTR(flick_upper, S_IRUGO | S_IWUSR, inv_flick_upper_show,
- inv_flick_upper_store);
-static DEVICE_ATTR(flick_counter, S_IRUGO | S_IWUSR, inv_flick_counter_show,
- inv_flick_counter_store);
-static DEVICE_ATTR(flick_message_on, S_IRUGO | S_IWUSR, inv_flick_msg_on_show,
- inv_flick_msg_on_store);
-static DEVICE_ATTR(flick_int_on, S_IRUGO | S_IWUSR, inv_flick_int_on_show,
- inv_flick_int_on_store);
-static DEVICE_ATTR(flick_axis, S_IRUGO | S_IWUSR, inv_flick_axis_show,
- inv_flick_axis_store);
-static DEVICE_ATTR(pedometer_time, S_IRUGO | S_IWUSR, inv_pedometer_time_show,
- inv_pedometer_time_store);
-static DEVICE_ATTR(pedometer_steps, S_IRUGO | S_IWUSR,
- inv_pedometer_steps_show, inv_pedometer_steps_store);
+ nvi_accl_fifo_enable_show, nvi_accl_fifo_enable_store);
+static DEVICE_ATTR(accl_delay, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_accl_delay_show, nvi_accl_delay_store);
+static DEVICE_ATTR(accl_resolution, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_accl_resolution_show, nvi_accl_resolution_store);
+static DEVICE_ATTR(accl_max_range, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_accl_max_range_show, nvi_accl_max_range_store);
+static DEVICE_ATTR(accl_orientation, S_IRUGO,
+ inv_accl_matrix_show, NULL);
+static DEVICE_ATTR(raw_accl, S_IRUGO,
+ inv_raw_accl_show, NULL);
+static DEVICE_ATTR(lpa_delay, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_lpa_delay_enable_show, nvi_lpa_delay_enable_store);
+static DEVICE_ATTR(motion_threshold, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_motion_thr_show, nvi_motion_thr_store);
+static DEVICE_ATTR(motion_duration, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_motion_dur_show, nvi_motion_dur_store);
+static DEVICE_ATTR(motion_count, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_motion_count_show, nvi_motion_count_store);
+static DEVICE_ATTR(motion_control, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_motion_ctrl_show, nvi_motion_ctrl_store);
+static DEVICE_ATTR(temp_scale, S_IRUGO,
+ inv_temp_scale_show, NULL);
+static DEVICE_ATTR(temp_offset, S_IRUGO,
+ inv_temp_offset_show, NULL);
+static DEVICE_ATTR(temperature, S_IRUGO,
+ inv_temperature_show, NULL);
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_enable_show, nvi_enable_store);
+static DEVICE_ATTR(dbg_reg, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_dbg_reg_show, nvi_dbg_reg_store);
+static DEVICE_ATTR(dbg_dat, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_dbg_dat_show, nvi_dbg_dat_store);
+static DEVICE_ATTR(dbg_i2c_addr, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_dbg_i2c_addr_show, nvi_dbg_i2c_addr_store);
+static DEVICE_ATTR(aux_dbg, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_aux_dbg_show, nvi_aux_dbg_store);
+static DEVICE_ATTR(mot_dbg, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_mot_dbg_show, nvi_mot_dbg_store);
+static DEVICE_ATTR(key, S_IRUGO | S_IWUSR,
+ inv_key_show, inv_key_store);
+static DEVICE_ATTR(reg_dump, S_IRUGO,
+ inv_reg_dump_show, NULL);
+static DEVICE_ATTR(min_delay_us, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_min_delay_us_show, nvi_min_delay_us_store);
static struct device_attribute *inv_attributes[] = {
+ &dev_attr_gyro_delay,
+ &dev_attr_gyro_orientation,
&dev_attr_raw_gyro,
- &dev_attr_temperature,
- &dev_attr_fifo_rate,
- &dev_attr_enable,
- &dev_attr_clock_source,
- &dev_attr_power_state,
- &dev_attr_gyro_fs,
&dev_attr_temp_scale,
&dev_attr_temp_offset,
+ &dev_attr_temperature,
&dev_attr_reg_dump,
- &dev_attr_self_test,
&dev_attr_key,
- &dev_attr_gyro_matrix,
+#if DEBUG_SYSFS_INTERFACE
+ &dev_attr_dbg_reg,
+ &dev_attr_dbg_dat,
+ &dev_attr_dbg_i2c_addr,
+#endif /* DEBUG_SYSFS_INTERFACE */
NULL
};
static struct device_attribute *inv_mpu6050_attributes[] = {
- &dev_attr_gyro_fifo_enable,
&dev_attr_gyro_enable,
- &dev_attr_accl_fifo_enable,
+ &dev_attr_gyro_fifo_enable,
+ &dev_attr_gyro_max_range,
+ &dev_attr_gyro_resolution,
&dev_attr_accl_enable,
- &dev_attr_accl_fs,
- &dev_attr_accl_bias,
+ &dev_attr_accl_fifo_enable,
+ &dev_attr_accl_delay,
+ &dev_attr_accl_max_range,
+ &dev_attr_accl_resolution,
+ &dev_attr_accl_orientation,
&dev_attr_raw_accl,
- &dev_attr_accl_matrix,
- &dev_attr_firmware_loaded,
- &dev_attr_lpa_mode,
- &dev_attr_lpa_freq,
- &dev_attr_flick_lower,
- &dev_attr_flick_upper,
- &dev_attr_flick_counter,
- &dev_attr_flick_message_on,
- &dev_attr_flick_int_on,
- &dev_attr_flick_axis,
- &dev_attr_pedometer_time,
- &dev_attr_pedometer_steps,
- NULL
-};
-
-static struct device_attribute *inv_compass_attributes[] = {
- &dev_attr_compass_enable,
- &dev_attr_compass_scale,
- &dev_attr_compass_matrix,
+ &dev_attr_lpa_delay,
+ &dev_attr_motion_threshold,
+ &dev_attr_motion_duration,
+ &dev_attr_motion_count,
+ &dev_attr_motion_control,
+ &dev_attr_enable,
+#if DEBUG_SYSFS_INTERFACE
+ &dev_attr_min_delay_us,
+ &dev_attr_aux_dbg,
+ &dev_attr_mot_dbg,
+#endif /* DEBUG_SYSFS_INTERFACE */
NULL
};
-static void inv_init_regulator(struct inv_gyro_state_s *st,
- struct i2c_client *client)
-{
- int result;
-
- /* Power regulator registration*/
- st->inv_regulator.regulator_vdd =
- devm_regulator_get(&client->dev, "vdd");
- if (IS_ERR(st->inv_regulator.regulator_vdd)) {
- dev_info(&client->adapter->dev,
- "regulator_get for vdd failed: %s\n",
- dev_name(&client->dev));
- dev_info(&client->adapter->dev,
- "Error code for vdd: %d",
- PTR_ERR(st->inv_regulator.regulator_vdd));
- goto err_null_regulator;
- }
-
- st->inv_regulator.regulator_vlogic =
- devm_regulator_get(&client->dev, "vlogic");
- if (IS_ERR(st->inv_regulator.regulator_vlogic)) {
- dev_info(&client->adapter->dev,
- "regulator_get for vlogic failed: %s\n",
- dev_name(&client->dev));
- dev_info(&client->adapter->dev,
- "Error code for vlogic: %d\n",
- PTR_ERR(st->inv_regulator.regulator_vlogic));
- goto err_put_regulator;
- }
-
- dev_info(&client->adapter->dev,
- "regulator_get for vdd and vlogic succeeded: %s\n",
- dev_name(&client->dev));
-
- result = regulator_enable(st->inv_regulator.regulator_vdd);
- if (result < 0)
- dev_err(&client->adapter->dev,
- "regulator_enable for vdd failed: %d\n", result);
-
- result = regulator_enable(st->inv_regulator.regulator_vlogic);
- if (result < 0)
- dev_err(&client->adapter->dev,
- "regulator_enable for vlogic failed: %d\n", result);
-
- return;
-
-err_put_regulator:
- devm_regulator_put(st->inv_regulator.regulator_vdd);
-err_null_regulator:
- st->inv_regulator.regulator_vdd = NULL;
- st->inv_regulator.regulator_vlogic = NULL;
-}
-
-static int inv_setup_compass(struct inv_gyro_state_s *st)
-{
- int result;
- unsigned char data[4];
-
- result = inv_i2c_read(st, 1, 1, data);
- if (result)
- return result;
-
- data[0] &= ~(0x80);
- data[0] |= (st->plat_data.level_shifter << 7);
- /*set up VDDIO register */
- result = inv_i2c_single_write(st, 1, data[0]);
- if (result)
- return result;
-
- /* set to bypass mode */
- result = inv_i2c_single_write(st, REG_INT_PIN_CFG, BIT_BYPASS_EN);
- if (result)
- return result;
-
- /*read secondary i2c ID register */
- result = inv_secondary_read(REG_AKM_ID, 2, data);
- if (result)
- return result;
-
- if (data[0] != DATA_AKM_ID)
- return -ENXIO;
-
- /*set AKM to Fuse ROM access mode */
- result = inv_secondary_write(REG_AKM_MODE, DATA_AKM_MODE_PW_FR);
- if (result)
- return result;
-
- result = inv_secondary_read(REG_AKM_SENSITIVITY, 3,
- st->chip_info.compass_sens);
- if (result)
- return result;
-
- /*revert to power down mode */
- result = inv_secondary_write(REG_AKM_MODE, DATA_AKM_MODE_PW_DN);
- if (result)
- return result;
-
- printk(KERN_ERR"senx=%d, seny=%d,senz=%d\n",
- st->chip_info.compass_sens[0],
- st->chip_info.compass_sens[1],
- st->chip_info.compass_sens[2]);
- /*restore to non-bypass mode */
- result = inv_i2c_single_write(st, REG_INT_PIN_CFG, 0);
- if (result)
- return result;
-
- /*setup master mode and master clock and ES bit*/
- result = inv_i2c_single_write(st, REG_I2C_MST_CTRL, BIT_WAIT_FOR_ES);
- if (result)
- return result;
-
- /* slave 0 is used to read data from compass */
- /*read mode */
- result = inv_i2c_single_write(st, REG_I2C_SLV0_ADDR, BIT_I2C_READ|
- st->plat_data.secondary_i2c_addr);
- if (result)
- return result;
-
- /* AKM status register address is 2 */
- result = inv_i2c_single_write(st, REG_I2C_SLV0_REG, REG_AKM_STATUS);
- if (result)
- return result;
-
- /* slave 0 is enabled at the beginning, read 8 bytes from here */
- result = inv_i2c_single_write(st, REG_I2C_SLV0_CTRL, BIT_SLV_EN | 8);
- if (result)
- return result;
-
- /*slave 1 is used for AKM mode change only*/
- /*write mode, slave address 0x0E */
- result = inv_i2c_single_write(st, REG_I2C_SLV1_ADDR,
- st->plat_data.secondary_i2c_addr);
- if (result)
- return result;
-
- /* AKM mode register address is 0x0A */
- result = inv_i2c_single_write(st, REG_I2C_SLV1_REG, REG_AKM_MODE);
- if (result)
- return result;
-
- /* slave 1 is enabled, byte length is 1 */
- result = inv_i2c_single_write(st, REG_I2C_SLV1_CTRL, BIT_SLV_EN | 1);
- if (result)
- return result;
-
- /* output data for slave 1 is fixed, single measure mode*/
- st->compass_scale = 1;
- if (COMPASS_ID_AK8975 == st->plat_data.sec_slave_id) {
- st->compass_st_upper[0] = DATA_AKM8975_ST_X_UP;
- st->compass_st_upper[1] = DATA_AKM8975_ST_Y_UP;
- st->compass_st_upper[2] = DATA_AKM8975_ST_Z_UP;
- st->compass_st_lower[0] = DATA_AKM8975_ST_X_LW;
- st->compass_st_lower[1] = DATA_AKM8975_ST_Y_LW;
- st->compass_st_lower[2] = DATA_AKM8975_ST_Z_LW;
- data[0] = 1;
- } else if (COMPASS_ID_AK8972 == st->plat_data.sec_slave_id) {
- st->compass_st_upper[0] = DATA_AKM8972_ST_X_UP;
- st->compass_st_upper[1] = DATA_AKM8972_ST_Y_UP;
- st->compass_st_upper[2] = DATA_AKM8972_ST_Z_UP;
- st->compass_st_lower[0] = DATA_AKM8972_ST_X_LW;
- st->compass_st_lower[1] = DATA_AKM8972_ST_Y_LW;
- st->compass_st_lower[2] = DATA_AKM8972_ST_Z_LW;
- data[0] = 1;
- } else if (COMPASS_ID_AK8963 == st->plat_data.sec_slave_id) {
- st->compass_st_upper[0] = DATA_AKM8963_ST_X_UP;
- st->compass_st_upper[1] = DATA_AKM8963_ST_Y_UP;
- st->compass_st_upper[2] = DATA_AKM8963_ST_Z_UP;
- st->compass_st_lower[0] = DATA_AKM8963_ST_X_LW;
- st->compass_st_lower[1] = DATA_AKM8963_ST_Y_LW;
- st->compass_st_lower[2] = DATA_AKM8963_ST_Z_LW;
- data[0] = (1 | (st->compass_scale << 4));
- }
- result = inv_i2c_single_write(st, REG_I2C_SLV1_DO, data[0]);
- if (result)
- return result;
-
- /* slave 0 and 1 timer action is enabled every sample*/
- result = inv_i2c_single_write(st, REG_I2C_MST_DELAY_CTRL,
- BIT_SLV0_DLY_EN | BIT_SLV1_DLY_EN);
- return result;
-}
-
static int inv_check_chip_type(struct inv_gyro_state_s *st,
const struct i2c_device_id *id)
{
struct inv_reg_map_s *reg;
- int result;
+ int result = 0;
reg = st->reg;
st->mpu_slave = NULL;
- if (!strcmp(id->name, "itg3500"))
+ if (!strcmp(id->name, "itg3500")) {
st->chip_type = INV_ITG3500;
- else if (!strcmp(id->name, "mpu3050")) {
+ st->nvi = false;
+ } else if (!strcmp(id->name, "mpu3050")) {
st->chip_type = INV_MPU3050;
inv_setup_reg_mpu3050(reg);
- } else if (!strcmp(id->name, "mpu6050"))
+ st->nvi = false;
+ } else if (!strcmp(id->name, "mpu6050")) {
st->chip_type = INV_MPU6050;
- else if (!strcmp(id->name, "mpu9150"))
+ st->nvi = true;
+ } else if (!strcmp(id->name, "mpu9150")) {
st->chip_type = INV_MPU9150;
- if (INV_MPU9150 == st->chip_type) {
- st->plat_data.sec_slave_type = SECONDARY_SLAVE_TYPE_COMPASS;
- st->plat_data.sec_slave_id = COMPASS_ID_AK8975;
- /*is MPU9150 i2c address hard coded? */
- /*st->plat_data.secondary_i2c_addr = 0xE;*/
- st->has_compass = 1;
+ st->nvi = true;
}
if (SECONDARY_SLAVE_TYPE_ACCEL == st->plat_data.sec_slave_type) {
if (st->plat_data.sec_slave_id == ACCEL_ID_KXTF9)
inv_register_kxtf9_slave(st);
}
- if (SECONDARY_SLAVE_TYPE_COMPASS == st->plat_data.sec_slave_type)
- st->has_compass = 1;
- else
- st->has_compass = 0;
- st->chip_config.gyro_enable = 1;
- /*reset register to power up default*/
- result = inv_i2c_single_write(st, reg->pwr_mgmt_1, BIT_RESET);
- if (result)
- return result;
+ if (st->nvi) {
+ nvi_pm_init(st);
+ } else {
+ nvi_vreg_init(st);
+ /*reset register to power up default*/
+ result = inv_i2c_single_write(st, reg->pwr_mgmt_1, 0);
+ result = inv_i2c_single_write(st, reg->pwr_mgmt_1, BIT_RESET);
+ if (!result)
+ mdelay(POWER_UP_TIME);
+ }
+ return result;
+}
- mdelay(POWER_UP_TIME);
- result = inv_set_power_state(st, 1);
- if (result)
- return result;
+/**
+ * inv_init_config() - Initialize hardware, disable FIFO.
+ * @st: Device driver instance.
+ * Initial configuration:
+ * FSR: +/- 2000DPS
+ * DLPF: 42Hz
+ * FIFO rate: 50Hz
+ * Clock source: Gyro PLL
+ */
+static int inv_init_config(struct inv_gyro_state_s *st)
+{
+ st->chip_config.min_delay_us = MIN_FIFO_RATE;
+ st->chip_config.lpf = INV_FILTER_42HZ;
+ st->chip_config.gyro_enable = 0;
+ st->chip_config.gyro_fifo_enable = 0;
+ st->chip_config.gyro_fsr = INV_FSR_2000DPS;
+ st->chip_config.accl_enable = 0;
+ st->chip_config.accl_fifo_enable = 0;
+ st->chip_config.accl_fsr = INV_FS_02G;
+ st->chip_config.mot_dur = 1;
+ st->chip_config.mot_ctrl = 1;
+ st->chip_config.mot_cnt = 10;
+ st->irq_dur_us = 20 * ONE_K_HZ;
+ st->chip_config.fifo_rate = 50;
+ st->chip_config.enable = 0;
+ st->chip_config.dmp_on = 0;
+ st->chip_config.firmware_loaded = 0;
+ st->chip_config.prog_start_addr = DMP_START_ADDR;
+ return 0;
+}
- if (st->has_compass) {
- result = inv_setup_compass(st);
- if (result)
- return result;
+static void inv_input_close(struct input_dev *d)
+{
+ struct inv_gyro_state_s *st;
+
+ st = input_get_drvdata(d);
+ inv_pm(st, NVI_PM_OFF_FORCE);
+ nvi_vreg_exit(st);
+}
+
+/**
+ * inv_setup_input() - internal setup input device.
+ * @st: Device driver instance.
+ * @**idev_in pointer to input device
+ * @*client i2c client
+ * @*name name of the input device.
+ */
+static int inv_setup_input(struct inv_gyro_state_s *st,
+ struct input_dev **idev_in,
+ struct i2c_client *client, unsigned char *name)
+{
+ int result;
+ struct input_dev *idev;
+
+ idev = input_allocate_device();
+ if (!idev) {
+ result = -ENOMEM;
+ return result;
}
- return 0;
+ /* Setup input device. */
+ idev->name = name;
+ idev->id.bustype = BUS_I2C;
+ idev->id.product = 'S';
+ idev->id.vendor = ('I'<<8) | 'S';
+ idev->id.version = 1;
+ idev->dev.parent = &client->dev;
+ /* Open and close method. */
+ if (strcmp(name, "INV_DMP"))
+ idev->close = inv_input_close;
+ input_set_capability(idev, EV_REL, REL_X);
+ input_set_capability(idev, EV_REL, REL_Y);
+ input_set_capability(idev, EV_REL, REL_Z);
+ input_set_capability(idev, EV_REL, REL_RX);
+ input_set_capability(idev, EV_REL, REL_RY);
+ input_set_capability(idev, EV_REL, REL_RZ);
+ input_set_capability(idev, EV_REL, REL_MISC);
+ input_set_capability(idev, EV_REL, REL_WHEEL);
+ input_set_drvdata(idev, st);
+ result = input_register_device(idev);
+ if (result)
+ input_free_device(idev);
+ *idev_in = idev;
+ return result;
}
static int inv_create_input(struct inv_gyro_state_s *st,
@@ -2578,7 +3205,7 @@ static int inv_create_input(struct inv_gyro_state_s *st,
int result;
idev = NULL;
- result = inv_setup_input(st, &idev, client, st->hw->name);
+ result = inv_setup_input(st, &idev, client, st->hw_s->name);
if (result)
return result;
@@ -2587,26 +3214,10 @@ static int inv_create_input(struct inv_gyro_state_s *st,
return 0;
result = inv_setup_input(st, &idev, client, "INV_DMP");
- if (result) {
+ if (result)
input_unregister_device(st->idev);
- return result;
- }
-
- st->idev_dmp = idev;
- if (!st->has_compass)
- return 0;
-
- if (st->has_compass) {
- result = inv_setup_input(st, &idev, client, "INV_COMPASS");
- if (result) {
- input_unregister_device(st->idev);
- input_unregister_device(st->idev_dmp);
- return result;
- }
-
- st->idev_compass = idev;
- }
-
+ else
+ st->idev_dmp = idev;
return 0;
}
@@ -2691,17 +3302,8 @@ static int create_sysfs_interfaces(struct inv_gyro_state_s *st)
if (result < 0)
goto exit_remove_bin_file;
- if (!st->has_compass)
- return 0;
-
- result = create_device_attributes(st->inv_dev, inv_compass_attributes);
- if (result < 0)
- goto exit_remove_6050_attributes;
-
return 0;
-exit_remove_6050_attributes:
- remove_device_attributes(st->inv_dev, inv_mpu6050_attributes);
exit_remove_bin_file:
sysfs_remove_bin_file(&st->inv_dev->kobj, &dmp_firmware);
exit_remove_device_attributes:
@@ -2725,20 +3327,65 @@ static void remove_sysfs_interfaces(struct inv_gyro_state_s *st)
remove_device_attributes(st->inv_dev, inv_mpu6050_attributes);
if (INV_MPU3050 == st->chip_type)
inv_mpu3050_remove_sysfs(st);
- if (st->has_compass)
- remove_device_attributes(st->inv_dev, inv_compass_attributes);
device_destroy(st->inv_class, inv_device_dev_t);
class_destroy(st->inv_class);
st->inv_dev = NULL;
st->inv_class = NULL;
}
-static int inv_mod_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static void nvi_shutdown(struct i2c_client *client)
+{
+ struct inv_gyro_state_s *inf;
+ int i;
+
+ inf = i2c_get_clientdata(client);
+ if (inf != NULL) {
+ if (inf->nvi) {
+ for (i = 0; i < AUX_PORT_SPECIAL; i++) {
+ if (inf->aux.port[i].nmp.shutdown_bypass) {
+ nvi_aux_bypass_enable(inf, true);
+ break;
+ }
+ }
+ }
+ inf->shutdown = true;
+ if (inf->inv_dev)
+ remove_sysfs_interfaces(inf);
+ kfifo_free(&inf->trigger.timestamps);
+ free_irq(client->irq, inf);
+ if (inf->idev)
+ input_unregister_device(inf->idev);
+ if ((INV_ITG3500 != inf->chip_type) && (inf->idev_dmp))
+ input_unregister_device(inf->idev_dmp);
+ }
+}
+
+static int nvi_remove(struct i2c_client *client)
+{
+ struct inv_gyro_state_s *inf;
+
+ nvi_shutdown(client);
+ inf = i2c_get_clientdata(client);
+ if (inf != NULL) {
+ if (inf->nvi) {
+ nvi_pm_exit(inf);
+ } else {
+ inv_pm(inf, NVI_PM_OFF_FORCE);
+ nvi_vreg_exit(inf);
+ }
+ kfree(inf);
+ }
+ dev_info(&client->dev, "Gyro module removed.\n");
+ return 0;
+}
+
+static int nvi_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct inv_gyro_state_s *st;
int result;
+ pr_info("%s: Probe name %s\n", __func__, id->name);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
result = -ENODEV;
goto out_no_free;
@@ -2750,24 +3397,22 @@ static int inv_mod_probe(struct i2c_client *client,
goto out_no_free;
}
- inv_init_regulator(st, client);
-
/* Make state variables available to all _show and _store functions. */
i2c_set_clientdata(client, st);
st->i2c = client;
st->sl_handle = client->adapter;
st->reg = (struct inv_reg_map_s *)&chip_reg ;
- st->hw = (struct inv_hw_s *)hw_info;
+ st->hw_s = (struct inv_hw_s *)hw_info;
st->i2c_addr = client->addr;
st->plat_data =
- *(struct mpu_platform_data *)dev_get_platdata(&client->dev);
+ *(struct mpu_platform_data *)dev_get_platdata(&client->dev);
/* power is turned on inside check chip type*/
result = inv_check_chip_type(st, id);
if (result)
goto out_free;
- st->hw = (struct inv_hw_s *)(hw_info + st->chip_type);
+ st->hw_s = (struct inv_hw_s *)(hw_info + st->chip_type);
if (INV_MPU3050 == st->chip_type)
result = inv_init_config_mpu3050(st);
else
@@ -2782,18 +3427,20 @@ static int inv_mod_probe(struct i2c_client *client,
result = inv_get_silicon_rev_mpu6050(st);
if (result) {
dev_err(&client->adapter->dev,
- "%s get silicon error.\n", st->hw->name);
+ "%s get silicon error.\n", st->hw_s->name);
goto out_free;
}
}
- result = inv_set_power_state(st, 0);
+ result = inv_pm(st, NVI_PM_OFF);
if (result) {
dev_err(&client->adapter->dev,
- "%s could not be turned off.\n", st->hw->name);
+ "%s could not be turned off.\n", st->hw_s->name);
goto out_free;
}
+ mutex_init(&st->mutex);
+ mutex_init(&st->mutex_temp);
INIT_KFIFO(st->trigger.timestamps);
result = create_sysfs_interfaces(st);
if (result)
@@ -2826,8 +3473,8 @@ static int inv_mod_probe(struct i2c_client *client,
goto out_close_sysfs;
}
- pr_info("%s: Probe name %s\n", __func__, id->name);
- dev_info(&client->adapter->dev, "%s is ready to go!\n", st->hw->name);
+ inf_local = st;
+ dev_info(&client->adapter->dev, "%s is ready to go!\n", st->hw_s->name);
return 0;
out_close_sysfs:
@@ -2835,11 +3482,11 @@ out_close_sysfs:
out_free_kfifo:
kfifo_free(&st->trigger.timestamps);
out_free:
- result = inv_i2c_single_write(st, st->reg->pwr_mgmt_1, BIT_RESET);
- if (st->inv_regulator.regulator_vlogic &&
- st->inv_regulator.regulator_vdd) {
- regulator_disable(st->inv_regulator.regulator_vlogic);
- regulator_disable(st->inv_regulator.regulator_vdd);
+ if (st->nvi) {
+ nvi_pm_exit(st);
+ } else {
+ inv_pm(st, NVI_PM_OFF_FORCE);
+ nvi_vreg_exit(st);
}
kfree(st);
out_no_free:
@@ -2847,45 +3494,6 @@ out_no_free:
return -EIO;
}
-static int inv_mod_remove(struct i2c_client *client)
-{
- int result;
- struct inv_gyro_state_s *st = i2c_get_clientdata(client);
-
- result = inv_set_power_state(st, 0);
- if (result)
- dev_err(&client->adapter->dev, "%s could not be turned off.\n",
- st->hw->name);
- remove_sysfs_interfaces(st);
- result = inv_i2c_single_write(st, st->reg->pwr_mgmt_1, BIT_RESET);
- kfifo_free(&st->trigger.timestamps);
- free_irq(client->irq, st);
- input_unregister_device(st->idev);
- if (INV_ITG3500 != st->chip_type)
- input_unregister_device(st->idev_dmp);
- if (st->has_compass)
- input_unregister_device(st->idev_compass);
- if (st->inv_regulator.regulator_vlogic &&
- st->inv_regulator.regulator_vdd) {
- regulator_disable(st->inv_regulator.regulator_vlogic);
- regulator_disable(st->inv_regulator.regulator_vdd);
- }
- kfree(st);
- dev_info(&client->adapter->dev, "Gyro module removed.\n");
- return 0;
-}
-
-static void inv_i2c_shutdown(struct i2c_client *client)
-{
- struct inv_gyro_state_s *st = i2c_get_clientdata(client);
-
- if (client->irq)
- disable_irq(client->irq);
- set_inv_enable(st, 0);
- inv_set_power_state(st, 0);
- st->i2c_shutdown = true;
-}
-
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* device id table is used to identify what device can be
@@ -2903,8 +3511,8 @@ MODULE_DEVICE_TABLE(i2c, inv_mod_id);
static struct i2c_driver inv_mod_driver = {
.class = I2C_CLASS_HWMON,
- .probe = inv_mod_probe,
- .remove = inv_mod_remove,
+ .probe = nvi_probe,
+ .remove = nvi_remove,
.id_table = inv_mod_id,
.driver = {
.owner = THIS_MODULE,
@@ -2914,7 +3522,7 @@ static struct i2c_driver inv_mod_driver = {
#endif
},
.address_list = normal_i2c,
- .shutdown = inv_i2c_shutdown,
+ .shutdown = nvi_shutdown,
};
static int __init inv_mod_init(void)
diff --git a/drivers/input/misc/mpu/inv_gyro.h b/drivers/input/misc/mpu/inv_gyro.h
index 8fca85f50dac..9852064f93d6 100644
--- a/drivers/input/misc/mpu/inv_gyro.h
+++ b/drivers/input/misc/mpu/inv_gyro.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Invensense, Inc.
+* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -33,6 +34,11 @@
#include <linux/regulator/consumer.h>
#include "dmpKey.h"
+
+#define GYRO_INPUT_RESOLUTION (1)
+#define ACCL_INPUT_RESOLUTION (1)
+
+
/**
* struct inv_reg_map_s - Notable slave registers.
* @who_am_i: Upper 6 bits of the device's slave address.
@@ -94,16 +100,16 @@ enum inv_devices {
* @sample_rate: sensitity for gyro.
* @sample_rate: sample rate, i.e, fifo rate.
* @lpf: low pass filter.
- * @fsr: full scale range.
- * @accl_fs: accel full scale range.
+ * @gyro_fsr: full scale range.
+ * @accl_fsr: accel full scale range.
* @accl_sens: accel sensitivity
*/
struct test_setup_t {
int gyro_sens;
int sample_rate;
int lpf;
- int fsr;
- int accl_fs;
+ int gyro_fsr;
+ int accl_fsr;
unsigned int accl_sens[3];
};
@@ -119,10 +125,10 @@ struct inv_hw_s {
/**
* struct inv_chip_config_s - Cached chip configuration data.
- * @fsr: Full scale range.
+ * @gyro_fsr: Full scale range.
* @lpf: Digital low pass filter frequency.
* @clk_src: Clock source.
- * @accl_fs: accel full scale range.
+ * @accl_fsr: accel full scale range.
* @fifo_rate: FIFO update rate.
* @enable: master enable to enable output
* @accl_enable: enable accel functionality
@@ -138,23 +144,29 @@ struct inv_hw_s {
* @prog_start_addr: firmware program start address
*/
struct inv_chip_config_s {
- unsigned char fsr;
unsigned char lpf;
unsigned char clk_src;
- unsigned char accl_fs;
- unsigned short fifo_rate;
unsigned char enable;
- unsigned char accl_enable;
- unsigned char accl_fifo_enable;
unsigned char gyro_enable;
unsigned char gyro_fifo_enable;
- unsigned char compass_enable;
- unsigned char is_asleep;
+ unsigned long gyro_delay_us;
+ unsigned int gyro_resolution;
+ unsigned char gyro_fsr;
+ unsigned char accl_enable;
+ unsigned char accl_fifo_enable;
+ unsigned long accl_delay_us;
+ unsigned int accl_resolution;
+ unsigned char accl_fsr;
+ unsigned long lpa_delay_us;
+ unsigned char temp_fifo_enable;
unsigned char dmp_on;
unsigned char firmware_loaded;
- unsigned char lpa_mode;
- unsigned char lpa_freq;
+ unsigned char mot_dur;
+ unsigned char mot_ctrl;
+ unsigned int mot_cnt;
+ unsigned char fifo_rate;
unsigned int prog_start_addr;
+ unsigned long min_delay_us;
};
/**
@@ -230,6 +242,67 @@ struct inv_regulator_s {
struct regulator *regulator_vdd;
};
+struct nvi_hw {
+ unsigned char aux_vddio;
+ unsigned char smplrt_div;
+ unsigned char config;
+ unsigned char gyro_config;
+ unsigned char accl_config;
+ unsigned char mot_thr;
+ unsigned char mot_dur;
+ unsigned char zrmot_thr;
+ unsigned char zrmot_dur;
+ unsigned char fifo_en;
+ unsigned char i2c_mst_ctrl;
+ unsigned char i2c_slv4_ctrl;
+ unsigned char int_pin_cfg;
+ unsigned char int_enable;
+ unsigned char i2c_mst_delay_ctrl;
+ unsigned char mot_detect_ctrl;
+ unsigned char user_ctrl;
+ unsigned char pwr_mgmt_1;
+ unsigned char pwr_mgmt_2;
+};
+
+#define AUX_PORT_MAX (5)
+#define AUX_PORT_SPECIAL (4)
+#define AUX_PORT_BYPASS (-1)
+#define AUX_EXT_DATA_REG_MAX (24)
+#define AUX_DEV_VALID_READ_MAX (10)
+
+struct aux_port {
+ struct nvi_mpu_port nmp;
+ long long delay_ns;
+ unsigned short ext_data_offset;
+ bool hw_valid;
+ bool hw_en;
+ bool hw_do;
+ bool enable;
+ bool fifo_en;
+};
+
+struct aux_ports {
+ struct aux_port port[AUX_PORT_MAX];
+ int bypass_lock;
+ unsigned char delay_hw;
+ unsigned short ext_data_n;
+ unsigned char ext_data[AUX_EXT_DATA_REG_MAX];
+ unsigned char clock_i2c;
+ bool need_reset;
+ bool enable;
+ bool dbg;
+};
+
+#define NVI_PM_ERR 0
+#define NVI_PM_AUTO 1
+#define NVI_PM_OFF_FORCE 2
+#define NVI_PM_OFF 3
+#define NVI_PM_STDBY 4
+#define NVI_PM_ON_CYCLE 5
+#define NVI_PM_ON 6
+#define NVI_PM_ON_FULL 7
+
+
struct inv_mpu_slave;
/**
* struct inv_gyro_state_s - Driver state variables.
@@ -267,35 +340,47 @@ struct inv_gyro_state_s {
struct inv_chip_config_s chip_config;
struct inv_chip_info_s chip_info;
struct inv_flick_s flick;
- struct inv_tap_s tap;
+ struct inv_tap_s tap;
struct inv_reg_map_s *reg;
- struct inv_hw_s *hw;
+ struct inv_hw_s *hw_s;
struct inv_trigger_s trigger;
struct input_dev *idev;
struct input_dev *idev_dmp;
- struct input_dev *idev_compass;
enum inv_devices chip_type;
spinlock_t time_stamp_lock;
struct class *inv_class;
- struct device *inv_dev;
+ struct device *inv_dev;
struct i2c_client *i2c;
struct mpu_platform_data plat_data;
struct inv_mpu_slave *mpu_slave;
- short compass_st_upper[3];
- short compass_st_lower[3];
+ struct regulator_bulk_data vreg[2];
unsigned char fifo_counter;
- unsigned char has_compass;
- unsigned char compass_scale;
unsigned char i2c_addr;
- unsigned char compass_divider;
- unsigned char compass_counter;
unsigned char sample_divider;
unsigned char fifo_divider;
void *sl_handle;
unsigned int irq_dur_us;
long long last_isr_time;
- struct inv_regulator_s inv_regulator;
- bool i2c_shutdown;
+ struct mutex mutex;
+ struct mutex mutex_temp;
+ struct nvi_hw hw;
+ struct aux_ports aux;
+ int pm;
+ int stby;
+ int lpa_hw;
+ unsigned long sample_delay_us;
+ bool shutdown;
+ bool nvi;
+ bool lpa_enable;
+ bool mot_enable;
+ bool mot_dbg;
+ unsigned int mot_cnt;
+ short temp_val;
+ s64 temp_ts;
+#if DEBUG_SYSFS_INTERFACE
+ unsigned short dbg_i2c_addr;
+ unsigned char dbg_reg;
+#endif /* DEBUG_SYSFS_INTERFACE */
};
/* produces an unique identifier for each device based on the
@@ -325,52 +410,6 @@ struct inv_mpu_slave {
int (*set_lpf)(struct inv_gyro_state_s *, int rate);
int (*set_fs)(struct inv_gyro_state_s *, int fs);
};
-/* AKM definitions */
-#define REG_AKM_ID (0x00)
-#define REG_AKM_STATUS (0x02)
-#define REG_AKM_MEASURE_DATA (0x03)
-#define REG_AKM_MODE (0x0A)
-#define REG_AKM_ST_CTRL (0x0C)
-#define REG_AKM_SENSITIVITY (0x10)
-#define REG_AKM8963_CNTL1 (0x0A)
-
-#define DATA_AKM_ID (0x48)
-#define DATA_AKM_MODE_PW_DN (0x00)
-#define DATA_AKM_MODE_PW_SM (0x01)
-#define DATA_AKM_MODE_PW_ST (0x08)
-#define DATA_AKM_MODE_PW_FR (0x0F)
-#define DATA_AKM_SELF_TEST (0x40)
-#define DATA_AKM_DRDY (0x01)
-#define DATA_AKM8963_BIT (0x10)
-#define DATA_AKM_STAT_MASK (0x0C)
-
-#define DATA_AKM8975_SCALE (9830)
-#define DATA_AKM8972_SCALE (19661)
-#define DATA_AKM8963_SCALE0 (19661)
-#define DATA_AKM8963_SCALE1 (4915)
-
-#define DATA_AKM8975_ST_X_UP (100)
-#define DATA_AKM8975_ST_X_LW (-100)
-#define DATA_AKM8975_ST_Y_UP (100)
-#define DATA_AKM8975_ST_Y_LW (-100)
-#define DATA_AKM8975_ST_Z_UP (-300)
-#define DATA_AKM8975_ST_Z_LW (-1000)
-
-/*need to verify the range for 8972 */
-#define DATA_AKM8972_ST_X_UP (50)
-#define DATA_AKM8972_ST_X_LW (-50)
-#define DATA_AKM8972_ST_Y_UP (50)
-#define DATA_AKM8972_ST_Y_LW (-50)
-#define DATA_AKM8972_ST_Z_UP (-100)
-#define DATA_AKM8972_ST_Z_LW (-500)
-
-#define DATA_AKM8963_ST_X_UP (200)
-#define DATA_AKM8963_ST_X_LW (-200)
-#define DATA_AKM8963_ST_Y_UP (200)
-#define DATA_AKM8963_ST_Y_LW (-200)
-#define DATA_AKM8963_ST_Z_UP (-800)
-#define DATA_AKM8963_ST_Z_LW (-3200)
-
/* register definition*/
#define REG_3050_AUX_VDDIO (0x13)
@@ -379,22 +418,34 @@ struct inv_mpu_slave {
#define REG_3050_AUX_XOUT_H (0x23)
#define REG_3500_OTP (0x00)
-
+#define REG_AUX_VDDIO (0x01)
#define REG_ST_GCT_X (0x0D)
+#define REG_MOT_THR (0x1F)
+#define REG_MOT_DUR (0x20)
+#define REG_ZMOT_THR (0x21)
+#define REG_ZMOT_DUR (0x22)
#define REG_I2C_MST_CTRL (0x24)
+#define BIT_SLV3_FIFO_EN (0x20)
#define REG_I2C_SLV0_ADDR (0x25)
#define REG_I2C_SLV0_REG (0x26)
#define REG_I2C_SLV0_CTRL (0x27)
-#define REG_I2C_SLV1_ADDR (0x28)
-#define REG_I2C_SLV1_REG (0x29)
-#define REG_I2C_SLV1_CTRL (0x2A)
-
+#define BITS_I2C_SLV_CTRL_LEN (0x0F)
+#define BITS_I2C_SLV_REG_DIS (0x10)
+#define REG_I2C_SLV4_ADDR (0x31)
+#define REG_I2C_SLV4_REG (0x32)
+#define REG_I2C_SLV4_DO (0x33)
#define REG_I2C_SLV4_CTRL (0x34)
+#define REG_I2C_SLV4_DI (0x35)
+#define REG_I2C_MST_STATUS (0x36)
+#define REG_I2C_SLV0_DO (0x63)
+#define REG_FIFO_EN (0x23)
+
+#define BITS_I2C_MST_DLY (0x1F)
#define REG_INT_PIN_CFG (0x37)
#define REG_DMP_INT_STATUS (0x39)
#define REG_EXT_SENS_DATA_00 (0x49)
-#define REG_I2C_SLV1_DO (0x64)
#define REG_I2C_MST_DELAY_CTRL (0x67)
+#define REG_MOT_DETECT_CTRL (0x69)
#define REG_BANK_SEL (0x6D)
#define REG_MEM_START (0x6E)
#define REG_MEM_RW (0x6F)
@@ -407,27 +458,32 @@ struct inv_mpu_slave {
#define BIT_BYPASS_EN (0x2)
#define BIT_WAIT_FOR_ES (0x40)
+#define BIT_I2C_MST_P_NSR (0x10)
#define BIT_I2C_READ (0x80)
#define BIT_SLV_EN (0x80)
#define BIT_DMP_EN (0x80)
-#define BIT_FIFO_EN (0x40)
+#define BIT_FIFO_EN (0x40)
#define BIT_I2C_MST_EN (0x20)
#define BIT_DMP_RST (0x08)
-#define BIT_FIFO_RST (0x04)
+#define BIT_FIFO_RST (0x04)
#define BIT_I2C_MST_RST (0x02)
#define BIT_SLV0_DLY_EN (0x01)
#define BIT_SLV1_DLY_EN (0x02)
+#define BIT_DELAY_ES_SHADOW (0x80)
-#define BIT_FIFO_OVERFLOW (0x10)
-#define BIT_DATA_RDY_EN (0x01)
+#define BIT_MOT_EN (0x40)
+#define BIT_ZMOT_EN (0x20)
+#define BIT_FIFO_OVERFLOW (0x10)
+#define BIT_DATA_RDY_EN (0x01)
#define BIT_DMP_INT_EN (0x02)
#define BIT_PWR_ACCL_STBY (0x38)
#define BIT_PWR_GYRO_STBY (0x07)
-#define BIT_GYRO_XOUT (0x40)
+#define BIT_TEMP_FIFO_EN (0x80)
+#define BIT_GYRO_XOUT (0x40)
#define BIT_GYRO_YOUT (0x20)
#define BIT_GYRO_ZOUT (0x10)
#define BIT_ACCEL_OUT (0x08)
@@ -464,9 +520,15 @@ struct inv_mpu_slave {
#define TIME_STAMP_TOR (5)
#define MAX_CATCH_UP (5)
#define DEFAULT_ACCL_TRIM (16384)
-#define MAX_FIFO_RATE (1000)
-#define MIN_FIFO_RATE (4)
+#define MAX_FIFO_RATE (1000000)
+#define MIN_FIFO_RATE (4000)
#define ONE_K_HZ (1000)
+#define NVI_DELAY_US_MAX (256000)
+#define NVI_DELAY_US_MIN (125)
+#define NVI_DELAY_DEFAULT (50000)
+#define NVI_INPUT_GYRO_DELAY_US_MIN (125)
+#define NVI_INPUT_ACCL_DELAY_US_MIN (1000)
+
/* authenticate key */
#define D_AUTH_OUT (32)
@@ -606,8 +668,6 @@ int mpu_memory_read(struct i2c_adapter *i2c_adap,
void inv_setup_reg_mpu3050(struct inv_reg_map_s *reg);
int inv_init_config_mpu3050(struct inv_gyro_state_s *st);
irqreturn_t inv_read_fifo_mpu3050(int irq, void *dev_id);
-int inv_reset_fifo(struct inv_gyro_state_s *st);
-void inv_clear_kfifo(struct inv_gyro_state_s *st);
int inv_setup_mpu3050(struct inv_gyro_state_s *st);
int inv_register_kxtf9_slave(struct inv_gyro_state_s *st);
int create_device_attributes(struct device *dev,
@@ -620,28 +680,28 @@ int inv_mpu3050_create_sysfs(struct inv_gyro_state_s *st);
int inv_mpu3050_remove_sysfs(struct inv_gyro_state_s *st);
int inv_get_accl_bias(struct inv_gyro_state_s *st, int *accl_bias_regular);
int set_power_mpu3050(struct inv_gyro_state_s *st, unsigned char power_on);
-int reset_fifo_mpu3050(struct inv_gyro_state_s *st);
int inv_enable_tap_dmp(struct inv_gyro_state_s *st, unsigned char on);
int inv_enable_orientation_dmp(struct inv_gyro_state_s *st);
unsigned short inv_dmp_get_address(unsigned short key);
-ssize_t inv_gyro_fifo_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-ssize_t inv_gyro_fifo_enable_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-ssize_t inv_gyro_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-ssize_t inv_gyro_enable_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-ssize_t inv_accl_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-ssize_t inv_accl_fifo_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-ssize_t inv_accl_fs_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-ssize_t inv_accl_fs_show(struct device *dev,
- struct device_attribute *attr, char *buf);
+ssize_t nvi_gyro_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+ssize_t nvi_gyro_fifo_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+ssize_t nvi_gyro_max_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+ssize_t nvi_accl_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+ssize_t nvi_accl_fifo_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+ssize_t nvi_accl_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+ssize_t nvi_accl_max_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
ssize_t inv_accl_matrix_show(struct device *dev,
- struct device_attribute *attr, char *buf);
+ struct device_attribute *attr, char *buf);
+ssize_t nvi_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
ssize_t inv_dmp_firmware_write(struct file *fp, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t pos, size_t size);
diff --git a/drivers/input/misc/mpu/inv_gyro_misc.c b/drivers/input/misc/mpu/inv_gyro_misc.c
index 80bc3ca86411..0a058dea9b3a 100644
--- a/drivers/input/misc/mpu/inv_gyro_misc.c
+++ b/drivers/input/misc/mpu/inv_gyro_misc.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Invensense, Inc.
+* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -76,11 +77,11 @@
#define DEF_GYRO_CT_SHIFT_MAX (105)
static struct test_setup_t test_setup = {
- .gyro_sens = 32768 / 250,
- .sample_rate = DEF_SELFTEST_SAMPLE_RATE,
- .lpf = DEF_SELFTEST_LPF_PARA,
- .fsr = DEF_SELFTEST_GYRO_FULL_SCALE,
- .accl_fs = DEF_SELFTEST_ACCL_FULL_SCALE
+ .gyro_sens = 32768 / 250,
+ .sample_rate = DEF_SELFTEST_SAMPLE_RATE,
+ .lpf = DEF_SELFTEST_LPF_PARA,
+ .gyro_fsr = DEF_SELFTEST_GYRO_FULL_SCALE,
+ .accl_fsr = DEF_SELFTEST_ACCL_FULL_SCALE
};
/* NOTE: product entries are in chronological order */
@@ -623,13 +624,13 @@ static int inv_do_test(struct inv_gyro_state_s *st, int self_test_flag,
return result;
result = inv_i2c_single_write(st, reg->gyro_config,
- self_test_flag | test_setup.fsr);
+ self_test_flag | test_setup.gyro_fsr);
if (result)
return result;
if (has_accl) {
result = inv_i2c_single_write(st, reg->accl_config,
- self_test_flag | test_setup.accl_fs);
+ self_test_flag | test_setup.accl_fsr);
if (result)
return result;
}
@@ -717,111 +718,16 @@ static void inv_recover_setting(struct inv_gyro_state_s *st)
reg = st->reg;
set_inv_enable(st, st->chip_config.enable);
- inv_i2c_single_write(st, reg->gyro_config, st->chip_config.fsr<<3);
+ inv_i2c_single_write(st, reg->gyro_config,
+ st->chip_config.gyro_fsr<<3);
inv_i2c_single_write(st, reg->lpf, st->chip_config.lpf);
data = ONE_K_HZ/st->chip_config.fifo_rate - 1;
inv_i2c_single_write(st, reg->sample_rate_div, data);
if (INV_ITG3500 != st->chip_type) {
inv_i2c_single_write(st, reg->accl_config,
- (st->chip_config.accl_fs << 3)|0);
+ (st->chip_config.accl_fsr << 3)|0);
}
- if (st->chip_config.is_asleep)
- inv_set_power_state(st, 0);
- else
- inv_set_power_state(st, 1);
-}
-
-static int inv_check_compass_self_test(struct inv_gyro_state_s *st)
-{
- int result;
- unsigned char data[6];
- unsigned char counter, cntl;
- short x, y, z;
- unsigned char *sens;
-
- sens = st->chip_info.compass_sens;
- /*set to bypass mode */
- result = inv_i2c_single_write(st, REG_INT_PIN_CFG, BIT_BYPASS_EN);
- if (result) {
- inv_i2c_single_write(st, REG_INT_PIN_CFG, 0x0);
- return result;
- }
-
- /*set to power down mode */
- result = inv_secondary_write(REG_AKM_MODE, DATA_AKM_MODE_PW_DN);
- if (result)
- goto AKM_fail;
-
- /*write 1 to ASTC register */
- result = inv_secondary_write(REG_AKM_ST_CTRL, DATA_AKM_SELF_TEST);
- if (result)
- goto AKM_fail;
-
- /*set self test mode */
- result = inv_secondary_write(REG_AKM_MODE, DATA_AKM_MODE_PW_ST);
- if (result)
- goto AKM_fail;
-
- counter = 10;
- while (counter > 0) {
- mdelay(10);
- result = inv_secondary_read(REG_AKM_STATUS, 1, data);
- if (result)
- goto AKM_fail;
-
- if (data[0] != DATA_AKM_DRDY)
- counter--;
- else
- counter = 0;
- }
-
- if (data[0] != DATA_AKM_DRDY) {
- result = -1;
- goto AKM_fail;
- }
-
- result = inv_secondary_read(REG_AKM_MEASURE_DATA, 6, data);
- if (result)
- goto AKM_fail;
-
- x = (short)((data[1]<<8) | data[0]);
- y = (short)((data[3]<<8) | data[2]);
- z = (short)((data[5]<<8) | data[4]);
- x = ((x * (sens[0] + 128)) >> 8);
- y = ((y * (sens[1] + 128)) >> 8);
- z = ((z * (sens[2] + 128)) >> 8);
- if (COMPASS_ID_AK8963 == st->plat_data.sec_slave_id) {
- result = inv_secondary_read(REG_AKM8963_CNTL1, 1, &cntl);
- if (result)
- goto AKM_fail;
-
- if (0 == (cntl & DATA_AKM8963_BIT)) {
- x <<= 2;
- y <<= 2;
- z <<= 2;
- }
- }
-
- result = 1;
- result = inv_secondary_read(REG_AKM8963_CNTL1, 1, &cntl);
- if (x > st->compass_st_upper[0] || x < st->compass_st_lower[0])
- goto AKM_fail;
-
- if (y > st->compass_st_upper[1] || y < st->compass_st_lower[1])
- goto AKM_fail;
-
- if (z > st->compass_st_upper[2] || z < st->compass_st_lower[2])
- goto AKM_fail;
-
- result = 0;
-AKM_fail:
- /*write 0 to ASTC register */
- result |= inv_secondary_write(REG_AKM_ST_CTRL, 0);
- /*set to power down mode */
- result |= inv_secondary_write(REG_AKM_MODE, DATA_AKM_MODE_PW_DN);
- /*restore to non-bypass mode */
- result |= inv_i2c_single_write(st, REG_INT_PIN_CFG, 0x0);
- return result;
+ inv_set_power_state(st, 1);
}
/**
@@ -834,9 +740,9 @@ int inv_hw_self_test(struct inv_gyro_state_s *st,
int gyro_bias_st[3];
int accl_bias_st[3], accl_bias_regular[3];
int test_times;
- char compass_result, accel_result, gyro_result;
+ char accel_result, gyro_result;
- compass_result = accel_result = gyro_result = 0;
+ accel_result = gyro_result = 0;
test_times = 2;
while (test_times > 0) {
result = inv_do_test(st, 0, gyro_bias_regular,
@@ -865,8 +771,6 @@ int inv_hw_self_test(struct inv_gyro_state_s *st,
gyro_result = !inv_check_3500_gyro_self_test(st,
gyro_bias_regular, gyro_bias_st);
} else {
- if (st->has_compass)
- compass_result = !inv_check_compass_self_test(st);
accel_result = !inv_check_accl_self_test(st,
accl_bias_regular, accl_bias_st);
gyro_result = !inv_check_6050_gyro_self_test(st,
@@ -874,7 +778,7 @@ int inv_hw_self_test(struct inv_gyro_state_s *st,
}
test_fail:
inv_recover_setting(st);
- return (compass_result<<2) | (accel_result<<1) | gyro_result;
+ return (accel_result<<1) | gyro_result;
}
/**
@@ -1517,9 +1421,6 @@ ssize_t inv_dmp_firmware_write(struct file *fp, struct kobject *kobj,
struct inv_reg_map_s *reg;
st = dev_get_drvdata(container_of(kobj, struct device, kobj));
- if (st->chip_config.is_asleep)
- return -EPERM;
-
if (1 == st->chip_config.firmware_loaded)
return -EINVAL;
diff --git a/drivers/input/misc/mpu/inv_mpu3050.c b/drivers/input/misc/mpu/inv_mpu3050.c
index 96a6e22d5665..205bf456f974 100644
--- a/drivers/input/misc/mpu/inv_mpu3050.c
+++ b/drivers/input/misc/mpu/inv_mpu3050.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Invensense, Inc.
+* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -38,77 +39,292 @@
#include <linux/spinlock.h>
#include "inv_gyro.h"
-int set_3050_bypass(struct inv_gyro_state_s *st, int enable)
+
+static unsigned long nvi_lpf_us_tbl[] = {
+ 0, /* N/A */
+ 5319, /* 188Hz */
+ 10204, /* 98Hz */
+ 23810, /* 42Hz */
+ 50000, /* 20Hz */
+ 100000, /* 10Hz */
+ /* 200000, 5Hz */
+};
+
+
+/**
+ * inv_clear_kfifo() - clear time stamp fifo
+ * @st: Device driver instance.
+ */
+static void inv_clear_kfifo(struct inv_gyro_state_s *st)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&st->time_stamp_lock, flags);
+ kfifo_reset(&st->trigger.timestamps);
+ spin_unlock_irqrestore(&st->time_stamp_lock, flags);
+}
+
+/**
+ * mpu3050_fifo_reset() - Reset FIFO related registers
+ * @st: Device driver instance.
+ */
+static int mpu3050_fifo_reset(struct inv_gyro_state_s *st)
{
struct inv_reg_map_s *reg;
int result;
- unsigned char b;
+ unsigned char val, user_ctrl;
reg = st->reg;
- result = inv_i2c_read(st, reg->user_ctrl, 1, &b);
+ /* disable interrupt */
+ result = inv_i2c_single_write(st, reg->int_enable, 0);
if (result)
return result;
- if (((b & BIT_3050_AUX_IF_EN) == 0) && enable)
- return 0;
- if ((b & BIT_3050_AUX_IF_EN) && (enable == 0))
- return 0;
- b &= ~BIT_3050_AUX_IF_EN;
- if (!enable) {
- b |= BIT_3050_AUX_IF_EN;
- result = inv_i2c_single_write(st, reg->user_ctrl, b);
- return result;
+
+ inv_clear_kfifo(st);
+ /* disable the sensor output to FIFO */
+ result = inv_i2c_single_write(st, reg->fifo_en, 0);
+ if (result)
+ goto reset_fifo_fail;
+ result = inv_i2c_read(st, reg->user_ctrl, 1, &user_ctrl);
+ if (result)
+ goto reset_fifo_fail;
+ /* disable fifo reading */
+ user_ctrl &= ~BIT_FIFO_EN;
+ st->fifo_counter = 0;
+ /* reset fifo */
+ val = (BIT_3050_FIFO_RST | user_ctrl);
+ result = inv_i2c_single_write(st, reg->user_ctrl, val);
+ if (result)
+ goto reset_fifo_fail;
+ mdelay(POWER_UP_TIME);
+ st->last_isr_time = get_time_ns();
+ if (st->chip_config.dmp_on) {
+ /* enable interrupt when DMP is done */
+ result = inv_i2c_single_write(st, reg->int_enable,
+ BIT_DMP_INT_EN);
+ if (result)
+ return result;
+
+ result = inv_i2c_single_write(st, reg->user_ctrl,
+ BIT_FIFO_EN|user_ctrl);
+ if (result)
+ return result;
} else {
- /* Coming out of I2C is tricky due to several erratta. Do not
- * modify this algorithm
- */
- /*
- * 1) wait for the right time and send the command to change
- * the aux i2c slave address to an invalid address that will
- * get nack'ed
- *
- * 0x00 is broadcast. 0x7F is unlikely to be used by any aux.
- */
- result = inv_i2c_single_write(st, REG_3050_SLAVE_ADDR,
- 0x7F);
+ /* enable interrupt */
+ if (st->chip_config.accl_fifo_enable ||
+ st->chip_config.gyro_fifo_enable){
+ result = inv_i2c_single_write(st, reg->int_enable,
+ BIT_DATA_RDY_EN);
+ if (result)
+ return result;
+ }
+ /* enable FIFO reading and I2C master interface*/
+ result = inv_i2c_single_write(st, reg->user_ctrl,
+ BIT_FIFO_EN | user_ctrl);
if (result)
return result;
- /*
- * 2) wait enough time for a nack to occur, then go into
- * bypass mode:
- */
- mdelay(2);
- result = inv_i2c_single_write(st, reg->user_ctrl, b);
+ /* enable sensor output to FIFO and FIFO footer*/
+ val = 1;
+ if (st->chip_config.accl_fifo_enable)
+ val |= BITS_3050_ACCL_OUT;
+ if (st->chip_config.gyro_fifo_enable)
+ val |= BITS_GYRO_OUT;
+ result = inv_i2c_single_write(st, reg->fifo_en, val);
if (result)
return result;
- /*
- * 3) wait for up to one MPU cycle then restore the slave
- * address
- */
- mdelay(20);
- result = inv_i2c_single_write(st, REG_3050_SLAVE_REG,
- st->plat_data.secondary_read_reg);
+ }
+
+ return 0;
+reset_fifo_fail:
+ if (st->chip_config.dmp_on)
+ val = BIT_DMP_INT_EN;
+ else
+ val = BIT_DATA_RDY_EN;
+ inv_i2c_single_write(st, reg->int_enable, val);
+ pr_err("%s failed\n", __func__);
+ return result;
+}
+
+/**
+ * set_power_mpu3050() - set power of mpu3050.
+ * @st: Device driver instance.
+ * @power_on: on/off
+ */
+int set_power_mpu3050(struct inv_gyro_state_s *st, unsigned char power_on)
+{
+ struct inv_reg_map_s *reg;
+ unsigned char data, p;
+ int result;
+ reg = st->reg;
+ if (power_on) {
+ data = 0;
+ } else {
+ if (st->mpu_slave) {
+ result = st->mpu_slave->suspend(st);
+ if (result)
+ return result;
+ }
+
+ data = BIT_SLEEP;
+ }
+ if (st->chip_config.gyro_enable) {
+ p = (BITS_3050_POWER1 | INV_CLK_PLL);
+ result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p);
if (result)
return result;
- result = inv_i2c_single_write(st, REG_3050_SLAVE_ADDR,
- st->plat_data.secondary_i2c_addr);
+ p = (BITS_3050_POWER2 | INV_CLK_PLL);
+ result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p);
if (result)
return result;
- result = inv_i2c_single_write(st, reg->user_ctrl,
- (b | BIT_3050_AUX_IF_RST));
+ p = INV_CLK_PLL;
+ result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p);
if (result)
return result;
- mdelay(2);
+ st->chip_config.clk_src = INV_CLK_PLL;
+ } else {
+ data |= (BITS_3050_GYRO_STANDBY | INV_CLK_INTERNAL);
+ result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data);
+ if (result)
+ return result;
+ st->chip_config.clk_src = INV_CLK_INTERNAL;
}
+ if (power_on) {
+ mdelay(POWER_UP_TIME);
+ if (st->mpu_slave) {
+ result = st->mpu_slave->resume(st);
+ if (result)
+ return result;
+ }
+ }
+
return 0;
}
/**
+ * inv_set_power_state() - Turn device on/off.
+ * @st: Device driver instance.
+ * @power_on: 1 to turn on, 0 to suspend.
+ */
+int inv_set_power_state(struct inv_gyro_state_s *st, unsigned char power_on)
+{
+ return set_power_mpu3050(st, power_on);
+}
+
+/**
+ * set_inv_enable() - Reset FIFO related registers.
+ * @st: Device driver instance.
+ * @fifo_enable: enable/disable
+ */
+int set_inv_enable(struct inv_gyro_state_s *st, unsigned long enable)
+{
+ struct inv_reg_map_s *reg;
+ int result;
+
+ reg = st->reg;
+ if (enable) {
+ result = mpu3050_fifo_reset(st);
+ if (result)
+ return result;
+
+ st->chip_config.enable = 1;
+ } else {
+ result = inv_i2c_single_write(st, reg->fifo_en, 0);
+ if (result)
+ return result;
+
+ result = inv_i2c_single_write(st, reg->int_enable, 0);
+ if (result)
+ return result;
+
+ st->chip_config.enable = 0;
+ }
+
+ return 0;
+}
+
+static int mpu3050_global_delay(struct inv_gyro_state_s *inf)
+{
+ unsigned long delay_us;
+ unsigned char val;
+ int rate;
+ int err = 0;
+
+ /* find the fastest polling of all the devices */
+ delay_us = -1;
+ if (inf->chip_config.gyro_enable && inf->chip_config.gyro_delay_us) {
+ if (inf->chip_config.gyro_delay_us < delay_us)
+ delay_us = inf->chip_config.gyro_delay_us;
+ }
+ if (inf->chip_config.accl_enable && inf->chip_config.accl_delay_us) {
+ if (inf->chip_config.accl_delay_us < delay_us)
+ delay_us = inf->chip_config.accl_delay_us;
+ }
+ if (delay_us == -1)
+ delay_us = NVI_DELAY_DEFAULT; /* default if nothing found */
+ if (delay_us < MIN_FIFO_RATE)
+ delay_us = MIN_FIFO_RATE;
+ if (delay_us > MAX_FIFO_RATE)
+ delay_us = MAX_FIFO_RATE;
+ /* program if new value */
+ if (delay_us != inf->sample_delay_us) {
+ dev_dbg(&inf->i2c->dev, "%s %lu\n", __func__, delay_us);
+ inf->sample_delay_us = delay_us;
+ val = delay_us / ONE_K_HZ - 1;
+ err = inv_i2c_single_write(inf, inf->reg->sample_rate_div,
+ val);
+ rate = 1000000 / delay_us;
+ inf->irq_dur_us = delay_us;
+ delay_us <<= 1;
+ for (val = 1; val < ARRAY_SIZE(nvi_lpf_us_tbl); val++) {
+ if (delay_us < nvi_lpf_us_tbl[val])
+ break;
+ }
+ if (inf->mpu_slave != NULL)
+ err |= inf->mpu_slave->set_lpf(inf, rate);
+ err |= inv_i2c_single_write(inf, inf->reg->lpf, val |
+ (inf->chip_config.gyro_fsr << 3));
+ inf->last_isr_time = get_time_ns();
+ }
+ return err;
+}
+
+static int mpu3050_gyro_enable(struct inv_gyro_state_s *inf,
+ unsigned char enable, unsigned char fifo_enable)
+{
+ unsigned char enable_old;
+ unsigned char fifo_enable_old;
+ unsigned char val;
+ int err = 0;
+
+ enable_old = inf->chip_config.gyro_enable;
+ fifo_enable_old = inf->chip_config.gyro_fifo_enable;
+ inf->chip_config.gyro_fifo_enable = fifo_enable;
+ inf->chip_config.gyro_enable = enable;
+ set_power_mpu3050(inf, 1);
+ if (enable != enable_old) {
+ if (enable) {
+ val = (inf->chip_config.gyro_fsr << 3);
+ val |= inf->chip_config.lpf;
+ err = inv_i2c_single_write(inf, inf->reg->lpf, val);
+ }
+ mpu3050_global_delay(inf);
+ }
+ if (fifo_enable_old != fifo_enable)
+ mpu3050_fifo_reset(inf);
+ if (err) {
+ inf->chip_config.gyro_enable = enable_old;
+ inf->chip_config.gyro_fifo_enable = fifo_enable_old;
+ }
+ set_power_mpu3050(inf, 1);
+ return err;
+}
+
+/**
* inv_raw_accl_show() - Read accel data directly from registers.
*/
-static ssize_t inv_raw_accl_mpu3050_show(struct device *dev,
+static ssize_t mpu3050_raw_accl_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned char data[6];
@@ -132,14 +348,12 @@ static ssize_t inv_raw_accl_mpu3050_show(struct device *dev,
/**
* inv_accl_fifo_enable_store() - Enable/disable accl fifo output.
*/
-static ssize_t inv_accl_fifo_mpu3050_enable_store(struct device *dev,
+static ssize_t mpu3050_accl_fifo_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long en;
struct inv_gyro_state_s *st;
st = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EINVAL;
if (kstrtoul(buf, 10, &en))
return -EINVAL;
if (en == !(!(st->chip_config.accl_fifo_enable)))
@@ -147,22 +361,19 @@ static ssize_t inv_accl_fifo_mpu3050_enable_store(struct device *dev,
st->chip_config.accl_fifo_enable = en;
if (en && (0 == st->chip_config.accl_enable)) {
st->chip_config.accl_enable = en;
- if (st->mpu_slave != NULL)
- st->mpu_slave->resume(st);
+ set_power_mpu3050(st, 1);
}
return count;
}
/**
- * inv_accl_mpu3050_enable_store() - Enable/disable accl.
+ * mpu3050_accl_enable_store() - Enable/disable accl.
*/
-static ssize_t inv_accl_mpu3050_enable_store(struct device *dev,
+static ssize_t mpu3050_accl_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long en;
struct inv_gyro_state_s *st;
st = dev_get_drvdata(dev);
- if (st->chip_config.is_asleep)
- return -EINVAL;
if (kstrtoul(buf, 10, &en))
return -EINVAL;
if (en == !(!(st->chip_config.accl_enable)))
@@ -172,36 +383,245 @@ static ssize_t inv_accl_mpu3050_enable_store(struct device *dev,
st->chip_config.accl_fifo_enable = 0;
if (st->mpu_slave != NULL) {
if (en)
- st->mpu_slave->resume(st);
+ set_power_mpu3050(st, 1);
+ else
+ set_power_mpu3050(st, 0);
+ }
+ return count;
+}
+
+static ssize_t mpu3050_accl_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned long accl_delay_us;
+ unsigned long accl_delay_us_old;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtoul(buf, 10, &accl_delay_us);
+ if (err)
+ return err;
+
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %lu\n", __func__, accl_delay_us);
+ if (accl_delay_us < NVI_INPUT_ACCL_DELAY_US_MIN)
+ accl_delay_us = NVI_INPUT_ACCL_DELAY_US_MIN;
+ if (accl_delay_us != inf->chip_config.accl_delay_us) {
+ accl_delay_us_old = inf->chip_config.accl_delay_us;
+ inf->chip_config.accl_delay_us = accl_delay_us;
+ if (inf->chip_config.accl_enable) {
+ err = mpu3050_global_delay(inf);
+ if (!err)
+ inf->chip_config.accl_delay_us =
+ accl_delay_us_old;
+ }
+ }
+ mutex_unlock(&inf->mutex);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %lu ERR=%d\n",
+ __func__, accl_delay_us, err);
+ return err;
+ }
+
+ return count;
+}
+
+static ssize_t mpu3050_accl_max_range_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned char fsr;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &fsr);
+ if (err)
+ return -EINVAL;
+
+ if (fsr > 3)
+ return -EINVAL;
+
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, fsr);
+ if (fsr != inf->chip_config.accl_fsr) {
+ inf->chip_config.accl_fsr = fsr;
+ if (inf->chip_config.accl_enable) {
+ if ((inf->chip_type == INV_MPU3050) &&
+ (inf->mpu_slave != NULL)) {
+ err = inf->mpu_slave->set_fs(inf, fsr);
+ /* reset fifo to purge old data */
+ mpu3050_fifo_reset(inf);
+ }
+ }
+ }
+ mutex_unlock(&inf->mutex);
+ if (err < 0) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n", __func__, fsr, err);
+ return err;
+ }
+
+ return count;
+}
+
+static ssize_t mpu3050_gyro_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned char enable;
+ unsigned char fifo_enable;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &enable);
+ if (err)
+ return -EINVAL;
+
+ if (enable > 7)
+ return -EINVAL;
+
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, enable);
+ if (enable != inf->chip_config.gyro_enable) {
+ if (enable)
+ fifo_enable = inf->chip_config.gyro_fifo_enable;
else
- st->mpu_slave->suspend(st);
+ fifo_enable = 0;
+ err = mpu3050_gyro_enable(inf, enable, fifo_enable);
+ }
+ mutex_unlock(&inf->mutex);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n",
+ __func__, enable, err);
+ return err;
}
+
return count;
}
+static ssize_t mpu3050_gyro_fifo_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned char fifo_enable;
+ unsigned char enable;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &fifo_enable);
+ if (err)
+ return -EINVAL;
+
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, fifo_enable);
+ enable = inf->chip_config.gyro_enable;
+ if (fifo_enable) {
+ fifo_enable = 1;
+ if (!enable)
+ enable = 7;
+ }
+ if (fifo_enable != inf->chip_config.gyro_fifo_enable)
+ err = mpu3050_gyro_enable(inf, enable, fifo_enable);
+ mutex_unlock(&inf->mutex);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n",
+ __func__, fifo_enable, err);
+ return err;
+ }
+
+ return count;
+}
+
+static ssize_t mpu3050_gyro_max_range_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned char fsr;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &fsr);
+ if (err)
+ return -EINVAL;
+
+ if (fsr > 3)
+ return -EINVAL;
+
+ mutex_lock(&inf->mutex);
+ dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, fsr);
+ if (fsr != inf->chip_config.gyro_fsr) {
+ inf->chip_config.gyro_fsr = fsr;
+ if (inf->chip_config.gyro_enable) {
+ fsr = (fsr << 3) | inf->chip_config.lpf;
+ err = inv_i2c_single_write(inf, inf->reg->lpf, fsr);
+ mpu3050_fifo_reset(inf);
+ }
+ }
+ mutex_unlock(&inf->mutex);
+ if (err < 0) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n", __func__, fsr, err);
+ return err;
+ }
+
+ return count;
+}
+
+static ssize_t mpu3050_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct inv_gyro_state_s *inf;
+ unsigned char enable;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &enable);
+ if (err)
+ return -EINVAL;
+
+ if (enable)
+ enable = 1;
+ inf->chip_config.enable = enable;
+ return count;
+}
+
+static DEVICE_ATTR(gyro_enable, S_IRUGO | S_IWUSR,
+ nvi_gyro_enable_show, mpu3050_gyro_enable_store);
static DEVICE_ATTR(gyro_fifo_enable, S_IRUGO | S_IWUSR,
- inv_gyro_fifo_enable_show,
- inv_gyro_fifo_enable_store);
-static DEVICE_ATTR(gyro_enable, S_IRUGO | S_IWUSR, inv_gyro_enable_show,
- inv_gyro_enable_store);
-static DEVICE_ATTR(raw_accl, S_IRUGO, inv_raw_accl_mpu3050_show, NULL);
+ nvi_gyro_fifo_enable_show, mpu3050_gyro_fifo_enable_store);
+static DEVICE_ATTR(gyro_max_range, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_gyro_max_range_show, mpu3050_gyro_max_range_store);
+static DEVICE_ATTR(accl_enable, S_IRUGO | S_IWUSR,
+ nvi_accl_enable_show, mpu3050_accl_enable_store);
static DEVICE_ATTR(accl_fifo_enable, S_IRUGO | S_IWUSR,
- inv_accl_fifo_enable_show,
- inv_accl_fifo_mpu3050_enable_store);
-static DEVICE_ATTR(accl_enable, S_IRUGO | S_IWUSR, inv_accl_enable_show,
- inv_accl_mpu3050_enable_store);
-static DEVICE_ATTR(accl_matrix, S_IRUGO, inv_accl_matrix_show, NULL);
-static DEVICE_ATTR(accl_fs, S_IRUGO | S_IWUSR, inv_accl_fs_show,
- inv_accl_fs_store);
+ nvi_accl_fifo_enable_show, mpu3050_accl_fifo_enable_store);
+static DEVICE_ATTR(accl_delay, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_accl_delay_show, mpu3050_accl_delay_store);
+static DEVICE_ATTR(accl_max_range, S_IRUGO | S_IWUSR,
+ nvi_accl_max_range_show, mpu3050_accl_max_range_store);
+static DEVICE_ATTR(accl_orientation, S_IRUGO,
+ inv_accl_matrix_show, NULL);
+static DEVICE_ATTR(raw_accl, S_IRUGO,
+ mpu3050_raw_accl_show, NULL);
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWOTH,
+ nvi_enable_show, mpu3050_enable_store);
static struct device_attribute *inv_mpu3050_attributes[] = {
- &dev_attr_gyro_fifo_enable,
&dev_attr_gyro_enable,
- &dev_attr_accl_fifo_enable,
+ &dev_attr_gyro_fifo_enable,
+ &dev_attr_gyro_max_range,
&dev_attr_accl_enable,
+ &dev_attr_accl_fifo_enable,
+ &dev_attr_accl_delay,
+ &dev_attr_accl_max_range,
+ &dev_attr_accl_orientation,
&dev_attr_raw_accl,
- &dev_attr_accl_matrix,
- &dev_attr_accl_fs,
+ &dev_attr_enable,
NULL
};
@@ -219,8 +639,8 @@ int inv_mpu3050_remove_sysfs(struct inv_gyro_state_s *st)
return 0;
}
-static void inv_report_data_3050(struct inv_gyro_state_s *st, s64 t,
- int counter, unsigned char *data)
+static void mpu3050_report(struct inv_gyro_state_s *st, s64 t,
+ int counter, unsigned char *data)
{
short x = 0, y = 0, z = 0;
int ind;
@@ -278,6 +698,7 @@ static void inv_report_data_3050(struct inv_gyro_state_s *st, s64 t,
input_sync(st->idev);
}
}
+
/**
* inv_read_fifo() - Transfer data from FIFO to ring buffer.
*/
@@ -296,15 +717,19 @@ irqreturn_t inv_read_fifo_mpu3050(int irq, void *dev_id)
st = (struct inv_gyro_state_s *)dev_id;
reg = st->reg;
- if (st->chip_config.is_asleep)
- goto end_session;
- if (!(st->chip_config.enable))
- goto end_session;
if (!(st->chip_config.accl_fifo_enable |
st->chip_config.gyro_fifo_enable |
- st->chip_config.dmp_on |
- st->chip_config.compass_enable))
+ st->chip_config.dmp_on))
goto end_session;
+
+ result = inv_i2c_read(st, reg->temperature, 2, data);
+ if (!result) {
+ mutex_lock(&st->mutex_temp);
+ st->temp_val = (data[0] << 8) | data[1];
+ st->temp_ts = timestamp;
+ mutex_unlock(&st->mutex_temp);
+ }
+
if (st->chip_config.dmp_on)
bytes_per_datum = BYTES_FOR_DMP;
else
@@ -353,7 +778,7 @@ irqreturn_t inv_read_fifo_mpu3050(int irq, void *dev_id)
&timestamp, sizeof(timestamp), &copied);
if (result)
goto flush_fifo;
- inv_report_data_3050(st, timestamp, st->fifo_counter, data);
+ mpu3050_report(st, timestamp, st->fifo_counter, data);
fifo_count -= byte_read;
if (st->fifo_counter == 0) {
st->fifo_counter = 1;
@@ -364,8 +789,7 @@ end_session:
return IRQ_HANDLED;
flush_fifo:
/* Flush HW and SW FIFOs. */
- inv_reset_fifo(st);
- inv_clear_kfifo(st);
+ mpu3050_fifo_reset(st);
return IRQ_HANDLED;
}
void inv_setup_reg_mpu3050(struct inv_reg_map_s *reg)
@@ -399,9 +823,6 @@ int inv_init_config_mpu3050(struct inv_gyro_state_s *st)
int result;
unsigned char data;
- if (st->chip_config.is_asleep)
- return -EPERM;
-
/*reading AUX VDDIO register */
result = inv_i2c_read(st, REG_3050_AUX_VDDIO, 1, &data);
if (result)
@@ -421,7 +842,7 @@ int inv_init_config_mpu3050(struct inv_gyro_state_s *st)
| INV_FILTER_42HZ);
if (result)
return result;
- st->chip_config.fsr = INV_FSR_2000DPS;
+ st->chip_config.gyro_fsr = INV_FSR_2000DPS;
st->chip_config.lpf = INV_FILTER_42HZ;
result = inv_i2c_single_write(st, reg->sample_rate_div, 19);
if (result)
@@ -430,9 +851,6 @@ int inv_init_config_mpu3050(struct inv_gyro_state_s *st)
st->irq_dur_us = 20*1000;
st->chip_config.enable = 0;
st->chip_config.dmp_on = 0;
- st->compass_divider = 0;
- st->compass_counter = 0;
- st->chip_config.compass_enable = 0;
st->chip_config.firmware_loaded = 0;
st->chip_config.prog_start_addr = DMP_START_ADDR;
st->chip_config.gyro_enable = 1;
@@ -460,142 +878,72 @@ int inv_init_config_mpu3050(struct inv_gyro_state_s *st)
}
return 0;
}
-/**
- * set_power_mpu3050() - set power of mpu3050.
- * @st: Device driver instance.
- * @power_on: on/off
- */
-int set_power_mpu3050(struct inv_gyro_state_s *st,
- unsigned char power_on)
+
+int set_3050_bypass(struct inv_gyro_state_s *st, int enable)
{
struct inv_reg_map_s *reg;
- unsigned char data, p;
int result;
+ unsigned char b;
+
reg = st->reg;
- if (power_on) {
- data = 0;
+ result = inv_i2c_read(st, reg->user_ctrl, 1, &b);
+ if (result)
+ return result;
+ if (((b & BIT_3050_AUX_IF_EN) == 0) && enable)
+ return 0;
+ if ((b & BIT_3050_AUX_IF_EN) && (enable == 0))
+ return 0;
+ b &= ~BIT_3050_AUX_IF_EN;
+ if (!enable) {
+ b |= BIT_3050_AUX_IF_EN;
+ result = inv_i2c_single_write(st, reg->user_ctrl, b);
+ return result;
} else {
- if (st->mpu_slave) {
- result = st->mpu_slave->suspend(st);
- if (result)
- return result;
- }
-
- data = BIT_SLEEP;
- }
- if (st->chip_config.gyro_enable) {
- p = (BITS_3050_POWER1 | INV_CLK_PLL);
- result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p);
- if (result)
- return result;
-
- p = (BITS_3050_POWER2 | INV_CLK_PLL);
- result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p);
+ /* Coming out of I2C is tricky due to several erratta. Do not
+ * modify this algorithm
+ */
+ /*
+ * 1) wait for the right time and send the command to change
+ * the aux i2c slave address to an invalid address that will
+ * get nack'ed
+ *
+ * 0x00 is broadcast. 0x7F is unlikely to be used by any aux.
+ */
+ result = inv_i2c_single_write(st, REG_3050_SLAVE_ADDR,
+ 0x7F);
if (result)
return result;
-
- p = INV_CLK_PLL;
- result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p);
+ /*
+ * 2) wait enough time for a nack to occur, then go into
+ * bypass mode:
+ */
+ mdelay(2);
+ result = inv_i2c_single_write(st, reg->user_ctrl, b);
if (result)
return result;
-
- st->chip_config.clk_src = INV_CLK_PLL;
- } else {
- data |= (BITS_3050_GYRO_STANDBY | INV_CLK_INTERNAL);
- result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data);
+ /*
+ * 3) wait for up to one MPU cycle then restore the slave
+ * address
+ */
+ mdelay(20);
+ result = inv_i2c_single_write(st, REG_3050_SLAVE_REG,
+ st->plat_data.secondary_read_reg);
if (result)
return result;
- st->chip_config.clk_src = INV_CLK_INTERNAL;
- }
- if (power_on) {
- mdelay(POWER_UP_TIME);
- if (st->mpu_slave) {
- result = st->mpu_slave->resume(st);
- if (result)
- return result;
- }
- st->chip_config.is_asleep = 0;
- } else
- st->chip_config.is_asleep = 1;
- return 0;
-}
-/**
- * reset_fifo_mpu3050() - Reset FIFO related registers
- * @st: Device driver instance.
- */
-int reset_fifo_mpu3050(struct inv_gyro_state_s *st)
-{
- struct inv_reg_map_s *reg;
- int result;
- unsigned char val, user_ctrl;
- reg = st->reg;
- /* disable interrupt */
- result = inv_i2c_single_write(st, reg->int_enable, 0);
- if (result)
- return result;
- /* disable the sensor output to FIFO */
- result = inv_i2c_single_write(st, reg->fifo_en, 0);
- if (result)
- goto reset_fifo_fail;
- result = inv_i2c_read(st, reg->user_ctrl, 1, &user_ctrl);
- if (result)
- goto reset_fifo_fail;
- /* disable fifo reading */
- user_ctrl &= ~BIT_FIFO_EN;
- st->fifo_counter = 0;
- /* reset fifo */
- val = (BIT_3050_FIFO_RST | user_ctrl);
- result = inv_i2c_single_write(st, reg->user_ctrl, val);
- if (result)
- goto reset_fifo_fail;
- mdelay(POWER_UP_TIME);
- st->last_isr_time = get_time_ns();
- if (st->chip_config.dmp_on) {
- /* enable interrupt when DMP is done */
- result = inv_i2c_single_write(st, reg->int_enable,
- BIT_DMP_INT_EN);
+ result = inv_i2c_single_write(st, REG_3050_SLAVE_ADDR,
+ st->plat_data.secondary_i2c_addr);
if (result)
return result;
result = inv_i2c_single_write(st, reg->user_ctrl,
- BIT_FIFO_EN|user_ctrl);
- if (result)
- return result;
- } else {
- /* enable interrupt */
- if (st->chip_config.accl_fifo_enable ||
- st->chip_config.gyro_fifo_enable){
- result = inv_i2c_single_write(st, reg->int_enable,
- BIT_DATA_RDY_EN);
- if (result)
- return result;
- }
- /* enable FIFO reading and I2C master interface*/
- result = inv_i2c_single_write(st, reg->user_ctrl,
- BIT_FIFO_EN | user_ctrl);
- if (result)
- return result;
- /* enable sensor output to FIFO and FIFO footer*/
- val = 1;
- if (st->chip_config.accl_fifo_enable)
- val |= BITS_3050_ACCL_OUT;
- if (st->chip_config.gyro_fifo_enable)
- val |= BITS_GYRO_OUT;
- result = inv_i2c_single_write(st, reg->fifo_en, val);
+ (b | BIT_3050_AUX_IF_RST));
if (result)
return result;
- }
+ mdelay(2);
+ }
return 0;
-reset_fifo_fail:
- if (st->chip_config.dmp_on)
- val = BIT_DMP_INT_EN;
- else
- val = BIT_DATA_RDY_EN;
- inv_i2c_single_write(st, reg->int_enable, val);
- pr_err("%s failed\n", __func__);
- return result;
}
/**
* @}
diff --git a/drivers/input/misc/pressure/Kconfig b/drivers/input/misc/pressure/Kconfig
new file mode 100644
index 000000000000..adacb4ab7868
--- /dev/null
+++ b/drivers/input/misc/pressure/Kconfig
@@ -0,0 +1,12 @@
+#
+# Kconfig for stand-alone pressure input device drivers
+#
+
+config INV_BMP180
+ tristate "Bosch BMP180 pressure input device driver"
+ depends on I2C && SYSFS && INPUT && INPUT_EVDEV
+ default n
+ help
+ This driver supports the Bosch BMP180 pressure sensor.
+ This driver can be built as a module. The module will be called
+ inv-bmp180.
diff --git a/drivers/input/misc/pressure/Makefile b/drivers/input/misc/pressure/Makefile
new file mode 100644
index 000000000000..6831383c3c92
--- /dev/null
+++ b/drivers/input/misc/pressure/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for stand-alone pressure input device drivers
+#
+
+obj-$(CONFIG_INV_BMP180) += inv-bmp180.o
+inv-bmp180-objs += bmp180.o
+
diff --git a/drivers/input/misc/pressure/bmp180.c b/drivers/input/misc/pressure/bmp180.c
new file mode 100644
index 000000000000..25306d157698
--- /dev/null
+++ b/drivers/input/misc/pressure/bmp180.c
@@ -0,0 +1,1080 @@
+/* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mpu.h>
+
+
+#define BMP180_NAME "bmp180"
+#define BMP180_I2C_ADDR (0x77)
+#define BMP180_HW_DELAY_MS (10)
+#define BMP180_POLL_DELAY_MS_DFLT (200)
+#define BMP180_MPU_RETRY_COUNT (20)
+#define BMP180_MPU_RETRY_DELAY_MS (20)
+#define BMP180_ERR_CNT_MAX (20)
+/* sampling delays */
+#define BMP180_DELAY_ULP (5)
+#define BMP180_DELAY_ST (8)
+#define BMP180_DELAY_HIGH_RES (14)
+#define BMP180_DELAY_UHIGH_RES (26)
+/* input poll values*/
+#define BMP180_INPUT_RESOLUTION (1)
+#define BMP180_INPUT_DIVISOR (100)
+#define BMP180_INPUT_DELAY_MS_MIN (BMP180_DELAY_UHIGH_RES)
+#define BMP180_INPUT_POWER_UA (12)
+#define BMP180_PRESSURE_MIN (30000)
+#define BMP180_PRESSURE_MAX (110000)
+#define BMP180_PRESSURE_FUZZ (5)
+#define BMP180_PRESSURE_FLAT (5)
+/* BMP180 registers */
+#define BMP180_REG_ID (0xD0)
+#define BMP180_REG_ID_VAL (0x55)
+#define BMP180_REG_RESET (0xE0)
+#define BMP180_REG_RESET_VAL (0xB6)
+#define BMP180_REG_CTRL (0xF4)
+#define BMP180_REG_CTRL_MODE_MASK (0x1F)
+#define BMP180_REG_CTRL_MODE_PRES (0x34)
+#define BMP180_REG_CTRL_MODE_TEMP (0x2E)
+#define BMP180_REG_CTRL_OSS (6)
+#define BMP180_REG_CTRL_SCO (5)
+#define BMP180_REG_OUT_MSB (0xF6)
+#define BMP180_REG_OUT_LSB (0xF7)
+#define BMP180_REG_OUT_XLSB (0xF8)
+/* ROM registers */
+#define BMP180_REG_AC1 (0xAA)
+#define BMP180_REG_AC2 (0xAC)
+#define BMP180_REG_AC3 (0xAE)
+#define BMP180_REG_AC4 (0xB0)
+#define BMP180_REG_AC5 (0xB2)
+#define BMP180_REG_AC6 (0xB4)
+#define BMP180_REG_B1 (0xB6)
+#define BMP180_REG_B2 (0xB8)
+#define BMP180_REG_MB (0xBA)
+#define BMP180_REG_MC (0xBC)
+#define BMP180_REG_MD (0xBE)
+
+#define WR (0)
+#define RD (1)
+
+
+/* regulator names in order of powering on */
+static char *bmp180_vregs[] = {
+ "vdd",
+ "vddio",
+};
+
+static unsigned long bmp180_delay_ms_tbl[] = {
+ BMP180_DELAY_ULP,
+ BMP180_DELAY_ST,
+ BMP180_DELAY_HIGH_RES,
+ BMP180_DELAY_UHIGH_RES,
+};
+
+
+struct bmp180_rom {
+ s16 ac1;
+ s16 ac2;
+ s16 ac3;
+ u16 ac4;
+ u16 ac5;
+ u16 ac6;
+ s16 b1;
+ s16 b2;
+ s16 mb;
+ s16 mc;
+ s16 md;
+};
+
+struct bmp180_inf {
+ struct i2c_client *i2c;
+ struct input_dev *idev;
+ struct workqueue_struct *wq;
+ struct delayed_work dw;
+ struct regulator_bulk_data vreg[ARRAY_SIZE(bmp180_vregs)];
+ struct mpu_platform_data pdata;
+ struct bmp180_rom rom; /* data for calibration */
+ unsigned long poll_delay_us; /* requested sampling delay (us) */
+ unsigned int resolution; /* report when new data outside this */
+ bool use_mpu; /* if device behind MPU */
+ bool initd; /* set if initialized */
+ bool enable; /* requested enable value */
+ bool report; /* used to report first valid sample */
+ bool port_en[2]; /* enable status of MPU write port */
+ int port_id[2]; /* MPU port ID */
+ u8 data_out; /* write value to trigger a sample */
+ u8 range_index; /* oversampling value */
+ long UT; /* uncompensated temperature */
+ long UP; /* uncompensated pressure */
+ long temperature; /* true temperature */
+ int pressure; /* true pressure hPa/100 Pa/1 mBar */
+};
+
+
+static int bmp180_i2c_rd(struct bmp180_inf *inf, u8 reg, u16 len, u8 *val)
+{
+ struct i2c_msg msg[2];
+
+ msg[0].addr = BMP180_I2C_ADDR;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &reg;
+ msg[1].addr = BMP180_I2C_ADDR;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = len;
+ msg[1].buf = val;
+ if (i2c_transfer(inf->i2c->adapter, msg, 2) != 2)
+ return -EIO;
+
+ return 0;
+}
+
+static int bmp180_i2c_wr(struct bmp180_inf *inf, u8 reg, u8 val)
+{
+ struct i2c_msg msg;
+ u8 buf[2];
+
+ buf[0] = reg;
+ buf[1] = val;
+ msg.addr = BMP180_I2C_ADDR;
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = buf;
+ if (i2c_transfer(inf->i2c->adapter, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int bmp180_vreg_dis(struct bmp180_inf *inf, int i)
+{
+ int err = 0;
+
+ if (inf->vreg[i].ret && (inf->vreg[i].consumer != NULL)) {
+ err = regulator_disable(inf->vreg[i].consumer);
+ if (err)
+ dev_err(&inf->i2c->dev, "%s %s ERR\n",
+ __func__, inf->vreg[i].supply);
+ else
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ }
+ inf->vreg[i].ret = 0;
+ return err;
+}
+
+static int bmp180_vreg_dis_all(struct bmp180_inf *inf)
+{
+ unsigned int i;
+ int err = 0;
+
+ for (i = ARRAY_SIZE(bmp180_vregs); i > 0; i--)
+ err |= bmp180_vreg_dis(inf, (i - 1));
+ return err;
+}
+
+static int bmp180_vreg_en(struct bmp180_inf *inf, int i)
+{
+ int err = 0;
+
+ if ((!inf->vreg[i].ret) && (inf->vreg[i].consumer != NULL)) {
+ err = regulator_enable(inf->vreg[i].consumer);
+ if (!err) {
+ inf->vreg[i].ret = 1;
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ err = 1; /* flag regulator state change */
+ } else {
+ dev_err(&inf->i2c->dev, "%s %s ERR\n",
+ __func__, inf->vreg[i].supply);
+ }
+ }
+ return err;
+}
+
+static int bmp180_vreg_en_all(struct bmp180_inf *inf)
+{
+ int i;
+ int err = 0;
+
+ for (i = 0; i < ARRAY_SIZE(bmp180_vregs); i++)
+ err |= bmp180_vreg_en(inf, i);
+ return err;
+}
+
+static void bmp180_vreg_exit(struct bmp180_inf *inf)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bmp180_vregs); i++) {
+ if (inf->vreg[i].consumer != NULL) {
+ devm_regulator_put(inf->vreg[i].consumer);
+ inf->vreg[i].consumer = NULL;
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ }
+ }
+}
+
+static int bmp180_vreg_init(struct bmp180_inf *inf)
+{
+ unsigned int i;
+ int err = 0;
+
+ for (i = 0; i < ARRAY_SIZE(bmp180_vregs); i++) {
+ inf->vreg[i].supply = bmp180_vregs[i];
+ inf->vreg[i].ret = 0;
+ inf->vreg[i].consumer = devm_regulator_get(&inf->i2c->dev,
+ inf->vreg[i].supply);
+ if (IS_ERR(inf->vreg[i].consumer)) {
+ err |= PTR_ERR(inf->vreg[i].consumer);
+ dev_err(&inf->i2c->dev, "%s err %d for %s\n",
+ __func__, err, inf->vreg[i].supply);
+ inf->vreg[i].consumer = NULL;
+ } else {
+ dev_dbg(&inf->i2c->dev, "%s %s\n",
+ __func__, inf->vreg[i].supply);
+ }
+ }
+ return err;
+}
+
+static int bmp180_pm(struct bmp180_inf *inf, bool enable)
+{
+ int err;
+
+ if (enable) {
+ err = bmp180_vreg_en_all(inf);
+ if (err)
+ mdelay(BMP180_HW_DELAY_MS);
+ } else {
+ err = bmp180_vreg_dis_all(inf);
+ }
+ if (err > 0)
+ err = 0;
+ if (err)
+ dev_err(&inf->i2c->dev, "%s enable=%x ERR=%d\n",
+ __func__, enable, err);
+ else
+ dev_dbg(&inf->i2c->dev, "%s enable=%x\n",
+ __func__, enable);
+ return err;
+}
+
+static int bmp180_port_free(struct bmp180_inf *inf, int port)
+{
+ int err = 0;
+
+ if ((inf->use_mpu) && (inf->port_id[port] >= 0)) {
+ err = nvi_mpu_port_free(inf->port_id[port]);
+ if (!err)
+ inf->port_id[port] = -1;
+ }
+ return err;
+}
+
+static int bmp180_ports_free(struct bmp180_inf *inf)
+{
+ int err;
+
+ err = bmp180_port_free(inf, WR);
+ err |= bmp180_port_free(inf, RD);
+ return err;
+}
+
+static void bmp180_pm_exit(struct bmp180_inf *inf)
+{
+ bmp180_ports_free(inf);
+ bmp180_pm(inf, false);
+ bmp180_vreg_exit(inf);
+}
+
+static int bmp180_pm_init(struct bmp180_inf *inf)
+{
+ int err;
+
+ inf->initd = false;
+ inf->enable = false;
+ inf->port_en[WR] = false;
+ inf->port_en[RD] = false;
+ inf->port_id[WR] = -1;
+ inf->port_id[RD] = -1;
+ inf->resolution = 0;
+ inf->range_index = 0;
+ inf->poll_delay_us = (BMP180_POLL_DELAY_MS_DFLT * 1000);
+ bmp180_vreg_init(inf);
+ err = bmp180_pm(inf, true);
+ return err;
+}
+
+static int bmp180_nvi_mpu_bypass_request(struct bmp180_inf *inf)
+{
+ int i;
+ int err = 0;
+
+ if (inf->use_mpu) {
+ for (i = 0; i < BMP180_MPU_RETRY_COUNT; i++) {
+ err = nvi_mpu_bypass_request(true);
+ if ((!err) || (err == -EPERM))
+ break;
+
+ mdelay(BMP180_MPU_RETRY_DELAY_MS);
+ }
+ if (err == -EPERM)
+ err = 0;
+ }
+ return err;
+}
+
+static int bmp180_nvi_mpu_bypass_release(struct bmp180_inf *inf)
+{
+ int err = 0;
+
+ if (inf->use_mpu)
+ err = nvi_mpu_bypass_release();
+ return err;
+}
+
+static int bmp180_wr(struct bmp180_inf *inf, u8 reg, u8 val)
+{
+ int err = 0;
+
+ err = bmp180_nvi_mpu_bypass_request(inf);
+ if (!err) {
+ err = bmp180_i2c_wr(inf, reg, val);
+ bmp180_nvi_mpu_bypass_release(inf);
+ }
+ return err;
+}
+
+static int bmp180_port_enable(struct bmp180_inf *inf, int port, bool enable)
+{
+ int err = 0;
+
+ if (enable != inf->port_en[port]) {
+ err = nvi_mpu_enable(inf->port_id[port], enable, false);
+ if (!err)
+ inf->port_en[port] = enable;
+ }
+ return err;
+}
+
+static int bmp180_ports_enable(struct bmp180_inf *inf, bool enable)
+{
+ int err;
+
+ err = bmp180_port_enable(inf, WR, enable);
+ err |= bmp180_port_enable(inf, RD, enable);
+ return err;
+}
+
+static int bmp180_reset(struct bmp180_inf *inf)
+{
+ int err = 0;
+
+ if (inf->use_mpu)
+ err = bmp180_ports_enable(inf, false);
+ else
+ cancel_delayed_work_sync(&inf->dw);
+ if (err)
+ return err;
+
+ err = bmp180_wr(inf, BMP180_REG_RESET, BMP180_REG_RESET_VAL);
+ if (!err)
+ mdelay(BMP180_HW_DELAY_MS);
+ if (inf->use_mpu) {
+ err |= nvi_mpu_data_out(inf->port_id[WR],
+ BMP180_REG_CTRL_MODE_TEMP);
+ err |= bmp180_ports_enable(inf, true);
+ } else {
+ err = bmp180_wr(inf, BMP180_REG_CTRL,
+ BMP180_REG_CTRL_MODE_TEMP);
+ queue_delayed_work(inf->wq, &inf->dw,
+ usecs_to_jiffies(inf->poll_delay_us));
+ }
+ return err;
+}
+
+static int bmp180_delay(struct bmp180_inf *inf, unsigned long delay_us)
+{
+ int err = 0;
+
+ if (inf->use_mpu)
+ err = nvi_mpu_delay_us(inf->port_id[RD], delay_us);
+ return err;
+}
+
+static int bmp180_init_hw(struct bmp180_inf *inf)
+{
+ u8 *p_rom1;
+ u8 *p_rom2;
+ u8 tmp;
+ int i;
+ int err = 0;
+
+ inf->UT = 0;
+ inf->UP = 0;
+ inf->temperature = 0;
+ inf->pressure = 0;
+ p_rom1 = (u8 *)&inf->rom.ac1;
+ err = bmp180_nvi_mpu_bypass_request(inf);
+ if (!err) {
+ err = bmp180_i2c_rd(inf, BMP180_REG_AC1, 22, p_rom1);
+ bmp180_nvi_mpu_bypass_release(inf);
+ }
+ if (err)
+ return err;
+
+ for (i = 0; i < 11; i++) {
+ p_rom2 = p_rom1;
+ tmp = *p_rom1;
+ *p_rom1++ = *++p_rom2;
+ *p_rom2 = tmp;
+ p_rom1++;
+ }
+ inf->initd = true;
+ return err;
+}
+
+static void bmp180_calc(struct bmp180_inf *inf)
+{
+ long X1, X2, X3, B3, B5, B6, p;
+ unsigned long B4, B7;
+ long pressure;
+
+ X1 = ((inf->UT - inf->rom.ac6) * inf->rom.ac5) >> 15;
+ X2 = inf->rom.mc * (1 << 11) / (X1 + inf->rom.md);
+ B5 = X1 + X2;
+ inf->temperature = (B5 + 8) >> 4;
+ B6 = B5 - 4000;
+ X1 = (inf->rom.b2 * ((B6 * B6) >> 12)) >> 11;
+ X2 = (inf->rom.ac2 * B6) >> 11;
+ X3 = X1 + X2;
+ B3 = ((((inf->rom.ac1 << 2) + X3) << inf->range_index) + 2) >> 2;
+ X1 = (inf->rom.ac3 * B6) >> 13;
+ X2 = (inf->rom.b1 * ((B6 * B6) >> 12)) >> 16;
+ X3 = ((X1 + X2) + 2) >> 2;
+ B4 = (inf->rom.ac4 * (unsigned long)(X3 + 32768)) >> 15;
+ B7 = ((unsigned long)inf->UP - B3) * (50000 >> inf->range_index);
+ if (B7 < 0x80000000)
+ p = (B7 << 1) / B4;
+ else
+ p = (B7 / B4) << 1;
+ X1 = (p >> 8) * (p >> 8);
+ X1 = (X1 * 3038) >> 16;
+ X2 = (-7357 * p) >> 16;
+ pressure = p + ((X1 + X2 + 3791) >> 4);
+ inf->pressure = (int)pressure;
+}
+
+static void bmp180_report(struct bmp180_inf *inf, u8 *data, s64 ts)
+{
+ input_report_abs(inf->idev, ABS_PRESSURE, inf->pressure);
+ input_sync(inf->idev);
+}
+
+static int bmp180_read_sts(struct bmp180_inf *inf, u8 *data)
+{
+ long val;
+ int limit_lo;
+ int limit_hi;
+ int pres;
+ bool report;
+ int err = 0;
+
+ /* BMP180_REG_CTRL_SCO is 0 when data is ready */
+ val = data[0] & (1 << BMP180_REG_CTRL_SCO);
+ if (!val) {
+ err = -1;
+ if (data[0] == 0x0A) { /* temperature */
+ inf->UT = ((data[2] << 8) + data[3]);
+ inf->data_out = BMP180_REG_CTRL_MODE_PRES |
+ (inf->range_index << BMP180_REG_CTRL_OSS);
+ } else { /* pressure */
+ val = ((data[2] << 16) + (data[3] << 8) + data[4]) >>
+ (8 - inf->range_index);
+ inf->data_out = BMP180_REG_CTRL_MODE_TEMP;
+ if (inf->resolution && (!inf->report)) {
+ if (inf->UP == val)
+ return err;
+ }
+
+ inf->UP = val;
+ bmp180_calc(inf);
+ pres = inf->pressure;
+ if (inf->resolution) {
+ limit_lo = pres;
+ limit_hi = pres;
+ limit_lo -= (inf->resolution / 2);
+ limit_hi += (inf->resolution / 2);
+ if (limit_lo < 0)
+ limit_lo = 0;
+ if ((pres < limit_lo) || (pres > limit_hi))
+ report = true;
+ else
+ report = false;
+ } else {
+ report = true;
+ }
+ if (report || inf->report) {
+ inf->report = false;
+ err = 1;
+ }
+ }
+ }
+ return err;
+}
+
+static s64 bmp180_timestamp_ns(void)
+{
+ struct timespec ts;
+ s64 ns;
+
+ ktime_get_ts(&ts);
+ ns = timespec_to_ns(&ts);
+ return ns;
+}
+
+static int bmp180_read(struct bmp180_inf *inf)
+{
+ long long timestamp1;
+ long long timestamp2;
+ u8 data[5];
+ int err;
+
+ timestamp1 = bmp180_timestamp_ns();
+ err = bmp180_i2c_rd(inf, BMP180_REG_CTRL, 5, data);
+ timestamp2 = bmp180_timestamp_ns();
+ if (err)
+ return err;
+
+ err = bmp180_read_sts(inf, data);
+ if (err > 0) {
+ timestamp2 = (timestamp2 - timestamp1) / 2;
+ timestamp1 += timestamp2;
+ bmp180_report(inf, data, timestamp1);
+ bmp180_i2c_wr(inf, BMP180_REG_CTRL, inf->data_out);
+ } else if (err < 0) {
+ bmp180_i2c_wr(inf, BMP180_REG_CTRL, inf->data_out);
+ }
+ return err;
+}
+
+static void bmp180_mpu_handler(u8 *data, unsigned int len, s64 ts, void *p_val)
+{
+ struct bmp180_inf *inf;
+ int err;
+
+ inf = (struct bmp180_inf *)p_val;
+ if (inf->enable) {
+ err = bmp180_read_sts(inf, data);
+ if (err > 0) {
+ bmp180_report(inf, data, ts);
+ nvi_mpu_data_out(inf->port_id[WR], inf->data_out);
+ } else if (err < 0) {
+ nvi_mpu_data_out(inf->port_id[WR], inf->data_out);
+ }
+ }
+}
+
+static int bmp180_id(struct bmp180_inf *inf)
+{
+ struct nvi_mpu_port nmp;
+ u8 config_boot;
+ u8 val = 0;
+ int err;
+
+ config_boot = inf->pdata.config & NVI_CONFIG_BOOT_MASK;
+ if (config_boot == NVI_CONFIG_BOOT_AUTO) {
+ nmp.addr = BMP180_I2C_ADDR | 0x80;
+ nmp.reg = BMP180_REG_ID;
+ nmp.ctrl = 1;
+ err = nvi_mpu_dev_valid(&nmp, &val);
+ /* see mpu.h for possible return values */
+ if ((err == -EAGAIN) || (err == -EBUSY))
+ return -EAGAIN;
+
+ if (((!err) && (val == BMP180_REG_ID_VAL)) || (err == -EIO))
+ config_boot = NVI_CONFIG_BOOT_MPU;
+ }
+ if (config_boot == NVI_CONFIG_BOOT_MPU) {
+ inf->use_mpu = true;
+ nmp.addr = BMP180_I2C_ADDR | 0x80;
+ nmp.reg = BMP180_REG_CTRL;
+ nmp.ctrl = 5;
+ nmp.data_out = 0;
+ nmp.delay_ms = 0;
+ nmp.delay_us = inf->poll_delay_us;
+ nmp.shutdown_bypass = false;
+ nmp.handler = &bmp180_mpu_handler;
+ nmp.ext_driver = (void *)inf;
+ err = nvi_mpu_port_alloc(&nmp);
+ if (err < 0)
+ return err;
+
+ inf->port_id[RD] = err;
+ nmp.addr = BMP180_I2C_ADDR;
+ nmp.reg = BMP180_REG_CTRL;
+ nmp.ctrl = 1;
+ nmp.data_out = BMP180_REG_CTRL_MODE_TEMP;
+ nmp.delay_ms = bmp180_delay_ms_tbl[inf->range_index];
+ nmp.delay_us = 0;
+ nmp.shutdown_bypass = false;
+ nmp.handler = NULL;
+ nmp.ext_driver = NULL;
+ err = nvi_mpu_port_alloc(&nmp);
+ if (err < 0) {
+ bmp180_ports_free(inf);
+ dev_err(&inf->i2c->dev, "%s ERR %d", __func__, err);
+ } else {
+ inf->port_id[WR] = err;
+ err = 0;
+ }
+ return err;
+ }
+
+ /* NVI_CONFIG_BOOT_EXTERNAL */
+ inf->use_mpu = false;
+ err = bmp180_i2c_rd(inf, BMP180_REG_ID, 1, &val);
+ if ((!err) && (val == BMP180_REG_ID_VAL))
+ return 0;
+
+ return -ENODEV;
+}
+
+static void bmp180_work(struct work_struct *ws)
+{
+ struct bmp180_inf *inf;
+
+ inf = container_of(ws, struct bmp180_inf, dw.work);
+ bmp180_read(inf);
+ queue_delayed_work(inf->wq, &inf->dw,
+ usecs_to_jiffies(inf->poll_delay_us));
+}
+
+static int bmp180_enable(struct bmp180_inf *inf, bool enable)
+{
+ int err = 0;
+
+ bmp180_pm(inf, true);
+ if (!inf->initd)
+ err = bmp180_init_hw(inf);
+ if (enable) {
+ inf->report = true;
+ err |= bmp180_delay(inf, inf->poll_delay_us);
+ err |= bmp180_reset(inf);
+ if (!err)
+ inf->enable = true;
+ } else {
+ inf->enable = false;
+ if (inf->use_mpu)
+ err = bmp180_ports_enable(inf, false);
+ else
+ cancel_delayed_work_sync(&inf->dw);
+ if (!err)
+ bmp180_pm(inf, false);
+ }
+ return err;
+}
+
+static ssize_t bmp180_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bmp180_inf *inf;
+ unsigned int enable;
+ bool en;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtouint(buf, 10, &enable);
+ if (err)
+ return -EINVAL;
+
+ if (enable)
+ en = true;
+ else
+ en = false;
+ dev_dbg(&inf->i2c->dev, "%s: %x", __func__, en);
+ err = bmp180_enable(inf, en);
+ if (err) {
+ dev_err(&inf->i2c->dev, "%s: %x ERR=%d", __func__, en, err);
+ return err;
+ }
+
+ return count;
+}
+
+static ssize_t bmp180_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp180_inf *inf;
+ unsigned int enable = 0;
+
+ inf = dev_get_drvdata(dev);
+ if (inf->enable)
+ enable = 1;
+ return sprintf(buf, "%u\n", enable);
+}
+
+static ssize_t bmp180_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bmp180_inf *inf;
+ unsigned long delay_us;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtoul(buf, 10, &delay_us);
+ if (err)
+ return -EINVAL;
+
+ dev_dbg(&inf->i2c->dev, "%s: %lu\n", __func__, delay_us);
+ /* since we rotate between acquiring data for pressure and temperature
+ * we need to go twice as fast.
+ */
+ delay_us >>= 1;
+ if (delay_us < (bmp180_delay_ms_tbl[inf->range_index] * 1000))
+ delay_us = (bmp180_delay_ms_tbl[inf->range_index] * 1000);
+ if (inf->enable && (delay_us != inf->poll_delay_us))
+ err = bmp180_delay(inf, delay_us);
+ if (!err) {
+ inf->poll_delay_us = delay_us;
+ } else {
+ dev_err(&inf->i2c->dev, "%s: %lu ERR=%d\n",
+ __func__, delay_us, err);
+ return err;
+ }
+
+ return count;
+}
+
+static ssize_t bmp180_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp180_inf *inf;
+ unsigned long delay_us;
+
+ inf = dev_get_drvdata(dev);
+ if (inf->enable)
+ delay_us = inf->poll_delay_us;
+ else
+ delay_us = bmp180_delay_ms_tbl[inf->range_index] * 1000;
+ return sprintf(buf, "%lu\n", delay_us);
+}
+
+static ssize_t bmp180_resolution_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bmp180_inf *inf;
+ unsigned int resolution;
+
+ inf = dev_get_drvdata(dev);
+ if (kstrtouint(buf, 10, &resolution))
+ return -EINVAL;
+
+ inf->resolution = resolution;
+ dev_dbg(&inf->i2c->dev, "%s %u", __func__, resolution);
+ return count;
+}
+
+static ssize_t bmp180_resolution_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp180_inf *inf;
+ unsigned int resolution;
+
+ inf = dev_get_drvdata(dev);
+ if (inf->enable)
+ resolution = inf->resolution;
+ else
+ resolution = BMP180_INPUT_RESOLUTION;
+ return sprintf(buf, "%u\n", resolution);
+}
+
+static ssize_t bmp180_max_range_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bmp180_inf *inf;
+ u8 range_index;
+ int err;
+
+ inf = dev_get_drvdata(dev);
+ err = kstrtou8(buf, 10, &range_index);
+ if (err)
+ return -EINVAL;
+
+ if (range_index > 3)
+ return -EINVAL;
+
+ dev_dbg(&inf->i2c->dev, "%s %u", __func__, range_index);
+ inf->range_index = range_index;
+ nvi_mpu_delay_ms(inf->port_id[WR], bmp180_delay_ms_tbl[range_index]);
+ return count;
+}
+
+static ssize_t bmp180_max_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp180_inf *inf;
+ unsigned int range;
+
+ inf = dev_get_drvdata(dev);
+ if (inf->enable)
+ range = inf->range_index;
+ else
+ range = (BMP180_PRESSURE_MAX * BMP180_INPUT_DIVISOR);
+ return sprintf(buf, "%u\n", range);
+}
+
+static ssize_t bmp180_divisor_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp180_inf *inf;
+
+ inf = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", BMP180_INPUT_DIVISOR);
+}
+
+static ssize_t bmp180_microamp_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp180_inf *inf;
+
+ inf = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", BMP180_INPUT_POWER_UA);
+}
+
+static ssize_t bmp180_pressure_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp180_inf *inf;
+
+ inf = dev_get_drvdata(dev);
+ if (inf->enable)
+ return sprintf(buf, "%d\n", inf->pressure);
+
+ return -EPERM;
+}
+
+static ssize_t bmp180_temperature_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bmp180_inf *inf;
+
+ inf = dev_get_drvdata(dev);
+ if (inf->enable)
+ return sprintf(buf, "%ld\n", inf->temperature);
+
+ return -EPERM;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWOTH,
+ bmp180_enable_show, bmp180_enable_store);
+static DEVICE_ATTR(delay, S_IRUGO | S_IWUSR | S_IWOTH,
+ bmp180_delay_show, bmp180_delay_store);
+static DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR | S_IWOTH,
+ bmp180_resolution_show, bmp180_resolution_store);
+static DEVICE_ATTR(max_range, S_IRUGO | S_IWUSR | S_IWOTH,
+ bmp180_max_range_show, bmp180_max_range_store);
+static DEVICE_ATTR(divisor, S_IRUGO,
+ bmp180_divisor_show, NULL);
+static DEVICE_ATTR(microamp, S_IRUGO,
+ bmp180_microamp_show, NULL);
+static DEVICE_ATTR(pressure, S_IRUGO,
+ bmp180_pressure_show, NULL);
+static DEVICE_ATTR(temperature, S_IRUGO,
+ bmp180_temperature_show, NULL);
+
+static struct attribute *bmp180_attrs[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_delay.attr,
+ &dev_attr_resolution.attr,
+ &dev_attr_max_range.attr,
+ &dev_attr_divisor.attr,
+ &dev_attr_microamp.attr,
+ &dev_attr_pressure.attr,
+ &dev_attr_temperature.attr,
+ NULL
+};
+
+static struct attribute_group bmp180_attr_group = {
+ .name = BMP180_NAME,
+ .attrs = bmp180_attrs
+};
+
+static int bmp180_sysfs_create(struct bmp180_inf *inf)
+{
+ int err;
+
+ err = sysfs_create_group(&inf->idev->dev.kobj, &bmp180_attr_group);
+ return err;
+}
+
+static void bmp180_input_close(struct input_dev *idev)
+{
+ struct bmp180_inf *inf;
+
+ inf = input_get_drvdata(idev);
+ if (inf != NULL)
+ bmp180_enable(inf, false);
+}
+
+static int bmp180_input_create(struct bmp180_inf *inf)
+{
+ int err;
+
+ inf->idev = input_allocate_device();
+ if (!inf->idev) {
+ err = -ENOMEM;
+ dev_err(&inf->i2c->dev, "%s ERR %d\n", __func__, err);
+ return err;
+ }
+
+ inf->idev->name = BMP180_NAME;
+ inf->idev->dev.parent = &inf->i2c->dev;
+ inf->idev->close = bmp180_input_close;
+ input_set_drvdata(inf->idev, inf);
+ input_set_capability(inf->idev, EV_ABS, ABS_PRESSURE);
+ input_set_abs_params(inf->idev, ABS_PRESSURE,
+ BMP180_PRESSURE_MIN, BMP180_PRESSURE_MAX,
+ BMP180_PRESSURE_FUZZ, BMP180_PRESSURE_FLAT);
+ err = input_register_device(inf->idev);
+ if (err) {
+ input_free_device(inf->idev);
+ inf->idev = NULL;
+ }
+ return err;
+}
+
+static int bmp180_remove(struct i2c_client *client)
+{
+ struct bmp180_inf *inf;
+
+ inf = i2c_get_clientdata(client);
+ if (inf != NULL) {
+ if (inf->idev) {
+ input_unregister_device(inf->idev);
+ input_free_device(inf->idev);
+ }
+ if (inf->wq)
+ destroy_workqueue(inf->wq);
+ bmp180_pm_exit(inf);
+ kfree(inf);
+ }
+ dev_info(&client->dev, "%s\n", __func__);
+ return 0;
+}
+
+static void bmp180_shutdown(struct i2c_client *client)
+{
+ bmp180_remove(client);
+}
+
+static int bmp180_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct bmp180_inf *inf;
+ struct mpu_platform_data *pd;
+ int err;
+
+ dev_info(&client->dev, "%s\n", __func__);
+ inf = kzalloc(sizeof(*inf), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(inf)) {
+ dev_err(&client->dev, "%s kzalloc ERR\n", __func__);
+ return -ENOMEM;
+ }
+
+ inf->i2c = client;
+ i2c_set_clientdata(client, inf);
+ pd = (struct mpu_platform_data *)dev_get_platdata(&client->dev);
+ if (pd != NULL)
+ inf->pdata = *pd;
+ bmp180_pm_init(inf);
+ err = bmp180_id(inf);
+ bmp180_pm(inf, false);
+ if (err == -EAGAIN)
+ goto bmp180_probe_again;
+ else if (err)
+ goto bmp180_probe_err;
+
+ err = bmp180_input_create(inf);
+ if (err)
+ goto bmp180_probe_err;
+
+ inf->wq = create_singlethread_workqueue(BMP180_NAME);
+ if (!inf->wq) {
+ dev_err(&client->dev, "%s workqueue ERR\n", __func__);
+ err = -ENOMEM;
+ goto bmp180_probe_err;
+ }
+
+ INIT_DELAYED_WORK(&inf->dw, bmp180_work);
+ err = bmp180_sysfs_create(inf);
+ if (err)
+ goto bmp180_probe_err;
+
+ return 0;
+
+bmp180_probe_err:
+ dev_err(&client->dev, "%s ERR %d\n", __func__, err);
+bmp180_probe_again:
+ bmp180_remove(client);
+ return err;
+}
+
+static const struct i2c_device_id bmp180_i2c_device_id[] = {
+ {BMP180_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, bmp180_i2c_device_id);
+
+static struct i2c_driver bmp180_driver = {
+ .class = I2C_CLASS_HWMON,
+ .probe = bmp180_probe,
+ .remove = bmp180_remove,
+ .driver = {
+ .name = BMP180_NAME,
+ .owner = THIS_MODULE,
+ },
+ .id_table = bmp180_i2c_device_id,
+ .shutdown = bmp180_shutdown,
+};
+
+static int __init bmp180_init(void)
+{
+ return i2c_add_driver(&bmp180_driver);
+}
+
+static void __exit bmp180_exit(void)
+{
+ i2c_del_driver(&bmp180_driver);
+}
+
+module_init(bmp180_init);
+module_exit(bmp180_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("BMP180 driver");
+MODULE_AUTHOR("NVIDIA Corp");
+
diff --git a/include/linux/mpu.h b/include/linux/mpu.h
index 1f78833c30f5..3f303da8266a 100644
--- a/include/linux/mpu.h
+++ b/include/linux/mpu.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Invensense, Inc.
+* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -47,8 +48,19 @@
* data defined by dbg_dat
* - A read to dbg_dat initiates an I2C read transaction
* to the device register defined by dbg_reg.
+* dbg_i2c_addr = I2C device address
+* - if set to 0 (default) the MPU I2C address is used.
+* - other devices can be accessed by setting this to the
+* that device I2C address. When used after enabling
+* bypass mode, devices behind the MPU can be accessed.
+* aux_dbg = write 1 to spew auxiliary port register dumps after
+* after each external driver call.
+* Write 0 to disable the spew.
+* Writing anything takes a snapshot of the registers.
+* Therefore, a write of 0 can take snapshots whenever
+* without the external driver call spew.
**********************************************************************/
-#define DEBUG_SYSFS_INTERFACE 0
+#define DEBUG_SYSFS_INTERFACE 1
/* Mount maxtices for mount orientation.
* MTMAT_XXX_CCW_YYY
@@ -251,7 +263,6 @@ enum ext_slave_bus {
EXT_SLAVE_BUS_SECONDARY = 1
};
-
/**
* struct ext_slave_platform_data - Platform data for mpu3050 and mpu6050
* slave devices
@@ -358,6 +369,12 @@ struct ext_slave_descr {
struct ext_slave_read_trigger *trigger;
};
+
+#define NVI_CONFIG_BOOT_AUTO (0) /* auto detect connection to MPU */
+#define NVI_CONFIG_BOOT_MPU (1) /* connected to MPU */
+#define NVI_CONFIG_BOOT_EXTERNAL (2) /* connected to host */
+#define NVI_CONFIG_BOOT_MASK (0x03)
+
/**
* struct mpu_platform_data - Platform data for the mpu driver
* @int_config: Bits [7:3] of the int config register.
@@ -367,6 +384,8 @@ struct ext_slave_descr {
* @sec_slave_id: id of the secondary slave device
* @secondary_i2c_address: secondary device's i2c address
* @secondary_orientation: secondary device's orientation matrix
+ * @config: the selection determines the device behavior.
+ * Select from the NVI_CONFIG_BOOT_ defines.
*
* Contains platform specific information on how to configure the MPU3050 to
* work on this platform. The orientation matricies are 3x3 rotation matricies
@@ -384,6 +403,281 @@ struct mpu_platform_data {
__u8 secondary_read_reg;
__s8 secondary_orientation[9];
__u8 key[16];
+ __u8 config;
+};
+
+/**
+ * struct nvi_mpu_port: Allows an external driver to use the MPU
+ * auxiliary I2C master by providing the details for the I2C
+ * polling of a device connected to the MPU.
+ * - addr: The 6:0 I2C address of the device connected to
+ * the MPU.
+ * 7:7 = 0 if the port is to do write transactions.
+ * = 1 if the port is to do read transactions.
+ * - reg: The device register the I2C transaction will
+ * use.
+ * - ctrl: 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.
+ * - 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
+ * bypass if this is true.
+ * - *handler: The pointer to the function called when the data
+ * is available. This can be NULL if the port is
+ * configured for write transactions.
+ * The function is called with the following parameters:
+ * - *data: The pointer to the data to read.
+ * - length: The number of bytes to be read (same value as
+ * length above).
+ * - timestamp: The timestamp of when the data was polled.
+ * - *pointer: A generic pointer defined next below. Note
+ * that this can be NULL if this will be a write I2C
+ * transaction.
+ * - *ext_driver: A generic pointer that can be used by the
+ * external driver. Note that this is specifically for the
+ * external driver and not used by the MPU.
+ */
+struct nvi_mpu_port {
+ u8 addr;
+ u8 reg;
+ u8 ctrl;
+ u8 data_out;
+ unsigned int delay_ms;
+ unsigned long delay_us;
+ bool shutdown_bypass;
+ void (*handler)(u8 *data, unsigned int len,
+ long long timestamp, void *ext_driver);
+ void *ext_driver;
};
+/**
+ * Expected use of the nvi_mpu_ routines are as follows:
+ * - nvi_mpu_dev_valid: Use to validate whether a device is
+ * connected to the MPU.
+ * - nvi_mpu_port_alloc: Request a connection to the device. If
+ * successful, a port number will be returned to identify
+ * the connection. The port number is then used for all
+ * further communication with the connection.
+ * - nvi_mpu_port_free: Use to close the port connection.
+ * - nvi_mpu_enable: Use to enable/disable a port.
+ * The enable and FIFO enable is disabled by default so
+ * this will be required after a port is assigned.
+ * - nvi_mpu_delay_us: Use to set the sampling rate in
+ * microseconds. The fastest rate of all the enabled MPU
+ * devices will be used that does not exceed the
+ * nvi_mpu_delay_ms setting of an enabled device.
+ * - nvi_mpu_delay_ms: Use to change the port polling delay at
+ * runtime. There is only one HW delay so the delay used
+ * will be the longest delay of all the enabled ports.
+ * This is separate from the sampling rate
+ * (nvi_mpu_delay_us). See function notes below.
+ * - nvi_mpu_data_out: Use to change the data written at runtime
+ * for ports that are configured as I2C write transactions.
+ * - nvi_mpu_bypass request/release: Use to connect/disconnect
+ * the MPU host from the device. When bypass is enabled,
+ * the connection from the device to the MPU will then be
+ * connected to the host (that the MPU is connected to).
+ * This is a global connection switch affecting all ports
+ * so a mechanism is in place of whether the request is
+ * honored or not. See the funtion notes for
+ * nvi_mpu_bypass_request.
+ */
+
+/**
+ * Use to validate a device connected to the MPU I2C master.
+ * The function works by doing a single byte read or write to
+ * the device and detecting a NACK. Typically, the call would
+ * be set up to read a byte ID of the device.
+ * @param struct nvi_mpu_port *nmp
+ * Only the following is needed in nmp:
+ * - addr
+ * - reg
+ * - ctrl
+ * - data_out if a write transaction
+ * @param *val: pointer for read data. Can be NULL if write.
+ * @return int error
+ * Possible return value or errors are:
+ * - 0: device is connected to MPU.
+ * - -EAGAIN: MPU is not initialized yet.
+ * - -EPERM: MPU is shutdown. MPU API won't be
+ * available until a system restart.
+ * - -EBUSY: MPU is busy with another request.
+ * - -ENODEV: The device is not connected to the MPU.
+ * - -EINVAL: Problem with input parameters.
+ * - -EIO: The device is connected but responded with
+ * a NACK.
+ */
+int nvi_mpu_dev_valid(struct nvi_mpu_port *nmp, u8 *data);
+
+/**
+ * Request a port.
+ * @param struct nvi_mpu_port *nmp
+ * - addr: device I2C address 6:0.
+ * 7:7 = 0 if the port is to do writes.
+ * 7:7 = 1 if the port is to do reads.
+ * - reg: the starting register to write or read.
+ * - ctrl: number of bytes to read. Use 1 if port
+ * is configured to do writes.
+ * - data_out: only valid if port is configured to do
+ * writes.
+ * - delay: polling delay
+ * - handler: function to call when data is read. This
+ * should be NULL if the port is configured to do
+ * writes.
+ * - ext_driver: this pointer is passed in handler for
+ * use by external driver. This should be NULL
+ * if the port is configured for writes.
+ * @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).
+ * Possible errors are:
+ * - -EAGAIN: MPU is not initialized yet.
+ * - -EPERM: MPU is shutdown. MPU API won't be
+ * available until a system restart.
+ * - -EBUSY: MPU is busy with another request.
+ * - -ENODEV: A port is not available. The only way
+ * to resolve this error is for a port to be
+ * freed.
+ * - -EINVAL: Problem with input parameters.
+ */
+int nvi_mpu_port_alloc(struct nvi_mpu_port *nmp);
+
+/**
+ * Remove a port.
+ * @param port
+ * @return int error
+ * Possible errors are:
+ * - -EAGAIN: MPU is not initialized yet.
+ * - -EPERM: MPU is shutdown. MPU API won't be
+ * available until a system restart.
+ * - -EBUSY: MPU is busy with another request.
+ * - -EINVAL: Problem with input parameters.
+ */
+int nvi_mpu_port_free(int port);
+
+/**
+ * Enable/disable a port.
+ * @param port
+ * @param enable
+ * @return int error
+ * Possible errors are:
+ * - -EAGAIN: MPU is not initialized yet.
+ * - -EPERM: MPU is shutdown. MPU API won't be
+ * available until a system restart.
+ * - -EBUSY: MPU is busy with another request.
+ * - -EINVAL: Problem with input parameters.
+ */
+int nvi_mpu_enable(int port, bool enable, bool fifo_enable);
+
+/**
+ * Use to change the ports sampling delay in microseconds. The
+ * hardware only supports one sampling rate so the shortest time
+ * is used among all enabled ports, accelerometer, and gyro. If
+ * the requested rate is longer than the actual rate and the
+ * port is configured for reads, the data will be reported at
+ * the requested rate skipping the data polled at the faster
+ * rate. Setting this to zero causes other enabled devices to
+ * determine the sampling rate. If there are no other enabled
+ * devices, then the MPU default rate is used.
+ * @param port
+ * @param delay_us
+ * @return int error
+ * Possible errors are:
+ * - -EAGAIN: MPU is not initialized yet.
+ * - -EPERM: MPU is shutdown. MPU API won't be
+ * available until a system restart.
+ * - -EBUSY: MPU is busy with another request.
+ * - -EINVAL: Problem with input parameters.
+ */
+int nvi_mpu_delay_us(int port, unsigned long delay_us);
+
+/**
+ * Use to change the ports polling delay in milliseconds.
+ * A delay value of 0 disables the delay for that port. The
+ * hardware only supports one delay value so the largest request
+ * of all the enabled ports is used. The polling delay is in
+ * addition to the sampling delay (nvi_mpu_delay_us). This is
+ * typically used to guarantee a delay after an I2C write to a
+ * device to allow the device to process the request and be read
+ * by another port before another write at the sampling delay.
+ *
+ * @param port
+ * @param delay_ms
+ * @return int error/delay used or 0 if request is to disable
+ * and is successful.
+ * Possible errors are:
+ * - -EAGAIN: MPU is not initialized yet.
+ * - -EPERM: MPU is shutdown. MPU API won't be
+ * available until a system restart.
+ * - -EBUSY: MPU is busy with another request.
+ * - -EINVAL: Problem with input parameters.
+ */
+int nvi_mpu_delay_ms(int port, u8 delay_ms);
+
+/**
+ * Use to change the data written to the sensor.
+ * @param port
+ * @param data_out is the new data to be written
+ * @return int error
+ * Possible errors are:
+ * - -EAGAIN: MPU is not initialized yet.
+ * - -EPERM: MPU is shutdown. MPU API won't be
+ * available until a system restart.
+ * - -EBUSY: MPU is busy with another request.
+ * - -EINVAL: Problem with input parameters.
+ */
+int nvi_mpu_data_out(int port, u8 data_out);
+
+/**
+ * Enable/disable the MPU bypass mode. When enabled, the MPU
+ * will connect its auxiliary I2C ports to the host. This is
+ * typically used to initialize a device that requires more I2C
+ * transactions than the automated port polling can offer.
+ * EVERY nvi_mpu_bypass_request call must be balanced with a
+ * nvi_mpu_bypass_release call!
+ * A bypass request does not need a following ~enable call. The
+ * release call will automatically handle the correct bypass
+ * enable setting. The request locks the bypass setting if
+ * successful. The release unlocks and restores the setting if
+ * need be. Although odd, the purpose of the request call with
+ * the enable cleared to false is to allow an external driver to
+ * access its device that would normally conflict with a device
+ * behind the MPU. Note that this call must not be a permanent
+ * solution, i.e. delayed or no release call.
+ * When the MPU is in a shutdown state the return error will be
+ * -EPERM and bypass will be enabled to allow access from the
+ * host to the devices connected to the MPU for their own
+ * shutdown needs.
+ * @param enable
+ * @return int error: calls that return with an error must not
+ * be balanced with a release call.
+ * Possible errors are:
+ * - -EAGAIN: MPU is not initialized yet.
+ * - -EPERM: MPU is shutdown. MPU API won't be
+ * available until a system restart.
+ * - -EBUSY: MPU is busy with another request.
+ */
+int nvi_mpu_bypass_request(bool enable);
+
+/**
+ * See the nvi_mpu_bypass_request notes.
+ * @return int error: calls that return with an error must be
+ * tried again.
+ * Possible errors are:
+ * - -EAGAIN: MPU is not initialized yet.
+ * - -EPERM: MPU is shutdown. MPU API won't be
+ * available until a system restart.
+ * - -EBUSY: MPU is busy with another request.
+ */
+int nvi_mpu_bypass_release(void);
+
#endif /* __MPU_H_ */