compatible = "nxp,pcf8563";
reg = <0x51>;
};
-
+/*
sensor@1d {
compatible = "gs_mma8452";
reg = <0x1d>;
irq_enable = <1>;
poll_delay_ms = <30>;
layout = <8>;
+ status = "disabled";
};
+
sensor@0d {
compatible = "ak8975";
reg = <0x0d>;
irq_enable = <1>;
poll_delay_ms = <30>;
layout = <1>;
+ status = "disabled";
};
+*/
sensor@10 {
compatible = "ls_cm3218";
reg = <0x10>;
poll_delay_ms = <30>;
layout = <1>;
};
-
+
+ mpu6050:mpu@68{
+ compatible = "mpu6050";
+ reg = <0x68>;
+ mpu-int_config = <0x10>;
+ mpu-level_shifter = <0>;
+ mpu-orientation = <1 0 0 0 1 0 0 0 1>;
+ orientation-x= <1>;
+ orientation-y= <0>;
+ orientation-z= <1>;
+ irq-gpio = <&gpio8 GPIO_A0 IRQ_TYPE_LEVEL_LOW>;
+ mpu-debug = <1>;
+ };
+/*
+ ak8963:compass@0d{
+ compatible = "ak8963";
+ reg = <0x0d>;
+ compass-bus = <0>;
+ compass-adapt_num = <0>;
+ compass-orientation = <1 0 0 0 1 0 0 0 1>;
+ orientation-x= <0>;
+ orientation-y= <0>;
+ orientation-z= <1>;
+ compass-debug = <1>;
+ status = "disabled";
+ };
+*/
+ ak8975:compass@0d{
+ compatible = "ak8975";
+ reg = <0x0d>;
+ compass-bus = <0>;
+ compass-adapt_num = <0>;
+ compass-orientation = <1 0 0 0 1 0 0 0 1>;
+ orientation-x= <1>;
+ orientation-y= <0>;
+ orientation-z= <1>;
+ compass-debug = <1>;
+ };
+
};
&i2c2 {
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
+source "drivers/misc/inv_mpu/Kconfig"
source "drivers/misc/ti-st/Kconfig"
source "drivers/misc/lis3lv02d/Kconfig"
source "drivers/misc/carma/Kconfig"
obj-$(CONFIG_INTEL_MEI) += mei/
obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
+obj-y += inv_mpu/
obj-$(CONFIG_SRAM) += sram.o
menuconfig: INV_SENSORS
tristate "Motion Processing Unit"
depends on I2C
+ default n
if INV_SENSORS
* @file bma150.c
* @brief Accelerometer setup and handling methods for Bosch BMA150.
*/
-#define DEBUG
+
/* -------------------------------------------------------------------------- */
#include <linux/i2c.h>
#include <linux/module.h>
struct bma150_mod_private_data *private_data;
int result = 0;
- dev_info(&client->adapter->dev, "%s: %s,0x%x\n", __func__, devid->name,(unsigned int)client);
+ dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
result = -ENODEV;
#define BMA222_PWR_REG (0x11)
#define BMA222_SOFTRESET_REG (0x14)
-#define BMA222_INTTERUPTSET_REG (0x17)
-
#define BMA222_STATUS_RDY_MASK (0x80)
#define BMA222_FSR_MASK (0x0F)
#define BMA222_ODR_MASK (0x1F)
break;
case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
case MPU_SLAVE_CONFIG_IRQ_RESUME:
- //zwp,TODO,need to add irq config???
- return INV_SUCCESS;
default:
return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
};
*((long *)data->data));
case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
case MPU_SLAVE_CONFIG_IRQ_RESUME:
- //zwp,TODO,need to add irq config???
- return INV_SUCCESS;
default:
return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
};
unsigned char *data)
{
int result = INV_SUCCESS;
-/* result = inv_serial_read(mlsl_handle, pdata->address,
+ result = inv_serial_read(mlsl_handle, pdata->address,
BMA222_STATUS_REG, 1, data);
if (data[0] & BMA222_STATUS_RDY_MASK) {
-*/
result = inv_serial_read(mlsl_handle, pdata->address,
slave->read_reg, slave->read_len, data);
-
return result;
-/* } else{
+ } else
return INV_ERROR_ACCEL_DATA_NOT_READY;
- }
-*/
}
static struct ext_slave_descr bma222_descr = {
struct ext_slave_platform_data *pdata;
struct bma222_mod_private_data *private_data;
int result = 0;
- printk("%s,++++++++++++++++++++\n",__FUNCTION__);
+
dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
--- /dev/null
+/*
+ $License:
+ Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+/**
+ * @addtogroup ACCELDL
+ * @brief Provides the interface to setup and handle an accelerometer.
+ *
+ * @{
+ * @file mpu6050.c
+ * @brief Accelerometer setup and handling methods for Invensense MPU6050
+ */
+
+/* -------------------------------------------------------------------------- */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include "mpu-dev.h"
+
+#include <log.h>
+#include <linux/mpu.h>
+#include "mpu6050b1.h"
+#include "mlsl.h"
+#include "mldl_cfg.h"
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+/* -------------------------------------------------------------------------- */
+
+struct mpu6050_config {
+ unsigned int odr; /**< output data rate 1/1000 Hz */
+ unsigned int fsr; /**< full scale range mg */
+ unsigned int ths; /**< mot/no-mot thseshold mg */
+ unsigned int dur; /**< mot/no-mot duration ms */
+ unsigned int irq_type; /**< irq type */
+};
+
+struct mpu6050_private_data {
+ struct mpu6050_config suspend;
+ struct mpu6050_config resume;
+ struct mldl_cfg *mldl_cfg_ref;
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int mpu6050_set_mldl_cfg_ref(void *mlsl_handle,
+ struct ext_slave_platform_data *pdata,
+ struct mldl_cfg *mldl_cfg_ref)
+{
+ struct mpu6050_private_data *private_data =
+ (struct mpu6050_private_data *)pdata->private_data;
+ private_data->mldl_cfg_ref = mldl_cfg_ref;
+ return 0;
+}
+static int mpu6050_set_lp_mode(void *mlsl_handle,
+ struct ext_slave_platform_data *pdata,
+ unsigned char lpa_freq)
+{
+ unsigned char b = 0;
+ /* Reducing the duration setting for lp mode */
+ b = 1;
+ inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_ACCEL_MOT_DUR, b);
+ /* Setting the cycle bit and LPA wake up freq */
+ inv_serial_read(mlsl_handle, pdata->address, MPUREG_PWR_MGMT_1, 1,
+ &b);
+ b |= BIT_CYCLE | BIT_PD_PTAT;
+ inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_1,
+ b);
+ inv_serial_read(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_2, 1, &b);
+ b |= lpa_freq & BITS_LPA_WAKE_CTRL;
+ inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_2, b);
+
+ return INV_SUCCESS;
+}
+
+static int mpu6050_set_fp_mode(void *mlsl_handle,
+ struct ext_slave_platform_data *pdata)
+{
+ unsigned char b;
+ struct mpu6050_private_data *private_data =
+ (struct mpu6050_private_data *)pdata->private_data;
+ /* Resetting the cycle bit and LPA wake up freq */
+ inv_serial_read(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_1, 1, &b);
+ b &= ~BIT_CYCLE & ~BIT_PD_PTAT;
+ inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_1, b);
+ inv_serial_read(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_2, 1, &b);
+ b &= ~BITS_LPA_WAKE_CTRL;
+ inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_2, b);
+ /* Resetting the duration setting for fp mode */
+ b = (unsigned char)private_data->suspend.ths / ACCEL_MOT_DUR_LSB;
+ inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_ACCEL_MOT_DUR, b);
+
+ return INV_SUCCESS;
+}
+/**
+ * Record the odr for use in computing duration values.
+ *
+ * @param config Config to set, suspend or resume structure
+ * @param odr output data rate in 1/1000 hz
+ */
+static int mpu6050_set_odr(void *mlsl_handle,
+ struct ext_slave_platform_data *pdata,
+ struct mpu6050_config *config, long apply, long odr)
+{
+ int result;
+ unsigned char b;
+ unsigned char lpa_freq = 1; /* Default value */
+ long base;
+ int total_divider;
+ struct mpu6050_private_data *private_data =
+ (struct mpu6050_private_data *)pdata->private_data;
+ struct mldl_cfg *mldl_cfg_ref =
+ (struct mldl_cfg *)private_data->mldl_cfg_ref;
+
+ if (mldl_cfg_ref) {
+ base = 1000 *
+ inv_mpu_get_sampling_rate_hz(mldl_cfg_ref->mpu_gyro_cfg)
+ * (mldl_cfg_ref->mpu_gyro_cfg->divider + 1);
+ } else {
+ /* have no reference to mldl_cfg => assume base rate is 1000 */
+ base = 1000000L;
+ }
+
+ if (odr != 0) {
+ total_divider = (base / odr) - 1;
+ /* final odr MAY be different from requested odr due to
+ integer truncation */
+ config->odr = base / (total_divider + 1);
+ } else {
+ config->odr = 0;
+ return 0;
+ }
+
+ /* if the DMP and/or gyros are on, don't set the ODR =>
+ the DMP/gyro mldl_cfg->divider setting will handle it */
+ if (apply
+ && (mldl_cfg_ref &&
+ !(mldl_cfg_ref->inv_mpu_cfg->requested_sensors &
+ INV_DMP_PROCESSOR))) {
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_SMPLRT_DIV,
+ (unsigned char)total_divider);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ MPL_LOGI("ODR : %d mHz\n", config->odr);
+ }
+ /* Decide whether to put accel in LP mode or pull out of LP mode
+ based on the odr. */
+ switch (odr) {
+ case 1000:
+ lpa_freq = BITS_LPA_WAKE_1HZ;
+ break;
+ case 2000:
+ lpa_freq = BITS_LPA_WAKE_2HZ;
+ break;
+ case 10000:
+ lpa_freq = BITS_LPA_WAKE_10HZ;
+ break;
+ case 40000:
+ lpa_freq = BITS_LPA_WAKE_40HZ;
+ break;
+ default:
+ inv_serial_read(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_1, 1, &b);
+ b &= BIT_CYCLE;
+ if (b == BIT_CYCLE) {
+ MPL_LOGI(" Accel LP - > FP mode. \n ");
+ mpu6050_set_fp_mode(mlsl_handle, pdata);
+ }
+ }
+ /* If lpa_freq default value was changed, set into LP mode */
+ if (lpa_freq != 1) {
+ MPL_LOGI(" Accel FP - > LP mode. \n ");
+ mpu6050_set_lp_mode(mlsl_handle, pdata, lpa_freq);
+ }
+ return 0;
+}
+
+static int mpu6050_set_fsr(void *mlsl_handle,
+ struct ext_slave_platform_data *pdata,
+ struct mpu6050_config *config, long apply, long fsr)
+{
+ unsigned char fsr_mask;
+ int result;
+
+ if (fsr <= 2000) {
+ config->fsr = 2000;
+ fsr_mask = 0x00;
+ } else if (fsr <= 4000) {
+ config->fsr = 4000;
+ fsr_mask = 0x08;
+ } else if (fsr <= 8000) {
+ config->fsr = 8000;
+ fsr_mask = 0x10;
+ } else { /* fsr = [8001, oo) */
+ config->fsr = 16000;
+ fsr_mask = 0x18;
+ }
+
+ if (apply) {
+ unsigned char reg;
+ result = inv_serial_read(mlsl_handle, pdata->address,
+ MPUREG_ACCEL_CONFIG, 1, ®);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_ACCEL_CONFIG,
+ reg | fsr_mask);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ MPL_LOGV("FSR: %d\n", config->fsr);
+ }
+ return 0;
+}
+
+static int mpu6050_set_irq(void *mlsl_handle,
+ struct ext_slave_platform_data *pdata,
+ struct mpu6050_config *config, long apply,
+ long irq_type)
+{
+ int result;
+ unsigned char reg_int_cfg;
+
+ /* HACK, no need for interrupts for MPU6050 accel
+ - use of soft interrupt is required */
+#if 0
+ switch (irq_type) {
+ case MPU_SLAVE_IRQ_TYPE_DATA_READY:
+ config->irq_type = irq_type;
+ reg_int_cfg = BIT_RAW_RDY_EN;
+ break;
+ /* todo: add MOTION, NO_MOTION, and FREEFALL */
+ case MPU_SLAVE_IRQ_TYPE_NONE:
+ /* Do nothing, not even set the interrupt because it is
+ shared with the gyro */
+ config->irq_type = irq_type;
+ return 0;
+ default:
+ return INV_ERROR_INVALID_PARAMETER;
+ }
+
+ if (apply) {
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_INT_ENABLE,
+ reg_int_cfg);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ MPL_LOGV("irq_type: %d\n", config->irq_type);
+ }
+#endif
+
+ return 0;
+}
+
+static int mpu6050_set_ths(void *mlsl_handle,
+ struct ext_slave_platform_data *slave,
+ struct mpu6050_config *config, long apply, long ths)
+{
+ if (ths < 0)
+ ths = 0;
+
+ config->ths = ths;
+ MPL_LOGV("THS: %d\n", config->ths);
+ return 0;
+}
+
+static int mpu6050_set_dur(void *mlsl_handle,
+ struct ext_slave_platform_data *slave,
+ struct mpu6050_config *config, long apply, long dur)
+{
+ if (dur < 0)
+ dur = 0;
+
+ config->dur = dur;
+ MPL_LOGV("DUR: %d\n", config->dur);
+ return 0;
+}
+
+
+static int mpu6050_init(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ int result;
+ struct mpu6050_private_data *private_data;
+
+
+ private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
+
+ if (!private_data)
+ return INV_ERROR_MEMORY_EXAUSTED;
+
+ pdata->private_data = private_data;
+
+ result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->suspend,
+ false, 0);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->resume,
+ false, 200000);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->suspend,
+ false, 2000);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->resume,
+ false, 2000);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->suspend,
+ false, MPU_SLAVE_IRQ_TYPE_NONE);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->resume,
+ false, MPU_SLAVE_IRQ_TYPE_NONE);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ result = mpu6050_set_ths(mlsl_handle, pdata, &private_data->suspend,
+ false, 80);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = mpu6050_set_ths(mlsl_handle, pdata, &private_data->resume,
+ false, 40);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = mpu6050_set_dur(mlsl_handle, pdata, &private_data->suspend,
+ false, 1000);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = mpu6050_set_dur(mlsl_handle, pdata, &private_data->resume,
+ false, 2540);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ return 0;
+}
+
+static int mpu6050_exit(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ kfree(pdata->private_data);
+ pdata->private_data = NULL;
+ return 0;
+}
+
+static int mpu6050_suspend(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ unsigned char reg;
+ int result;
+ struct mpu6050_private_data *private_data =
+ (struct mpu6050_private_data *)pdata->private_data;
+
+ result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->suspend,
+ true, private_data->suspend.odr);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->suspend,
+ true, private_data->suspend.irq_type);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ result = inv_serial_read(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_2, 1, ®);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ reg |= (BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA);
+
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_2, reg);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ return 0;
+}
+
+static int mpu6050_resume(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ int result;
+ unsigned char reg;
+ struct mpu6050_private_data *private_data =
+ (struct mpu6050_private_data *)pdata->private_data;
+
+ result = inv_serial_read(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_1, 1, ®);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ if (reg & BIT_SLEEP) {
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_1, reg & ~BIT_SLEEP);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ }
+ msleep(2);
+
+ result = inv_serial_read(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_2, 1, ®);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ reg &= ~(BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA);
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_PWR_MGMT_2, reg);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ /* settings */
+
+ result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->resume,
+ true, private_data->resume.fsr);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->resume,
+ true, private_data->resume.odr);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->resume,
+ true, private_data->resume.irq_type);
+
+ /* motion, no_motion */
+ /* TODO : port these in their respective _set_thrs and _set_dur
+ functions and use the APPLY paremeter to apply just like
+ _set_odr, _set_irq, and _set_fsr. */
+ reg = (unsigned char)private_data->suspend.ths / ACCEL_MOT_THR_LSB;
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_ACCEL_MOT_THR, reg);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ reg = (unsigned char)
+ ACCEL_ZRMOT_THR_LSB_CONVERSION(private_data->resume.ths);
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_ACCEL_ZRMOT_THR, reg);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ reg = (unsigned char)private_data->suspend.ths / ACCEL_MOT_DUR_LSB;
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_ACCEL_MOT_DUR, reg);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ reg = (unsigned char)private_data->resume.ths / ACCEL_ZRMOT_DUR_LSB;
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ MPUREG_ACCEL_ZRMOT_DUR, reg);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ return 0;
+}
+
+static int mpu6050_read(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata,
+ unsigned char *data)
+{
+ int result;
+ result = inv_serial_read(mlsl_handle, pdata->address,
+ slave->read_reg, slave->read_len, data);
+ return result;
+}
+
+static int mpu6050_config(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata,
+ struct ext_slave_config *data)
+{
+ struct mpu6050_private_data *private_data =
+ (struct mpu6050_private_data *)pdata->private_data;
+ if (!data->data)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ switch (data->key) {
+ case MPU_SLAVE_CONFIG_ODR_SUSPEND:
+ return mpu6050_set_odr(mlsl_handle, pdata,
+ &private_data->suspend,
+ data->apply, *((long *)data->data));
+ case MPU_SLAVE_CONFIG_ODR_RESUME:
+ return mpu6050_set_odr(mlsl_handle, pdata,
+ &private_data->resume,
+ data->apply, *((long *)data->data));
+ case MPU_SLAVE_CONFIG_FSR_SUSPEND:
+ return mpu6050_set_fsr(mlsl_handle, pdata,
+ &private_data->suspend,
+ data->apply, *((long *)data->data));
+ case MPU_SLAVE_CONFIG_FSR_RESUME:
+ return mpu6050_set_fsr(mlsl_handle, pdata,
+ &private_data->resume,
+ data->apply, *((long *)data->data));
+ case MPU_SLAVE_CONFIG_MOT_THS:
+ return mpu6050_set_ths(mlsl_handle, pdata,
+ &private_data->suspend,
+ data->apply, *((long *)data->data));
+ case MPU_SLAVE_CONFIG_NMOT_THS:
+ return mpu6050_set_ths(mlsl_handle, pdata,
+ &private_data->resume,
+ data->apply, *((long *)data->data));
+ case MPU_SLAVE_CONFIG_MOT_DUR:
+ return mpu6050_set_dur(mlsl_handle, pdata,
+ &private_data->suspend,
+ data->apply, *((long *)data->data));
+ case MPU_SLAVE_CONFIG_NMOT_DUR:
+ return mpu6050_set_dur(mlsl_handle, pdata,
+ &private_data->resume,
+ data->apply, *((long *)data->data));
+ case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
+ return mpu6050_set_irq(mlsl_handle, pdata,
+ &private_data->suspend,
+ data->apply, *((long *)data->data));
+ break;
+ case MPU_SLAVE_CONFIG_IRQ_RESUME:
+ return mpu6050_set_irq(mlsl_handle, pdata,
+ &private_data->resume,
+ data->apply, *((long *)data->data));
+ case MPU_SLAVE_CONFIG_INTERNAL_REFERENCE:
+ return mpu6050_set_mldl_cfg_ref(mlsl_handle, pdata,
+ (struct mldl_cfg *)data->data);
+ break;
+
+ default:
+ return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
+ };
+
+ return 0;
+}
+
+static int mpu6050_get_config(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata,
+ struct ext_slave_config *data)
+{
+ struct mpu6050_private_data *private_data =
+ (struct mpu6050_private_data *)pdata->private_data;
+ if (!data->data)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ switch (data->key) {
+ case MPU_SLAVE_CONFIG_ODR_SUSPEND:
+ (*(unsigned long *)data->data) =
+ (unsigned long)private_data->suspend.odr;
+ break;
+ case MPU_SLAVE_CONFIG_ODR_RESUME:
+ (*(unsigned long *)data->data) =
+ (unsigned long)private_data->resume.odr;
+ break;
+ case MPU_SLAVE_CONFIG_FSR_SUSPEND:
+ (*(unsigned long *)data->data) =
+ (unsigned long)private_data->suspend.fsr;
+ break;
+ case MPU_SLAVE_CONFIG_FSR_RESUME:
+ (*(unsigned long *)data->data) =
+ (unsigned long)private_data->resume.fsr;
+ break;
+ case MPU_SLAVE_CONFIG_MOT_THS:
+ (*(unsigned long *)data->data) =
+ (unsigned long)private_data->suspend.ths;
+ break;
+ case MPU_SLAVE_CONFIG_NMOT_THS:
+ (*(unsigned long *)data->data) =
+ (unsigned long)private_data->resume.ths;
+ break;
+ case MPU_SLAVE_CONFIG_MOT_DUR:
+ (*(unsigned long *)data->data) =
+ (unsigned long)private_data->suspend.dur;
+ break;
+ case MPU_SLAVE_CONFIG_NMOT_DUR:
+ (*(unsigned long *)data->data) =
+ (unsigned long)private_data->resume.dur;
+ break;
+ case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
+ (*(unsigned long *)data->data) =
+ (unsigned long)private_data->suspend.irq_type;
+ break;
+ case MPU_SLAVE_CONFIG_IRQ_RESUME:
+ (*(unsigned long *)data->data) =
+ (unsigned long)private_data->resume.irq_type;
+ break;
+ default:
+ return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
+ };
+
+ return 0;
+}
+
+static struct ext_slave_descr mpu6050_descr = {
+ .init = mpu6050_init,
+ .exit = mpu6050_exit,
+ .suspend = mpu6050_suspend,
+ .resume = mpu6050_resume,
+ .read = mpu6050_read,
+ .config = mpu6050_config,
+ .get_config = mpu6050_get_config,
+ .name = "mpu6050",
+ .type = EXT_SLAVE_TYPE_ACCEL,
+ .id = ACCEL_ID_MPU6050,
+ .read_reg = 0x3B,
+ .read_len = 6,
+ .endian = EXT_SLAVE_BIG_ENDIAN,
+ .range = {2, 0},
+ .trigger = NULL,
+};
+
+struct ext_slave_descr *mpu6050_get_slave_descr(void)
+{
+ return &mpu6050_descr;
+}
+
+/**
+ * @}
+ */
Specifying more that one compass in the board file will result
in runtime errors.
+config MPU_SENSORS_AK8963
+ tristate "AKM ak8963"
+ help
+ This enables support for the AKM ak8963 compass
+ This support is for integration with the MPU3050 or MPU6050 gyroscope
+ device driver. Only one compass can be registered at a time.
+ Specifying more that one compass in the board file will result
+ in runtime errors.
+
config MPU_SENSORS_AK8972
tristate "AKM ak8972"
help
obj-$(CONFIG_MPU_SENSORS_AK8975) += inv_mpu_ak8975.o
inv_mpu_ak8975-objs += ak8975.o
+obj-$(CONFIG_MPU_SENSORS_AK8963) += inv_mpu_ak8963.o
+inv_mpu_ak8963-objs += ak8963.o
obj-$(CONFIG_MPU_SENSORS_AK8972) += inv_mpu_ak8972.o
inv_mpu_ak8972-objs += ak8972.o
--- /dev/null
+/*
+ $License:
+ Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+/**
+ * @addtogroup COMPASSDL
+ *
+ * @{
+ * @file ak8963.c
+ * @brief Magnetometer setup and handling methods for the AKM AK8963,
+ * AKM AK8963B, and AKM AK8963C compass devices.
+ */
+
+/* -------------------------------------------------------------------------- */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "mpu-dev.h"
+
+#include <log.h>
+#include <linux/mpu.h>
+#include "mlsl.h"
+#include "mldl_cfg.h"
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-compass"
+#include <linux/of_gpio.h>
+#include <linux/iio/consumer.h>
+
+//#include <linux/gpio.h>
+//#include <mach/gpio.h>
+//#include <plat/gpio-cfg.h>
+
+/* -------------------------------------------------------------------------- */
+#define AK8963_REG_ST1 (0x02)
+#define AK8963_REG_HXL (0x03)
+#define AK8963_REG_ST2 (0x09)
+
+#define AK8963_REG_CNTL (0x0A)
+#define AK8963_REG_ASAX (0x10)
+#define AK8963_REG_ASAY (0x11)
+#define AK8963_REG_ASAZ (0x12)
+
+//define output bit is 16bit
+#define AK8963_CNTL_MODE_POWER_DOWN (0x10)
+#define AK8963_CNTL_MODE_SINGLE_MEASUREMENT (0x11)
+#define AK8963_CNTL_MODE_FUSE_ROM_ACCESS (0x1f)
+
+/* -------------------------------------------------------------------------- */
+struct ak8963_config {
+ char asa[COMPASS_NUM_AXES]; /* axis sensitivity adjustment */
+};
+
+struct ak8963_private_data {
+ struct ak8963_config init;
+};
+
+struct ext_slave_platform_data ak8963_data;
+
+/* -------------------------------------------------------------------------- */
+static int ak8963_init(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ int result;
+ unsigned char serial_data[COMPASS_NUM_AXES];
+ printk("yemk:ak8963_init\n");
+ struct ak8963_private_data *private_data;
+ private_data = (struct ak8963_private_data *)
+ kzalloc(sizeof(struct ak8963_private_data), GFP_KERNEL);
+
+ if (!private_data)
+ return INV_ERROR_MEMORY_EXAUSTED;
+
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ AK8963_REG_CNTL,
+ AK8963_CNTL_MODE_POWER_DOWN);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ /* Wait at least 100us */
+ udelay(100);
+
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ AK8963_REG_CNTL,
+ AK8963_CNTL_MODE_FUSE_ROM_ACCESS);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ /* Wait at least 200us */
+ udelay(200);
+
+ result = inv_serial_read(mlsl_handle, pdata->address,
+ AK8963_REG_ASAX,
+ COMPASS_NUM_AXES, serial_data);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ pdata->private_data = private_data;
+
+ private_data->init.asa[0] = serial_data[0];
+ private_data->init.asa[1] = serial_data[1];
+ private_data->init.asa[2] = serial_data[2];
+
+ result = inv_serial_single_write(mlsl_handle, pdata->address,
+ AK8963_REG_CNTL,
+ AK8963_CNTL_MODE_POWER_DOWN);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ printk("yemk:ak8963_init end\n");
+ udelay(100);
+ printk(KERN_ERR "invensense: %s ok\n", __func__);
+ return INV_SUCCESS;
+}
+
+static int ak8963_exit(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ kfree(pdata->private_data);
+ return INV_SUCCESS;
+}
+
+static int ak8963_suspend(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ int result = INV_SUCCESS;
+ result =
+ inv_serial_single_write(mlsl_handle, pdata->address,
+ AK8963_REG_CNTL,
+ AK8963_CNTL_MODE_POWER_DOWN);
+ msleep(1); /* wait at least 100us */
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ return result;
+}
+
+static int ak8963_resume(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ int result = INV_SUCCESS;
+ result =
+ inv_serial_single_write(mlsl_handle, pdata->address,
+ AK8963_REG_CNTL,
+ AK8963_CNTL_MODE_SINGLE_MEASUREMENT);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ return result;
+}
+
+static int ak8963_read(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata, unsigned char *data)
+{
+ unsigned char regs[8];
+ unsigned char *stat = ®s[0];
+ unsigned char *stat2 = ®s[7];
+ int result = INV_SUCCESS;
+ int status = INV_SUCCESS;
+
+ result =
+ inv_serial_read(mlsl_handle, pdata->address, AK8963_REG_ST1,
+ 8, regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ /* Always return the data and the status registers */
+ memcpy(data, ®s[1], 6);
+ data[6] = regs[0];
+ data[7] = regs[7];
+
+ /*
+ * ST : data ready -
+ * Measurement has been completed and data is ready to be read.
+ */
+ if (*stat & 0x01)
+ status = INV_SUCCESS;
+
+ /*
+ * 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 = INV_ERROR_COMPASS_DATA_ERROR;
+ /*
+ * 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 = INV_ERROR_COMPASS_DATA_OVERFLOW;
+ /*
+ * 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 = INV_SUCCESS;
+ }
+
+ /*
+ * 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 & 0x08) != 0x00 ) {
+ result = inv_serial_single_write(
+ mlsl_handle, pdata->address,
+ AK8963_REG_CNTL, AK8963_CNTL_MODE_SINGLE_MEASUREMENT);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ }
+
+ return status;
+}
+
+static int ak8963_config(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata,
+ struct ext_slave_config *data)
+{
+ int result;
+ if (!data->data)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ switch (data->key) {
+ case MPU_SLAVE_WRITE_REGISTERS:
+ result = inv_serial_write(mlsl_handle, pdata->address,
+ data->len,
+ (unsigned char *)data->data);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ break;
+ case MPU_SLAVE_CONFIG_ODR_SUSPEND:
+ case MPU_SLAVE_CONFIG_ODR_RESUME:
+ case MPU_SLAVE_CONFIG_FSR_SUSPEND:
+ case MPU_SLAVE_CONFIG_FSR_RESUME:
+ case MPU_SLAVE_CONFIG_MOT_THS:
+ case MPU_SLAVE_CONFIG_NMOT_THS:
+ case MPU_SLAVE_CONFIG_MOT_DUR:
+ case MPU_SLAVE_CONFIG_NMOT_DUR:
+ case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
+ case MPU_SLAVE_CONFIG_IRQ_RESUME:
+ default:
+ return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
+ };
+
+ return INV_SUCCESS;
+}
+
+static int ak8963_get_config(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata,
+ struct ext_slave_config *data)
+{
+ struct ak8963_private_data *private_data = pdata->private_data;
+ int result;
+ if (!data->data)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ switch (data->key) {
+ case MPU_SLAVE_READ_REGISTERS:
+ {
+ unsigned char *serial_data =
+ (unsigned char *)data->data;
+ result =
+ inv_serial_read(mlsl_handle, pdata->address,
+ serial_data[0], data->len - 1,
+ &serial_data[1]);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ break;
+ }
+ case MPU_SLAVE_READ_SCALE:
+ {
+ unsigned char *serial_data =
+ (unsigned char *)data->data;
+ serial_data[0] = private_data->init.asa[0];
+ serial_data[1] = private_data->init.asa[1];
+ serial_data[2] = private_data->init.asa[2];
+ result = INV_SUCCESS;
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ break;
+ }
+ case MPU_SLAVE_CONFIG_ODR_SUSPEND:
+ (*(unsigned long *)data->data) = 0;
+ break;
+ case MPU_SLAVE_CONFIG_ODR_RESUME:
+ (*(unsigned long *)data->data) = 8000;
+ break;
+ case MPU_SLAVE_CONFIG_FSR_SUSPEND:
+ case MPU_SLAVE_CONFIG_FSR_RESUME:
+ case MPU_SLAVE_CONFIG_MOT_THS:
+ case MPU_SLAVE_CONFIG_NMOT_THS:
+ case MPU_SLAVE_CONFIG_MOT_DUR:
+ case MPU_SLAVE_CONFIG_NMOT_DUR:
+ case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
+ case MPU_SLAVE_CONFIG_IRQ_RESUME:
+ default:
+ return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
+ };
+
+ return INV_SUCCESS;
+}
+
+static struct ext_slave_read_trigger ak8963_read_trigger = {
+ /*.reg = */ 0x0A,
+ /*.value = */ 0x11
+};
+
+static struct ext_slave_descr ak8963_descr = {
+ .init = ak8963_init,
+ .exit = ak8963_exit,
+ .suspend = ak8963_suspend,
+ .resume = ak8963_resume,
+ .read = ak8963_read,
+ .config = ak8963_config,
+ .get_config = ak8963_get_config,
+ .name = "ak8963",
+ .type = EXT_SLAVE_TYPE_COMPASS,
+ .id = COMPASS_ID_AK8963,
+ .read_reg = 0x01,
+ .read_len = 10,
+ .endian = EXT_SLAVE_LITTLE_ENDIAN,
+ .range = {9830, 4000},
+ .trigger = &ak8963_read_trigger,
+};
+
+static
+struct ext_slave_descr *ak8963_get_slave_descr(void)
+{
+ return &ak8963_descr;
+}
+
+/* -------------------------------------------------------------------------- */
+struct ak8963_mod_private_data {
+ struct i2c_client *client;
+ struct ext_slave_platform_data *pdata;
+};
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+static int ak8963_parse_dt(struct i2c_client *client,
+ struct ext_slave_platform_data *data)
+{
+ int ret;
+ struct device_node *np = client->dev.of_node;
+ //enum of_gpio_flags gpioflags;
+ int length = 0,size = 0;
+ struct property *prop;
+ int debug = 1;
+ int i;
+ int orig_x,orig_y,orig_z;
+ u32 orientation[9];
+
+ ret = of_property_read_u32(np,"compass-bus",&data->bus);
+ if(ret!=0){
+ dev_err(&client->dev, "get compass-bus error\n");
+ return -EIO;
+ }
+
+ ret = of_property_read_u32(np,"compass-adapt_num",&data->adapt_num);
+ if(ret!=0){
+ dev_err(&client->dev, "get compass-adapt_num error\n");
+ return -EIO;
+ }
+
+ prop = of_find_property(np, "compass-orientation", &length);
+ if (!prop){
+ dev_err(&client->dev, "get compass-orientation length error\n");
+ return -EINVAL;
+ }
+
+ size = length / sizeof(int);
+
+ if((size > 0)&&(size <10)){
+ ret = of_property_read_u32_array(np, "compass-orientation",
+ orientation,
+ size);
+ if(ret<0){
+ dev_err(&client->dev, "get compass-orientation data error\n");
+ return -EINVAL;
+ }
+ }
+ else{
+ printk(" use default orientation\n");
+ }
+
+ for(i=0;i<9;i++)
+ data->orientation[i]= orientation[i];
+
+
+ ret = of_property_read_u32(np,"orientation-x",&orig_x);
+ if(ret!=0){
+ dev_err(&client->dev, "get orientation-x error\n");
+ return -EIO;
+ }
+
+ if(orig_x>0){
+ for(i=0;i<3;i++)
+ if(data->orientation[i])
+ data->orientation[i]=-1;
+ }
+
+
+ ret = of_property_read_u32(np,"orientation-y",&orig_y);
+ if(ret!=0){
+ dev_err(&client->dev, "get orientation-y error\n");
+ return -EIO;
+ }
+
+ if(orig_y>0){
+ for(i=3;i<6;i++)
+ if(data->orientation[i])
+ data->orientation[i]=-1;
+ }
+
+
+ ret = of_property_read_u32(np,"orientation-z",&orig_z);
+ if(ret!=0){
+ dev_err(&client->dev, "get orientation-z error\n");
+ return -EIO;
+ }
+
+ if(orig_z>0){
+ for(i=6;i<9;i++)
+ if(data->orientation[i])
+ data->orientation[i]=-1;
+ }
+
+
+ ret = of_property_read_u32(np,"compass-debug",&debug);
+ if(ret!=0){
+ dev_err(&client->dev, "get compass-debug error\n");
+ return -EINVAL;
+ }
+
+ if(client->addr)
+ data->address=client->addr;
+ else
+ dev_err(&client->dev, "compass-addr error\n");
+
+ if(debug){
+ printk("bus=%d,adapt_num=%d,addr=%x\n",data->bus, \
+ data->adapt_num,data->address);
+
+ for(i=0;i<size;i++)
+ printk("%d ",data->orientation[i]);
+
+ printk("\n");
+
+ }
+ return 0;
+}
+static int ak8963_mod_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ int ret=0;
+ struct ext_slave_platform_data *pdata;
+ struct ak8963_mod_private_data *private_data;
+ int result = 0;
+
+ ret = ak8963_parse_dt(client,&ak8963_data);
+ if(ret< 0)
+ printk("parse ak8963 dts failed\n");
+
+ dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
+ printk("yemk:ak8963_mod_probe\n");
+ //request gpio for COMPASS_RST
+#if 0
+ if (gpio_request(COMPASS_RST_PIN, "COMPASS_RST")) {
+ pr_err("%s: failed to request gpio for COMPASS_RST\n", __func__);
+ //return -ENODEV;
+ }
+ gpio_direction_output(COMPASS_RST_PIN, 1);
+#else
+ //if (gpio_request_one(COMPASS_RST_PIN, GPIOF_OUT_INIT_HIGH, "COMPASS_RST")) {
+ // pr_err("%s: failed to request gpio for COMPASS_RST\n", __func__);
+ //return -ENODEV;
+ //}
+#endif
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ result = -ENODEV;
+ goto out_no_free;
+ }
+
+ pdata = &ak8963_data;
+ if (!pdata) {
+ dev_err(&client->adapter->dev,
+ "Missing platform data for slave %s\n", devid->name);
+ result = -EFAULT;
+ goto out_no_free;
+ }
+
+ private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
+ if (!private_data) {
+ result = -ENOMEM;
+ goto out_no_free;
+ }
+
+ i2c_set_clientdata(client, private_data);
+ private_data->client = client;
+ private_data->pdata = pdata;
+
+ result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
+ ak8963_get_slave_descr);
+ printk(KERN_ERR "invensense: in %s, result is %d\n", __func__, result);
+ if (result) {
+ dev_err(&client->adapter->dev,
+ "Slave registration failed: %s, %d\n",
+ devid->name, result);
+ goto out_free_memory;
+ }
+ printk("yemk:ak8963_mod_probe end\n");
+ return result;
+
+out_free_memory:
+ kfree(private_data);
+out_no_free:
+ dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
+ return result;
+
+}
+
+static int ak8963_mod_remove(struct i2c_client *client)
+{
+ struct ak8963_mod_private_data *private_data =
+ i2c_get_clientdata(client);
+
+ dev_dbg(&client->adapter->dev, "%s\n", __func__);
+ inv_mpu_unregister_slave(client, private_data->pdata,
+ ak8963_get_slave_descr);
+
+ kfree(private_data);
+ return 0;
+}
+
+static const struct i2c_device_id ak8963_mod_id[] = {
+ { "ak8963", COMPASS_ID_AK8963 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ak8963_mod_id);
+
+static const struct of_device_id of_mpu_ak8963_match[] = {
+ { .compatible = "ak8963" },
+ { /* Sentinel */ }
+};
+
+static struct i2c_driver ak8963_mod_driver = {
+ .class = I2C_CLASS_HWMON,
+ .probe = ak8963_mod_probe,
+ .remove = ak8963_mod_remove,
+ .id_table = ak8963_mod_id,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ak8963_mod",
+ .of_match_table = of_mpu_ak8963_match,
+ },
+ .address_list = normal_i2c,
+};
+
+static int __init ak8963_mod_init(void)
+{
+ int res = i2c_add_driver(&ak8963_mod_driver);
+ pr_info("%s: Probe name %s\n", __func__, "ak8963_mod");
+ if (res)
+ pr_err("%s failed\n", __func__);
+ return res;
+}
+
+static void __exit ak8963_mod_exit(void)
+{
+ pr_info("%s\n", __func__);
+ i2c_del_driver(&ak8963_mod_driver);
+}
+
+module_init(ak8963_mod_init);
+module_exit(ak8963_mod_exit);
+
+MODULE_AUTHOR("Invensense Corporation");
+MODULE_DESCRIPTION("Driver to integrate AK8963 sensor with the MPU");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ak8963_mod");
+
+/**
+ * @}
+ */
*/
/* -------------------------------------------------------------------------- */
-#define DEBUG
#include <linux/i2c.h>
#include <linux/module.h>
struct ak8975_config init;
};
+struct ext_slave_platform_data ak8975_data;
+
/* -------------------------------------------------------------------------- */
static int ak8975_init(void *mlsl_handle,
struct ext_slave_descr *slave,
if (!private_data)
return INV_ERROR_MEMORY_EXAUSTED;
-#if 0
+
result = inv_serial_single_write(mlsl_handle, pdata->address,
AK8975_REG_CNTL,
AK8975_CNTL_MODE_POWER_DOWN);
LOG_RESULT_LOCATION(result);
return result;
}
-#endif
+
/* Wait at least 200us */
udelay(200);
private_data->init.asa[0] = serial_data[0];
private_data->init.asa[1] = serial_data[1];
private_data->init.asa[2] = serial_data[2];
-#if 0
+
result = inv_serial_single_write(mlsl_handle, pdata->address,
AK8975_REG_CNTL,
AK8975_CNTL_MODE_POWER_DOWN);
LOG_RESULT_LOCATION(result);
return result;
}
-#endif
+
udelay(100);
return INV_SUCCESS;
}
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static int ak8975_parse_dt(struct i2c_client *client,
+ struct ext_slave_platform_data *data)
+{
+ int ret;
+ struct device_node *np = client->dev.of_node;
+ //enum of_gpio_flags gpioflags;
+ int length = 0,size = 0;
+ struct property *prop;
+ int debug = 1;
+ int i;
+ int orig_x,orig_y,orig_z;
+ u32 orientation[9];
+
+ ret = of_property_read_u32(np,"compass-bus",&data->bus);
+ if(ret!=0){
+ dev_err(&client->dev, "get compass-bus error\n");
+ return -EIO;
+ }
+
+ ret = of_property_read_u32(np,"compass-adapt_num",&data->adapt_num);
+ if(ret!=0){
+ dev_err(&client->dev, "get compass-adapt_num error\n");
+ return -EIO;
+ }
+
+ prop = of_find_property(np, "compass-orientation", &length);
+ if (!prop){
+ dev_err(&client->dev, "get compass-orientation length error\n");
+ return -EINVAL;
+ }
+
+ size = length / sizeof(int);
+
+ if((size > 0)&&(size <10)){
+ ret = of_property_read_u32_array(np, "compass-orientation",
+ orientation,
+ size);
+ if(ret<0){
+ dev_err(&client->dev, "get compass-orientation data error\n");
+ return -EINVAL;
+ }
+ }
+ else{
+ printk(" use default orientation\n");
+ }
+
+ for(i=0;i<9;i++)
+ data->orientation[i]= orientation[i];
+
+
+ ret = of_property_read_u32(np,"orientation-x",&orig_x);
+ if(ret!=0){
+ dev_err(&client->dev, "get orientation-x error\n");
+ return -EIO;
+ }
+
+ if(orig_x>0){
+ for(i=0;i<3;i++)
+ if(data->orientation[i])
+ data->orientation[i]=-1;
+ }
+
+
+ ret = of_property_read_u32(np,"orientation-y",&orig_y);
+ if(ret!=0){
+ dev_err(&client->dev, "get orientation-y error\n");
+ return -EIO;
+ }
+
+ if(orig_y>0){
+ for(i=3;i<6;i++)
+ if(data->orientation[i])
+ data->orientation[i]=-1;
+ }
+
+
+ ret = of_property_read_u32(np,"orientation-z",&orig_z);
+ if(ret!=0){
+ dev_err(&client->dev, "get orientation-z error\n");
+ return -EIO;
+ }
+
+ if(orig_z>0){
+ for(i=6;i<9;i++)
+ if(data->orientation[i])
+ data->orientation[i]=-1;
+ }
+
+
+ ret = of_property_read_u32(np,"compass-debug",&debug);
+ if(ret!=0){
+ dev_err(&client->dev, "get compass-debug error\n");
+ return -EINVAL;
+ }
+
+ if(client->addr)
+ data->address=client->addr;
+ else
+ dev_err(&client->dev, "compass-addr error\n");
+
+ if(debug){
+ printk("bus=%d,adapt_num=%d,addr=%x\n",data->bus, \
+ data->adapt_num,data->address);
+
+ for(i=0;i<size;i++)
+ printk("%d ",data->orientation[i]);
+
+ printk("\n");
+
+ }
+ return 0;
+}
+
static int ak8975_mod_probe(struct i2c_client *client,
const struct i2c_device_id *devid)
{
struct ext_slave_platform_data *pdata;
struct ak8975_mod_private_data *private_data;
int result = 0;
+ int ret;
- dev_info(&client->adapter->dev, "%s: %s,0x%x\n", __func__, devid->name,(unsigned int)client);
+
+ ret = ak8975_parse_dt(client,&ak8975_data);
+ if(ret< 0)
+ printk("parse ak8975 dts failed\n");
+ dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
result = -ENODEV;
goto out_no_free;
}
- pdata = client->dev.platform_data;
+ pdata = &ak8975_data;;
if (!pdata) {
dev_err(&client->adapter->dev,
"Missing platform data for slave %s\n", devid->name);
MODULE_DEVICE_TABLE(i2c, ak8975_mod_id);
+static const struct of_device_id of_mpu_ak8975_match[] = {
+ { .compatible = "ak8975" },
+ { /* Sentinel */ }
+};
+
static struct i2c_driver ak8975_mod_driver = {
.class = I2C_CLASS_HWMON,
.probe = ak8975_mod_probe,
.driver = {
.owner = THIS_MODULE,
.name = "ak8975_mod",
+ .of_match_table = of_mpu_ak8975_match,
},
.address_list = normal_i2c,
};
#include "mldl_cfg.h"
#include <linux/mpu.h>
-#include "mpu3050.h"
+#include "mpu6050b1.h"
#include "mlsl.h"
#include "mldl_print_cfg.h"
/* -------------------------------------------------------------------------- */
-#define SLEEP 1
-#define WAKE_UP 0
+#define SLEEP 0
+#define WAKE_UP 7
#define RESET 1
#define STANDBY 1
return result;
}
-
-
-static int mpu3050_set_i2c_bypass(struct mldl_cfg *mldl_cfg,
- void *mlsl_handle, unsigned char enable)
+/**
+ * @brief enables/disables the I2C bypass to an external device
+ * connected to MPU's secondary I2C bus.
+ * @param enable
+ * Non-zero to enable pass through.
+ * @return INV_SUCCESS if successful, a non-zero error code otherwise.
+ */
+static int mpu6050b1_set_i2c_bypass(struct mldl_cfg *mldl_cfg,
+ void *mlsl_handle, unsigned char enable)
{
- unsigned char b;
+ unsigned char reg;
int result;
unsigned char status = mldl_cfg->inv_mpu_state->status;
-
if ((status & MPU_GYRO_IS_BYPASSED && enable) ||
(!(status & MPU_GYRO_IS_BYPASSED) && !enable))
return INV_SUCCESS;
/*---- get current 'USER_CTRL' into b ----*/
- result = inv_serial_read(
- mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_USER_CTRL, 1, &b);
+ result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+ MPUREG_USER_CTRL, 1, ®);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
- b &= ~BIT_AUX_IF_EN;
-
if (!enable) {
+ /* setting int_config with the property flag BIT_BYPASS_EN
+ should be done by the setup functions */
result = inv_serial_single_write(
mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_USER_CTRL,
- (b | BIT_AUX_IF_EN));
- if (result) {
- LOG_RESULT_LOCATION(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_serial_single_write(
- mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_AUX_SLV_ADDR, 0x7F);
- if (result) {
- LOG_RESULT_LOCATION(result);
- return result;
- }
- /*
- * 2) wait enough time for a nack to occur, then go into
- * bypass mode:
- */
- msleep(2);
- result = inv_serial_single_write(
- mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_USER_CTRL, (b));
- if (result) {
- LOG_RESULT_LOCATION(result);
- return result;
+ MPUREG_INT_PIN_CFG,
+ (mldl_cfg->pdata->int_config & ~(BIT_BYPASS_EN)));
+ if (!(reg & BIT_I2C_MST_EN)) {
+ result =
+ inv_serial_single_write(
+ mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+ MPUREG_USER_CTRL,
+ (reg | BIT_I2C_MST_EN));
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
}
- /*
- * 3) wait for up to one MPU cycle then restore the slave
- * address
- */
- msleep(inv_mpu_get_sampling_period_us(mldl_cfg->mpu_gyro_cfg)
- / 1000);
- result = inv_serial_single_write(
- mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_AUX_SLV_ADDR,
- mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL]
- ->address);
- if (result) {
- LOG_RESULT_LOCATION(result);
- return result;
+ } else if (enable) {
+ if (reg & BIT_AUX_IF_EN) {
+ result =
+ inv_serial_single_write(
+ mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+ MPUREG_USER_CTRL,
+ (reg & (~BIT_I2C_MST_EN)));
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ /*****************************************
+ * To avoid hanging the bus we must sleep until all
+ * slave transactions have been completed.
+ * 24 bytes max slave reads
+ * +1 byte possible extra write
+ * +4 max slave address
+ * ---
+ * 33 Maximum bytes
+ * x9 Approximate bits per byte
+ * ---
+ * 297 bits.
+ * 2.97 ms minimum @ 100kbps
+ * 0.75 ms minimum @ 400kbps.
+ *****************************************/
+ msleep(3);
}
-
- /*
- * 4) reset the ime interface
- */
-
result = inv_serial_single_write(
mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_USER_CTRL,
- (b | BIT_AUX_IF_RST));
+ MPUREG_INT_PIN_CFG,
+ (mldl_cfg->pdata->int_config | BIT_BYPASS_EN));
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
- msleep(2);
}
if (enable)
mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_BYPASSED;
}
+
+
/**
* @brief enables/disables the I2C bypass to an external device
* connected to MPU's secondary I2C bus.
static int mpu_set_i2c_bypass(struct mldl_cfg *mldl_cfg, void *mlsl_handle,
unsigned char enable)
{
- return mpu3050_set_i2c_bypass(mldl_cfg, mlsl_handle, enable);
+ return mpu6050b1_set_i2c_bypass(mldl_cfg, mlsl_handle, enable);
}
/* NOTE : when not indicated, product revision
is considered an 'npp'; non production part */
+/* produces an unique identifier for each device based on the
+ combination of product version and product revision */
struct prod_rev_map_t {
+ unsigned short mpl_product_key;
unsigned char silicon_rev;
unsigned short gyro_trim;
+ unsigned short accel_trim;
};
-#define OLDEST_PROD_REV_SUPPORTED 11
+/* NOTE: product entries are in chronological order */
static struct prod_rev_map_t prod_rev_map[] = {
- {0, 0},
- {MPU_SILICON_REV_A4, 131}, /* 1 A? OBSOLETED */
- {MPU_SILICON_REV_A4, 131}, /* 2 | */
- {MPU_SILICON_REV_A4, 131}, /* 3 | */
- {MPU_SILICON_REV_A4, 131}, /* 4 | */
- {MPU_SILICON_REV_A4, 131}, /* 5 | */
- {MPU_SILICON_REV_A4, 131}, /* 6 | */
- {MPU_SILICON_REV_A4, 131}, /* 7 | */
- {MPU_SILICON_REV_A4, 131}, /* 8 | */
- {MPU_SILICON_REV_A4, 131}, /* 9 | */
- {MPU_SILICON_REV_A4, 131}, /* 10 V */
- {MPU_SILICON_REV_B1, 131}, /* 11 B1 */
- {MPU_SILICON_REV_B1, 131}, /* 12 | */
- {MPU_SILICON_REV_B1, 131}, /* 13 | */
- {MPU_SILICON_REV_B1, 131}, /* 14 V */
- {MPU_SILICON_REV_B4, 131}, /* 15 B4 */
- {MPU_SILICON_REV_B4, 131}, /* 16 | */
- {MPU_SILICON_REV_B4, 131}, /* 17 | */
- {MPU_SILICON_REV_B4, 131}, /* 18 | */
- {MPU_SILICON_REV_B4, 115}, /* 19 | */
- {MPU_SILICON_REV_B4, 115}, /* 20 V */
- {MPU_SILICON_REV_B6, 131}, /* 21 B6 (B6/A9) */
- {MPU_SILICON_REV_B4, 115}, /* 22 B4 (B7/A10) */
- {MPU_SILICON_REV_B6, 131}, /* 23 B6 (npp) */
- {MPU_SILICON_REV_B6, 131}, /* 24 | (npp) */
- {MPU_SILICON_REV_B6, 131}, /* 25 V (npp) */
- {MPU_SILICON_REV_B6, 131}, /* 26 (B6/A11) */
- {MPU_SILICON_REV_B6, 131}, /* 27 (B6/A11) */
- {MPU_SILICON_REV_B6, 131}, /* 28 (B6/A11) */
- {MPU_SILICON_REV_B6, 131}, /* 29 (B6/A11) */
- {MPU_SILICON_REV_B6, 131}, /* 30 (B6/A11) */
- {MPU_SILICON_REV_B6, 131}, /* 31 (B6/A11) */
- {MPU_SILICON_REV_B6, 131}, /* 32 (B6/A11) */
+ /* prod_ver = 0 */
+ {MPL_PROD_KEY(0, 1), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 2), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 3), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 4), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 5), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 6), MPU_SILICON_REV_A2, 131, 16384}, /* (A2/C2-1) */
+ /* prod_ver = 1, forced to 0 for MPU6050 A2 */
+ {MPL_PROD_KEY(0, 7), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 8), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 9), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 10), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 11), MPU_SILICON_REV_A2, 131, 16384}, /* (A2/D2-1) */
+ {MPL_PROD_KEY(0, 12), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 13), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 14), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 15), MPU_SILICON_REV_A2, 131, 16384},
+ {MPL_PROD_KEY(0, 27), MPU_SILICON_REV_A2, 131, 16384}, /* (A2/D4) */
+ /* prod_ver = 1 */
+ {MPL_PROD_KEY(1, 16), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-1) */
+ {MPL_PROD_KEY(1, 17), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-2) */
+ {MPL_PROD_KEY(1, 18), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-3) */
+ {MPL_PROD_KEY(1, 19), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-4) */
+ {MPL_PROD_KEY(1, 20), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-5) */
+ {MPL_PROD_KEY(1, 28), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D4) */
+ {MPL_PROD_KEY(1, 1), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-1) */
+ {MPL_PROD_KEY(1, 2), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-2) */
+ {MPL_PROD_KEY(1, 3), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-3) */
+ {MPL_PROD_KEY(1, 4), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-4) */
+ {MPL_PROD_KEY(1, 5), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-5) */
+ {MPL_PROD_KEY(1, 6), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-6) */
+ /* prod_ver = 2 */
+ {MPL_PROD_KEY(2, 7), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-1) */
+ {MPL_PROD_KEY(2, 8), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-2) */
+ {MPL_PROD_KEY(2, 9), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-3) */
+ {MPL_PROD_KEY(2, 10), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-4) */
+ {MPL_PROD_KEY(2, 11), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-5) */
+ {MPL_PROD_KEY(2, 12), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-6) */
+ {MPL_PROD_KEY(2, 29), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/D4) */
+ /* prod_ver = 3 */
+ {MPL_PROD_KEY(3, 30), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E2) */
+ /* prod_ver = 4 */
+ {MPL_PROD_KEY(4, 31), MPU_SILICON_REV_B1, 131, 8192}, /* (B2/F1) */
+ {MPL_PROD_KEY(4, 1), MPU_SILICON_REV_B1, 131, 8192}, /* (B3/F1) */
+ {MPL_PROD_KEY(4, 3), MPU_SILICON_REV_B1, 131, 8192}, /* (B4/F1) */
+ /* prod_ver = 5 */
+ {MPL_PROD_KEY(5, 3), MPU_SILICON_REV_B1, 131, 16384}, /* (B4/F1) */
+ /* prod_ver = 6 */
+ {MPL_PROD_KEY(6, 19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2) */
+ /* prod_ver = 7 */
+ {MPL_PROD_KEY(7, 19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2) */
+ /* prod_ver = 8 */
+ {MPL_PROD_KEY(8, 19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2) */
+ /* prod_ver = 9 */
+ {MPL_PROD_KEY(9, 19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2) */
+ /* prod_ver = 10 */
+ {MPL_PROD_KEY(10, 19), MPU_SILICON_REV_B1, 131, 16384} /* (B5/E2) */
+
};
+/*
+ List of product software revisions
+
+ NOTE :
+ software revision 0 falls back to the old detection method
+ based off the product version and product revision per the
+ table above
+*/
+static struct prod_rev_map_t sw_rev_map[] = {
+ {0, 0, 0, 0},
+ {1, MPU_SILICON_REV_B1, 131, 8192}, /* rev C */
+ {2, MPU_SILICON_REV_B1, 131, 16384} /* rev D */
+ };
+
/**
* @internal
- * @brief Get the silicon revision ID from OTP for MPU3050.
- * The silicon revision number is in read from OTP bank 0,
- * ADDR6[7:2]. The corresponding ID is retrieved by lookup
- * in a map.
+ * @brief Inverse lookup of the index of an MPL product key .
+ * @param key
+ * the MPL product indentifier also referred to as 'key'.
+ * @return the index position of the key in the array, -1 if not found.
+ */
+short index_of_key(unsigned short key)
+{
+ int i;
+ for (i = 0; i < NUM_OF_PROD_REVS; i++)
+ if (prod_rev_map[i].mpl_product_key == key)
+ return (short)i;
+ return -1;
+}
+
+/**
+ * @internal
+ * @brief Get the product revision and version for MPU6050 and
+ * extract all per-part specific information.
+ * The product version number is read from the PRODUCT_ID register in
+ * user space register map.
+ * The product revision number is in read from OTP bank 0, ADDR6[7:2].
+ * These 2 numbers, combined, provide an unique key to be used to
+ * retrieve some per-device information such as the silicon revision
+ * and the gyro and accel sensitivity trim values.
*
* @param mldl_cfg
* a pointer to the mldl config data structure.
*
* @return 0 on success, a non-zero error code otherwise.
*/
-static int inv_get_silicon_rev_mpu3050(
+static int inv_get_silicon_rev_mpu6050(
struct mldl_cfg *mldl_cfg, void *mlsl_handle)
{
- int result;
- unsigned char index = 0x00;
+ unsigned char prod_ver, prod_rev;
+ struct prod_rev_map_t *p_rev;
+ unsigned sw_rev;
+ unsigned short key;
unsigned char bank =
(BIT_PRFTCH_EN | BIT_CFG_USER_BANK | MPU_MEM_OTP_BANK_0);
unsigned short mem_addr = ((bank << 8) | 0x06);
+ short index;
+ unsigned char regs[5];
+ int result;
struct mpu_chip_info *mpu_chip_info = mldl_cfg->mpu_chip_info;
+ /* get the product version */
result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_PRODUCT_ID, 1,
- &mpu_chip_info->product_id);
+ MPUREG_PRODUCT_ID, 1, &prod_ver);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
+ prod_ver &= 0xF;
- result = inv_serial_read_mem(
- mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- mem_addr, 1, &index);
+ /* get the product revision */
+ result = inv_serial_read_mem(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+ mem_addr, 1, &prod_rev);
+ MPL_LOGE("prod_ver %d , prod_rev %d\n", prod_ver, prod_rev);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
- index >>= 2;
+ prod_rev >>= 2;
/* clean the prefetch and cfg user bank bits */
result = inv_serial_single_write(
return result;
}
- if (OLDEST_PROD_REV_SUPPORTED <= index && NUM_OF_PROD_REVS >= index) {
- mpu_chip_info->silicon_revision = prod_rev_map[index].silicon_rev;
- mpu_chip_info->gyro_sens_trim = prod_rev_map[index].gyro_trim;
- }
- else
- {
- mpu_chip_info->silicon_revision = MPU_SILICON_REV_B6;
- mpu_chip_info->gyro_sens_trim = 131;
+ /* get the software-product version */
+ result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+ MPUREG_XA_OFFS_L, 5, regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
}
+ sw_rev = (regs[4] & 0x01) << 2 | /* 0x0b, bit 0 */
+ (regs[2] & 0x01) << 1 | /* 0x09, bit 0 */
+ (regs[0] & 0x01); /* 0x07, bit 0 */
+
+ /* if 0, use the product key to determine the type of part */
+ if (sw_rev == 0) {
+ key = MPL_PROD_KEY(prod_ver, prod_rev);
+ if (key == 0) {
+ MPL_LOGE("Product id read as 0 "
+ "indicates device is either "
+ "incompatible or an MPU3050\n");
+ return INV_ERROR_INVALID_MODULE;
+ }
+ index = index_of_key(key);
+ if (index == -1 || index >= NUM_OF_PROD_REVS) {
+ MPL_LOGE("Unsupported product key %d in MPL\n", key);
+ return INV_ERROR_INVALID_MODULE;
+ }
+ /* check MPL is compiled for this device */
+ if (prod_rev_map[index].silicon_rev != MPU_SILICON_REV_B1) {
+ MPL_LOGE("MPL compiled for MPU6050B1 support "
+ "but device is not MPU6050B1 (%d)\n", key);
+ return INV_ERROR_INVALID_MODULE;
+ }
+ p_rev = &prod_rev_map[index];
+
+ /* if valid, use the software product key */
+ } else if (sw_rev < ARRAY_SIZE(sw_rev_map)) {
+ p_rev = &sw_rev_map[sw_rev];
- mpu_chip_info->product_revision = index;
- if (mpu_chip_info->gyro_sens_trim == 0) {
- MPL_LOGE("gyro sensitivity trim is 0"
- " - unsupported non production part.\n");
+ } else {
+ MPL_LOGE("Software revision key is outside of known "
+ "range [0..%d] : %d\n", ARRAY_SIZE(sw_rev_map));
return INV_ERROR_INVALID_MODULE;
}
+ mpu_chip_info->product_id = prod_ver;
+ mpu_chip_info->product_revision = prod_rev;
+ mpu_chip_info->silicon_revision = p_rev->silicon_rev;
+ mpu_chip_info->gyro_sens_trim = p_rev->gyro_trim;
+ mpu_chip_info->accel_sens_trim = p_rev->accel_trim;
+
return result;
}
-#define inv_get_silicon_rev inv_get_silicon_rev_mpu3050
+#define inv_get_silicon_rev inv_get_silicon_rev_mpu6050
/**
int result;
unsigned char regval;
- unsigned char reg;
- unsigned char mask;
-
- if (0 == mldl_cfg->mpu_chip_info->silicon_revision)
- return INV_ERROR_INVALID_PARAMETER;
-
- /*-- on parts before B6 the VDDIO bit is bit 7 of ACCEL_BURST_ADDR --
- NOTE: this is incompatible with ST accelerometers where the VDDIO
- bit MUST be set to enable ST's internal logic to autoincrement
- the register address on burst reads --*/
- if ((mldl_cfg->mpu_chip_info->silicon_revision & 0xf)
- < MPU_SILICON_REV_B6) {
- reg = MPUREG_ACCEL_BURST_ADDR;
- mask = 0x80;
- } else {
- /*-- on B6 parts the VDDIO bit was moved to FIFO_EN2 =>
- the mask is always 0x04 --*/
- reg = MPUREG_FIFO_EN2;
- mask = 0x04;
- }
-
result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- reg, 1, ®val);
+ MPUREG_YG_OFFS_TC, 1, ®val);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
-
if (enable)
- regval |= mask;
- else
- regval &= ~mask;
+ regval |= BIT_I2C_MST_VDDIO;
result = inv_serial_single_write(
- mlsl_handle, mldl_cfg->mpu_chip_info->addr, reg, regval);
+ mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+ MPUREG_YG_OFFS_TC, regval);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
- return result;
return INV_SUCCESS;
}
/**
* @internal
- * @brief This function controls the power management on the MPU device.
- * The entire chip can be put to low power sleep mode, or individual
- * gyros can be turned on/off.
+ * @brief MPU6050 B1 power management functions.
+ * @param mldl_cfg
+ * a pointer to the internal mldl_cfg data structure.
+ * @param mlsl_handle
+ * a file handle to the serial device used to communicate
+ * with the MPU6050 B1 device.
+ * @param reset
+ * 1 to reset hardware.
+ * @param sensors
+ * Bitfield of sensors to leave on
*
- * Putting the device into sleep mode depending upon the changing needs
- * of the associated applications is a recommended method for reducing
- * power consuption. It is a safe opearation in that sleep/wake up of
- * gyros while running will not result in any interruption of data.
- *
- * Although it is entirely allowed to put the device into full sleep
- * while running the DMP, it is not recomended because it will disrupt
- * the ongoing calculations carried on inside the DMP and consequently
- * the sensor fusion algorithm. Furthermore, while in sleep mode
- * read & write operation from the app processor on both registers and
- * memory are disabled and can only regained by restoring the MPU in
- * normal power mode.
- * Disabling any of the gyro axis will reduce the associated power
- * consuption from the PLL but will not stop the DMP from running
- * state.
- *
- * @param reset
- * Non-zero to reset the device. Note that this setting
- * is volatile and the corresponding register bit will
- * clear itself right after being applied.
- * @param sleep
- * Non-zero to put device into full sleep.
- * @param disable_gx
- * Non-zero to disable gyro X.
- * @param disable_gy
- * Non-zero to disable gyro Y.
- * @param disable_gz
- * Non-zero to disable gyro Z.
- *
- * @return INV_SUCCESS if successfull; a non-zero error code otherwise.
+ * @return 0 on success, a non-zero error code on error.
*/
-static int mpu3050_pwr_mgmt(struct mldl_cfg *mldl_cfg,
- void *mlsl_handle,
- unsigned char reset,
- unsigned char sleep,
- unsigned char disable_gx,
- unsigned char disable_gy,
- unsigned char disable_gz)
+static int mpu60xx_pwr_mgmt(struct mldl_cfg *mldl_cfg,
+ void *mlsl_handle,
+ unsigned int reset, unsigned long sensors)
{
- unsigned char b;
+ unsigned char pwr_mgmt[2];
+ unsigned char pwr_mgmt_prev[2];
int result;
+ int sleep = !(sensors & (INV_THREE_AXIS_GYRO | INV_THREE_AXIS_ACCEL
+ | INV_DMP_PROCESSOR));
- result =
- inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_PWR_MGM, 1, &b);
- if (result) {
- LOG_RESULT_LOCATION(result);
- return result;
- }
-
- /* If we are awake, we need to put it in bypass before resetting */
- if ((!(b & BIT_SLEEP)) && reset)
- result = mpu_set_i2c_bypass(mldl_cfg, mlsl_handle, 1);
-
- /* Reset if requested */
if (reset) {
- MPL_LOGV("Reset MPU3050\n");
+ MPL_LOGI("Reset MPU6050 B1\n");
result = inv_serial_single_write(
mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_PWR_MGM, b | BIT_H_RESET);
- if (result) {
- LOG_RESULT_LOCATION(result);
- return result;
- }
- msleep(5);
- /* Some chips are awake after reset and some are asleep,
- * check the status */
- result = inv_serial_read(
- mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_PWR_MGM, 1, &b);
+ MPUREG_PWR_MGMT_1, BIT_H_RESET);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
+ mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_BYPASSED;
+ msleep(15);
}
- /* Update the suspended state just in case we return early */
- if (b & BIT_SLEEP) {
- mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_SUSPENDED;
- mldl_cfg->inv_mpu_state->status |= MPU_DEVICE_IS_SUSPENDED;
- } else {
- mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_SUSPENDED;
- mldl_cfg->inv_mpu_state->status &= ~MPU_DEVICE_IS_SUSPENDED;
- }
-
- /* if power status match requested, nothing else's left to do */
- if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) ==
- (((sleep != 0) * BIT_SLEEP) |
- ((disable_gx != 0) * BIT_STBY_XG) |
- ((disable_gy != 0) * BIT_STBY_YG) |
- ((disable_gz != 0) * BIT_STBY_ZG))) {
- return INV_SUCCESS;
+ /* NOTE : reading both PWR_MGMT_1 and PWR_MGMT_2 for efficiency because
+ they are accessible even when the device is powered off */
+ result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+ MPUREG_PWR_MGMT_1, 2, pwr_mgmt_prev);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
}
- /*
- * This specific transition between states needs to be reinterpreted:
- * (1,1,1,1) -> (0,1,1,1) has to become
- * (1,1,1,1) -> (1,0,0,0) -> (0,1,1,1)
- * where
- * (1,1,1,1) is (sleep=1,disable_gx=1,disable_gy=1,disable_gz=1)
- */
- if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) ==
- (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)
- && ((!sleep) && disable_gx && disable_gy && disable_gz)) {
- result = mpu3050_pwr_mgmt(mldl_cfg, mlsl_handle, 0, 1, 0, 0, 0);
- if (result)
- return result;
- b |= BIT_SLEEP;
- b &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG);
- }
+ pwr_mgmt[0] = pwr_mgmt_prev[0];
+ pwr_mgmt[1] = pwr_mgmt_prev[1];
- if ((b & BIT_SLEEP) != ((sleep != 0) * BIT_SLEEP)) {
- if (sleep) {
- result = mpu_set_i2c_bypass(mldl_cfg, mlsl_handle, 1);
- if (result) {
- LOG_RESULT_LOCATION(result);
- return result;
- }
- b |= BIT_SLEEP;
- result =
- inv_serial_single_write(
- mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_PWR_MGM, b);
- if (result) {
- LOG_RESULT_LOCATION(result);
- return result;
- }
- mldl_cfg->inv_mpu_state->status |=
- MPU_GYRO_IS_SUSPENDED;
- mldl_cfg->inv_mpu_state->status |=
- MPU_DEVICE_IS_SUSPENDED;
- } else {
- b &= ~BIT_SLEEP;
- result =
- inv_serial_single_write(
- mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_PWR_MGM, b);
- if (result) {
- LOG_RESULT_LOCATION(result);
- return result;
- }
- mldl_cfg->inv_mpu_state->status &=
- ~MPU_GYRO_IS_SUSPENDED;
- mldl_cfg->inv_mpu_state->status &=
- ~MPU_DEVICE_IS_SUSPENDED;
- msleep(5);
- }
+ if (sleep) {
+ mldl_cfg->inv_mpu_state->status |= MPU_DEVICE_IS_SUSPENDED;
+ pwr_mgmt[0] |= BIT_SLEEP;
+ } else {
+ mldl_cfg->inv_mpu_state->status &= ~MPU_DEVICE_IS_SUSPENDED;
+ pwr_mgmt[0] &= ~BIT_SLEEP;
}
- /*---
- WORKAROUND FOR PUTTING GYRO AXIS in STAND-BY MODE
- 1) put one axis at a time in stand-by
- ---*/
- if ((b & BIT_STBY_XG) != ((disable_gx != 0) * BIT_STBY_XG)) {
- b ^= BIT_STBY_XG;
+ if (pwr_mgmt[0] != pwr_mgmt_prev[0]) {
result = inv_serial_single_write(
mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_PWR_MGM, b);
+ MPUREG_PWR_MGMT_1, pwr_mgmt[0]);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
}
- if ((b & BIT_STBY_YG) != ((disable_gy != 0) * BIT_STBY_YG)) {
- b ^= BIT_STBY_YG;
+
+ pwr_mgmt[1] &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG);
+ if (!(sensors & INV_X_GYRO))
+ pwr_mgmt[1] |= BIT_STBY_XG;
+ if (!(sensors & INV_Y_GYRO))
+ pwr_mgmt[1] |= BIT_STBY_YG;
+ if (!(sensors & INV_Z_GYRO))
+ pwr_mgmt[1] |= BIT_STBY_ZG;
+
+ if (pwr_mgmt[1] != pwr_mgmt_prev[1]) {
result = inv_serial_single_write(
mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_PWR_MGM, b);
+ MPUREG_PWR_MGMT_2, pwr_mgmt[1]);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
}
- if ((b & BIT_STBY_ZG) != ((disable_gz != 0) * BIT_STBY_ZG)) {
- b ^= BIT_STBY_ZG;
- result = inv_serial_single_write(
- mlsl_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_PWR_MGM, b);
- if (result) {
- LOG_RESULT_LOCATION(result);
- return result;
- }
+
+ if ((pwr_mgmt[1] & (BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) ==
+ (BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) {
+ mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_SUSPENDED;
+ } else {
+ mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_SUSPENDED;
}
return INV_SUCCESS;
LOG_RESULT_LOCATION(result);
return result;
}
- /* TODO : workarounds to be determined and implemented */
+ /* ERRATA:
+ workaroud to switch from any MPU_CLK_SEL_PLLGYROx to
+ MPU_CLK_SEL_INTERNAL and XGyro is powered up:
+ 1) Select INT_OSC
+ 2) PD XGyro
+ 3) PU XGyro
+ */
+ if ((cur_clk_src == MPU_CLK_SEL_PLLGYROX
+ || cur_clk_src == MPU_CLK_SEL_PLLGYROY
+ || cur_clk_src == MPU_CLK_SEL_PLLGYROZ)
+ && mldl_cfg->mpu_gyro_cfg->clk_src == MPU_CLK_SEL_INTERNAL
+ && mldl_cfg->inv_mpu_cfg->requested_sensors & INV_X_GYRO) {
+ unsigned char first_result = INV_SUCCESS;
+ mldl_cfg->inv_mpu_cfg->requested_sensors &= ~INV_X_GYRO;
+ result = mpu60xx_pwr_mgmt(
+ mldl_cfg, gyro_handle,
+ false, mldl_cfg->inv_mpu_cfg->requested_sensors);
+ ERROR_CHECK_FIRST(first_result, result);
+ mldl_cfg->inv_mpu_cfg->requested_sensors |= INV_X_GYRO;
+ result = mpu60xx_pwr_mgmt(
+ mldl_cfg, gyro_handle,
+ false, mldl_cfg->inv_mpu_cfg->requested_sensors);
+ ERROR_CHECK_FIRST(first_result, result);
+ result = first_result;
+ }
return result;
}
*
* returns INV_SUCCESS or non-zero error code
*/
-static int mpu_set_slave_mpu3050(struct mldl_cfg *mldl_cfg,
+
+static int mpu_set_slave_mpu60xx(struct mldl_cfg *mldl_cfg,
void *gyro_handle,
struct ext_slave_descr *slave,
struct ext_slave_platform_data *slave_pdata,
{
int result;
unsigned char reg;
+ /* Slave values */
unsigned char slave_reg;
unsigned char slave_len;
unsigned char slave_endian;
unsigned char slave_address;
-
- if (slave_id != EXT_SLAVE_TYPE_ACCEL)
- return 0;
-
- result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, true);
+ /* Which MPU6050 registers to use */
+ unsigned char addr_reg;
+ unsigned char reg_reg;
+ unsigned char ctrl_reg;
+ /* Which MPU6050 registers to use for the trigger */
+ unsigned char addr_trig_reg;
+ unsigned char reg_trig_reg;
+ unsigned char ctrl_trig_reg;
+
+ unsigned char bits_slave_delay = 0;
+ /* Divide down rate for the Slave, from the mpu rate */
+ unsigned char d0_trig_reg;
+ unsigned char delay_ctrl_orig;
+ unsigned char delay_ctrl;
+ long divider;
if (NULL == slave || NULL == slave_pdata) {
slave_reg = 0;
slave_len = 0;
slave_endian = 0;
slave_address = 0;
- mldl_cfg->inv_mpu_state->i2c_slaves_enabled = 0;
} else {
slave_reg = slave->read_reg;
slave_len = slave->read_len;
slave_endian = slave->endian;
slave_address = slave_pdata->address;
- mldl_cfg->inv_mpu_state->i2c_slaves_enabled = 1;
- }
+ slave_address |= BIT_I2C_READ;
+ }
+
+ switch (slave_id) {
+ case EXT_SLAVE_TYPE_ACCEL:
+ addr_reg = MPUREG_I2C_SLV1_ADDR;
+ reg_reg = MPUREG_I2C_SLV1_REG;
+ ctrl_reg = MPUREG_I2C_SLV1_CTRL;
+ addr_trig_reg = 0;
+ reg_trig_reg = 0;
+ ctrl_trig_reg = 0;
+ bits_slave_delay = BIT_SLV1_DLY_EN;
+ break;
+ case EXT_SLAVE_TYPE_COMPASS:
+ addr_reg = MPUREG_I2C_SLV0_ADDR;
+ reg_reg = MPUREG_I2C_SLV0_REG;
+ ctrl_reg = MPUREG_I2C_SLV0_CTRL;
+ addr_trig_reg = MPUREG_I2C_SLV2_ADDR;
+ reg_trig_reg = MPUREG_I2C_SLV2_REG;
+ ctrl_trig_reg = MPUREG_I2C_SLV2_CTRL;
+ d0_trig_reg = MPUREG_I2C_SLV2_DO;
+ bits_slave_delay = BIT_SLV2_DLY_EN | BIT_SLV0_DLY_EN;
+ break;
+ case EXT_SLAVE_TYPE_PRESSURE:
+ addr_reg = MPUREG_I2C_SLV3_ADDR;
+ reg_reg = MPUREG_I2C_SLV3_REG;
+ ctrl_reg = MPUREG_I2C_SLV3_CTRL;
+ addr_trig_reg = MPUREG_I2C_SLV4_ADDR;
+ reg_trig_reg = MPUREG_I2C_SLV4_REG;
+ ctrl_trig_reg = MPUREG_I2C_SLV4_CTRL;
+ bits_slave_delay = BIT_SLV4_DLY_EN | BIT_SLV3_DLY_EN;
+ break;
+ default:
+ LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER);
+ return INV_ERROR_INVALID_PARAMETER;
+ };
+
+ /* return if this slave has already been set */
+ if ((slave_address &&
+ ((mldl_cfg->inv_mpu_state->i2c_slaves_enabled & bits_slave_delay)
+ == bits_slave_delay)) ||
+ (!slave_address &&
+ (mldl_cfg->inv_mpu_state->i2c_slaves_enabled & bits_slave_delay) ==
+ 0))
+ return 0;
+
+ result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, true);
/* Address */
result = inv_serial_single_write(gyro_handle,
mldl_cfg->mpu_chip_info->addr,
- MPUREG_AUX_SLV_ADDR, slave_address);
+ addr_reg, slave_address);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
/* Register */
- result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_ACCEL_BURST_ADDR, 1, ®);
+ result = inv_serial_single_write(gyro_handle,
+ mldl_cfg->mpu_chip_info->addr,
+ reg_reg, slave_reg);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
- reg = ((reg & 0x80) | slave_reg);
+
+ /* Length, byte swapping, grouping & enable */
+ if (slave_len > BITS_SLV_LENG) {
+ MPL_LOGW("Limiting slave burst read length to "
+ "the allowed maximum (15B, req. %d)\n", slave_len);
+ slave_len = BITS_SLV_LENG;
+ return INV_ERROR_INVALID_CONFIGURATION;
+ }
+ reg = slave_len;
+ if (slave_endian == EXT_SLAVE_LITTLE_ENDIAN) {
+ reg |= BIT_SLV_BYTE_SW;
+ if (slave_reg & 1)
+ reg |= BIT_SLV_GRP;
+ }
+ if (slave_address)
+ reg |= BIT_SLV_ENABLE;
+
result = inv_serial_single_write(gyro_handle,
mldl_cfg->mpu_chip_info->addr,
- MPUREG_ACCEL_BURST_ADDR, reg);
+ ctrl_reg, reg);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
- /* Length */
- result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_USER_CTRL, 1, ®);
- if (result) {
- LOG_RESULT_LOCATION(result);
- return result;
+ /* Trigger */
+ if (addr_trig_reg) {
+ /* If slave address is 0 this clears the trigger */
+ result = inv_serial_single_write(gyro_handle,
+ mldl_cfg->mpu_chip_info->addr,
+ addr_trig_reg,
+ slave_address & ~BIT_I2C_READ);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
}
- reg = (reg & ~BIT_AUX_RD_LENG);
- result = inv_serial_single_write(
- gyro_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_USER_CTRL, reg);
+
+ if (slave && slave->trigger && reg_trig_reg) {
+ result = inv_serial_single_write(gyro_handle,
+ mldl_cfg->mpu_chip_info->addr,
+ reg_trig_reg,
+ slave->trigger->reg);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = inv_serial_single_write(gyro_handle,
+ mldl_cfg->mpu_chip_info->addr,
+ ctrl_trig_reg,
+ BIT_SLV_ENABLE | 0x01);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = inv_serial_single_write(gyro_handle,
+ mldl_cfg->mpu_chip_info->addr,
+ d0_trig_reg,
+ slave->trigger->value);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ } else if (ctrl_trig_reg) {
+ result = inv_serial_single_write(gyro_handle,
+ mldl_cfg->mpu_chip_info->addr,
+ ctrl_trig_reg, 0x00);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ }
+
+ /* Data rate */
+ if (slave) {
+ struct ext_slave_config config;
+ long data;
+ config.key = MPU_SLAVE_CONFIG_ODR_RESUME;
+ config.len = sizeof(long);
+ config.apply = false;
+ config.data = &data;
+ if (!(slave->get_config))
+ return INV_ERROR_INVALID_CONFIGURATION;
+
+ result = slave->get_config(NULL, slave, slave_pdata, &config);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ MPL_LOGI("Slave %d ODR: %ld Hz\n", slave_id, data / 1000);
+ divider = ((1000 * inv_mpu_get_sampling_rate_hz(
+ mldl_cfg->mpu_gyro_cfg))
+ / data) - 1;
+ } else {
+ divider = 0;
+ }
+
+ result = inv_serial_read(gyro_handle,
+ mldl_cfg->mpu_chip_info->addr,
+ MPUREG_I2C_MST_DELAY_CTRL,
+ 1, &delay_ctrl_orig);
+ delay_ctrl = delay_ctrl_orig;
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
+ if (divider > 0 && divider <= MASK_I2C_MST_DLY) {
+ result = inv_serial_read(gyro_handle,
+ mldl_cfg->mpu_chip_info->addr,
+ MPUREG_I2C_SLV4_CTRL, 1, ®);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ if ((reg & MASK_I2C_MST_DLY) &&
+ ((long)(reg & MASK_I2C_MST_DLY) !=
+ (divider & MASK_I2C_MST_DLY))) {
+ MPL_LOGW("Changing slave divider: %ld to %ld\n",
+ (long)(reg & MASK_I2C_MST_DLY),
+ (divider & MASK_I2C_MST_DLY));
+
+ }
+ reg |= (unsigned char)(divider & MASK_I2C_MST_DLY);
+ result = inv_serial_single_write(gyro_handle,
+ mldl_cfg->mpu_chip_info->addr,
+ MPUREG_I2C_SLV4_CTRL,
+ reg);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ delay_ctrl |= bits_slave_delay;
+ } else {
+ delay_ctrl &= ~(bits_slave_delay);
+ }
+ if (delay_ctrl != delay_ctrl_orig) {
+ result = inv_serial_single_write(
+ gyro_handle, mldl_cfg->mpu_chip_info->addr,
+ MPUREG_I2C_MST_DELAY_CTRL,
+ delay_ctrl);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ }
+
+ if (slave_address)
+ mldl_cfg->inv_mpu_state->i2c_slaves_enabled |=
+ bits_slave_delay;
+ else
+ mldl_cfg->inv_mpu_state->i2c_slaves_enabled &=
+ ~bits_slave_delay;
+
return result;
}
-
static int mpu_set_slave(struct mldl_cfg *mldl_cfg,
void *gyro_handle,
struct ext_slave_descr *slave,
struct ext_slave_platform_data *slave_pdata,
int slave_id)
{
- return mpu_set_slave_mpu3050(mldl_cfg, gyro_handle, slave,
+ return mpu_set_slave_mpu60xx(mldl_cfg, gyro_handle, slave,
slave_pdata, slave_id);
}
/**
return result;
}
-#define ML_SKIP_CHECK 20
+#define ML_SKIP_CHECK 38
for (offset = 0; offset < write_size; offset++) {
/* skip the register memory locations */
if (bank == 0 && offset < ML_SKIP_CHECK)
unsigned char regs[7];
/* Wake up the part */
- result = mpu3050_pwr_mgmt(mldl_cfg, gyro_handle, false, false,
- !(sensors & INV_X_GYRO),
- !(sensors & INV_Y_GYRO),
- !(sensors & INV_Z_GYRO));
-
- if (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_NEEDS_CONFIG) &&
- !mpu_was_reset(mldl_cfg, gyro_handle)) {
- return INV_SUCCESS;
- }
-
+ result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, false, sensors);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
+
+ /* Always set the INT_ENABLE and DIVIDER as the Accel Only mode for 6050
+ can set these too */
result = inv_serial_single_write(
gyro_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_INT_CFG,
- (mldl_cfg->mpu_gyro_cfg->int_config |
- mldl_cfg->pdata->int_config));
+ MPUREG_INT_ENABLE, (mldl_cfg->mpu_gyro_cfg->int_config));
if (result) {
LOG_RESULT_LOCATION(result);
return result;
LOG_RESULT_LOCATION(result);
return result;
}
+
+ if (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_NEEDS_CONFIG) &&
+ !mpu_was_reset(mldl_cfg, gyro_handle)) {
+ return INV_SUCCESS;
+ }
+
+ /* Configure the MPU */
+ result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
result = mpu_set_clock_source(gyro_handle, mldl_cfg);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
- reg = DLPF_FS_SYNC_VALUE(mldl_cfg->mpu_gyro_cfg->ext_sync,
- mldl_cfg->mpu_gyro_cfg->full_scale,
- mldl_cfg->mpu_gyro_cfg->lpf);
+ reg = MPUREG_GYRO_CONFIG_VALUE(0, 0, 0,
+ mldl_cfg->mpu_gyro_cfg->full_scale);
+ result = inv_serial_single_write(
+ gyro_handle, mldl_cfg->mpu_chip_info->addr,
+ MPUREG_GYRO_CONFIG, reg);
+ reg = MPUREG_CONFIG_VALUE(mldl_cfg->mpu_gyro_cfg->ext_sync,
+ mldl_cfg->mpu_gyro_cfg->lpf);
result = inv_serial_single_write(
gyro_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_DLPF_FS_SYNC, reg);
+ MPUREG_CONFIG, reg);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
result = inv_serial_single_write(
gyro_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_XG_OFFS_TC, mldl_cfg->mpu_offsets->tc[0]);
+ MPUREG_XG_OFFS_TC,
+ ((mldl_cfg->mpu_offsets->tc[0] << 1) & BITS_XG_OFFS_TC));
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
+ regs[0] = ((mldl_cfg->mpu_offsets->tc[1] << 1) & BITS_YG_OFFS_TC);
result = inv_serial_single_write(
gyro_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_YG_OFFS_TC, mldl_cfg->mpu_offsets->tc[1]);
+ MPUREG_YG_OFFS_TC, regs[0]);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
}
result = inv_serial_single_write(
gyro_handle, mldl_cfg->mpu_chip_info->addr,
- MPUREG_ZG_OFFS_TC, mldl_cfg->mpu_offsets->tc[2]);
+ MPUREG_ZG_OFFS_TC,
+ ((mldl_cfg->mpu_offsets->tc[2] << 1) & BITS_ZG_OFFS_TC));
if (result) {
LOG_RESULT_LOCATION(result);
return result;
struct mpu_offsets *mpu_offsets = mldl_cfg->mpu_offsets;
int ii;
- if (!data->data)
+ if (!data->data){
+ printk("gyro_get_config----------------------1\n");
return INV_ERROR_INVALID_PARAMETER;
+ }
switch (data->key) {
case MPU_SLAVE_INT_CONFIG:
*((__u16 *)data->data) = mpu_chip_info->accel_sens_trim;
break;
case MPU_SLAVE_RAM:
- if (data->len != mldl_cfg->mpu_ram->length)
+ if (data->len != mldl_cfg->mpu_ram->length){
+ printk("gyro_get_config----------------------2\n");
return INV_ERROR_INVALID_PARAMETER;
+ }
memcpy(data->data, mldl_cfg->mpu_ram->ram, data->len);
break;
default:
+ printk("gyro_get_config----------------------3\n");
LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
};
* Take the DMP out of sleep, and
* read the product_id, sillicon rev and whoami
*/
- mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_BYPASSED;
- result = mpu3050_pwr_mgmt(mldl_cfg, gyro_handle, RESET, 0, 0, 0, 0);
+ mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_BYPASSED;
+ result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, true,
+ INV_THREE_AXIS_GYRO);
if (result) {
LOG_RESULT_LOCATION(result);
return result;
return result;
}
+ for (ii = 0; ii < GYRO_NUM_AXES; ii++) {
+ mldl_cfg->mpu_offsets->tc[ii] =
+ (mldl_cfg->mpu_offsets->tc[ii] & BITS_XG_OFFS_TC) >> 1;
+ }
#if INV_CACHE_DMP != 0
- result = mpu3050_pwr_mgmt(mldl_cfg, gyro_handle, 0, SLEEP, 0, 0, 0);
+ result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, false, 0);
#endif
if (result) {
LOG_RESULT_LOCATION(result);
/* Gyro */
if (suspend_slave[EXT_SLAVE_TYPE_GYROSCOPE] &&
!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_IS_SUSPENDED)) {
- result = mpu3050_pwr_mgmt(
- mldl_cfg, gyro_handle, 0,
- suspend_dmp && suspend_slave[EXT_SLAVE_TYPE_GYROSCOPE],
- (unsigned char)(sensors & INV_X_GYRO),
- (unsigned char)(sensors & INV_Y_GYRO),
- (unsigned char)(sensors & INV_Z_GYRO));
+ result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, false,
+ ((~sensors) & INV_ALL_SENSORS));
if (result) {
LOG_RESULT_LOCATION(result);
return result;
#include "mltypes.h"
#include "mlsl.h"
#include <linux/mpu.h>
-#include "mpu3050.h"
+#include "mpu6050b1.h"
#include "log.h"
int ii;
/* mpu_gyro_cfg */
- MPL_LOGI("int_config = %02x\n", mpu_gyro_cfg->int_config);
- MPL_LOGI("ext_sync = %02x\n", mpu_gyro_cfg->ext_sync);
- MPL_LOGI("full_scale = %02x\n", mpu_gyro_cfg->full_scale);
- MPL_LOGI("lpf = %02x\n", mpu_gyro_cfg->lpf);
- MPL_LOGI("clk_src = %02x\n", mpu_gyro_cfg->clk_src);
- MPL_LOGI("divider = %02x\n", mpu_gyro_cfg->divider);
- MPL_LOGI("dmp_enable = %02x\n", mpu_gyro_cfg->dmp_enable);
- MPL_LOGI("fifo_enable = %02x\n", mpu_gyro_cfg->fifo_enable);
- MPL_LOGI("dmp_cfg1 = %02x\n", mpu_gyro_cfg->dmp_cfg1);
- MPL_LOGI("dmp_cfg2 = %02x\n", mpu_gyro_cfg->dmp_cfg2);
+ MPL_LOGV("int_config = %02x\n", mpu_gyro_cfg->int_config);
+ MPL_LOGV("ext_sync = %02x\n", mpu_gyro_cfg->ext_sync);
+ MPL_LOGV("full_scale = %02x\n", mpu_gyro_cfg->full_scale);
+ MPL_LOGV("lpf = %02x\n", mpu_gyro_cfg->lpf);
+ MPL_LOGV("clk_src = %02x\n", mpu_gyro_cfg->clk_src);
+ MPL_LOGV("divider = %02x\n", mpu_gyro_cfg->divider);
+ MPL_LOGV("dmp_enable = %02x\n", mpu_gyro_cfg->dmp_enable);
+ MPL_LOGV("fifo_enable = %02x\n", mpu_gyro_cfg->fifo_enable);
+ MPL_LOGV("dmp_cfg1 = %02x\n", mpu_gyro_cfg->dmp_cfg1);
+ MPL_LOGV("dmp_cfg2 = %02x\n", mpu_gyro_cfg->dmp_cfg2);
/* mpu_offsets */
MPL_LOGV("tc[0] = %02x\n", mpu_offsets->tc[0]);
MPL_LOGV("tc[1] = %02x\n", mpu_offsets->tc[1]);
MPL_LOGV("product_revision = %02x\n", mpu_chip_info->product_revision);
MPL_LOGV("product_id = %02x\n", mpu_chip_info->product_id);
MPL_LOGV("gyro_sens_trim = %02x\n", mpu_chip_info->gyro_sens_trim);
+ MPL_LOGV("accel_sens_trim = %02x\n", mpu_chip_info->accel_sens_trim);
MPL_LOGV("requested_sensors = %04x\n", inv_mpu_cfg->requested_sensors);
MPL_LOGV("ignore_system_suspend= %04x\n",
#include "mlsl.h"
#include <linux/i2c.h>
#include "log.h"
-#include "mpu3050.h"
+#include "mpu6050b1.h"
#define MPU_I2C_RATE 100*1000
static int inv_i2c_write(struct i2c_adapter *i2c_adap,
msgs[0].scl_rate = MPU_I2C_RATE;
res = i2c_transfer(i2c_adap, msgs, 1);
- if (res == 1)
- return 0;
- else if(res == 0)
- return -EBUSY;
- else
+ if (res < 1) {
+ if (res == 0)
+ res = -EIO;
+ LOG_RESULT_LOCATION(res);
return res;
-
+ } else
+ return 0;
}
static int inv_i2c_write_register(struct i2c_adapter *i2c_adap,
msgs[1].scl_rate = MPU_I2C_RATE;
res = i2c_transfer(i2c_adap, msgs, 2);
- if (res == 2)
- return 0;
- else if(res == 0)
- return -EBUSY;
- else
+ if (res < 2) {
+ if (res >= 0)
+ res = -EIO;
+ LOG_RESULT_LOCATION(res);
return res;
-
+ } else
+ return 0;
}
static int mpu_memory_read(struct i2c_adapter *i2c_adap,
along with this program. If not, see <http://www.gnu.org/licenses/>.
$
*/
-#define DEBUG
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/interrupt.h>
#include "mldl_cfg.h"
#include <linux/mpu.h>
+#include "accel/mpu6050.h"
+
+#include <linux/syscalls.h>
+#include <linux/freezer.h>
+#include <linux/jiffies.h>
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
+#include <linux/iio/consumer.h>
+
+
+
+
+
+#define CAB_NUM 1
+#define M_CONST 49152
+//#define MPU6050_CABLIC "/data/mpu6050_cablic.dat"
+#define MPU6050_CABLIC "/dev/mtd/mtd6"
+
+static int mpu6050_get = 0;
+static bool Is_cab=false;
+static int count_s=0;
+static int countx=0;
+static int countx_l=0;
+static int county=0;
+static int county_l=0;
+static int countz=0;
+static int countz_l=0;
+static int get_cablic;
+static int gsensor_clear = 0;
+
+
+struct cal_data {
+ int valid;
+ long xoffset;
+ long xoffset_l;
+ long xoffset1;
+ long xoffset1_l;
+ long yoffset;
+ long yoffset_l;
+ long yoffset1;
+ long yoffset1_l;
+ long zoffset;
+ long zoffset_l;
+ long zoffset1;
+ long zoffset1_l;
+// char magic[4];
+ char reser[512];
+};
+
+static struct cal_data cablic_arry[CAB_NUM];
+static struct kobject *android_gsensor_kobj;
+
+struct mpu6050_in{
+ //struct timer_list sn_timer;
+ struct workqueue_struct *wq;
+ struct delayed_work delay_work;
+ struct work_struct sn_work;
+};
/* Platform data for the MPU */
struct mpu_private_data {
struct module *slave_modules[EXT_SLAVE_NUM_TYPES];
};
+struct mpu_platform_data mpu_data;
struct mpu_private_data *mpu_private_data;
-static struct i2c_client *this_client;
static void mpu_pm_timeout(u_long data)
{
static int mpu_dev_open(struct inode *inode, struct file *file)
{
struct mpu_private_data *mpu =
- (struct mpu_private_data *) i2c_get_clientdata(this_client);
+ container_of(file->private_data, struct mpu_private_data, dev);
struct i2c_client *client = mpu->client;
int result;
int ii;
return -EBUSY;
}
mpu->pid = current->pid;
- file->private_data = &mpu->dev;
/* Reset the sensors to the default */
if (result) {
void *user_data;
retval = copy_from_user(&config, usr_config, sizeof(config));
- if (retval)
+ if (retval){
+ printk("inv_mpu_get_config----------------------\n");
return -EFAULT;
+ }
user_data = config.data;
if (config.len && config.data) {
void *data;
data = kmalloc(config.len, GFP_KERNEL);
- if (!data)
+ if (!data){
+ printk("inv_mpu_get_config----------------------1\n");
return -ENOMEM;
+ }
retval = copy_from_user(data,
(void __user *)config.data, config.len);
if (retval) {
+ printk("inv_mpu_get_config----------------------2\n");
retval = -EFAULT;
kfree(data);
return retval;
retval = copy_to_user((unsigned char __user *)user_data,
config.data, config.len);
kfree(config.data);
+
return retval;
}
return retval;
}
+static int mpu6050_load_cablic(const char *addr)
+{
+ int ret;
+ long fd = sys_open(addr,O_RDONLY,0);
+ printk("yemk:mpu6050_load_cablic\n");
+ if(fd < 0){
+ printk("mpu6050_load_cablic: open file %s\n", MPU6050_CABLIC);
+ return -1;
+ }
+ ret = sys_read(fd,(char __user *)cablic_arry,sizeof(cablic_arry));
+ sys_close(fd);
+
+ return ret;
+}
+
+static void mpu6050_put_cablic(const char *addr)
+{
+ long fd = sys_open(addr,O_CREAT | O_RDWR | O_TRUNC,0);
+ printk("yemk:mpu6050_put_cablic\n");
+ if(fd<0){
+ printk("mpu6050_put_cablic: open file%s\n",MPU6050_CABLIC);
+ return;
+ }
+ sys_write(fd,(const char __user *)cablic_arry,sizeof(cablic_arry));
+
+ sys_close(fd);
+}
+static void mpu_get(struct work_struct *work)
+{
+ struct mpu6050_in *bat = container_of((work), \
+ struct mpu6050_in, delay_work);
+
+ if(mpu6050_get==1){
+ mpu6050_put_cablic(MPU6050_CABLIC);
+ mpu6050_get=0;
+ }else{
+ if(get_cablic){
+ get_cablic=0;
+ mpu6050_load_cablic(MPU6050_CABLIC);
+ }
+ }
+
+ if(gsensor_clear==1){
+ mpu6050_put_cablic(MPU6050_CABLIC);
+ gsensor_clear=0;
+ }
+ queue_delayed_work(bat ->wq, &bat ->delay_work, msecs_to_jiffies(3000));
+}
+
static int inv_slave_read(struct mldl_cfg *mldl_cfg,
void *gyro_adapter,
void *slave_adapter,
kfree(msg.data);
return retval;
}
+static int mpu6050_check(unsigned long arg)
+{
+ char data[6];
+ short int x,y,z;
+ short int zoffs=0,xoffs=0,yoffs=0;
+
+ if(copy_from_user(data, (unsigned char __user *)arg, sizeof(data)))
+ return -EFAULT;
+
+ x = data[0]*256 + data[1];
+ y = data[2]*256 + data[3];
+ z = data[4]*256 + data[5];
+ xoffs = x;
+ yoffs = y;
+ zoffs = z-M_CONST;
+ //printk("yemk1111 cablic_arry[0].zoffset_l=%8ld\n",cablic_arry[0].zoffset_l);
+ if(Is_cab==true){
+ if(zoffs>0){
+ //printk("zheng cablic_arry[0].zoffset=%8ld\n",cablic_arry[0].zoffset);
+ cablic_arry[0].zoffset+=zoffs;
+ countz++;
+ }else{
+ //printk("zheng cablic_arry[0].zoffset_l=%8ld\n",cablic_arry[0].zoffset_l);
+ cablic_arry[0].zoffset_l+=zoffs;
+ countz_l++;
+ }
+ if(xoffs>0){
+ cablic_arry[0].xoffset+=xoffs;
+ countx++;
+ }else{
+ cablic_arry[0].xoffset_l+=xoffs;
+ countx_l++;
+ }
+ if(yoffs>0){
+ cablic_arry[0].yoffset+=yoffs;
+ county++;
+ }else{
+ cablic_arry[0].yoffset_l+=yoffs;
+ county_l++;
+ }
+ count_s++;
+ //printk("yemk2222 z=%d,zoffs=%d\n",z,zoffs);
+ //printk("yemk2222 x=%8ld,xoffs=%8ld\n",x,xoffs);
+ //printk("yemk2222 y=%8ld,yoffs=%8ld\n",y,yoffs);
+ if(count_s==20){
+ //cablic_arry[0].xoffset=cablic_arry[0].xoffset/count_s;
+ //cablic_arry[0].yoffset=cablic_arry[0].yoffset/count_s;
+ //printk("yemk11:cab_check->zoffset=%8ld\n",cablic_arry[0].zoffset);
+ if(countz)
+ cablic_arry[0].zoffset=(cablic_arry[0].zoffset-cablic_arry[0].zoffset1)/countz;
+ if(countz_l)
+ cablic_arry[0].zoffset_l=(cablic_arry[0].zoffset_l-cablic_arry[0].zoffset1_l)/countz_l;
+ if(countx)
+ cablic_arry[0].xoffset=(cablic_arry[0].xoffset-cablic_arry[0].xoffset1)/countx;
+ if(countx_l)
+ cablic_arry[0].xoffset_l=(cablic_arry[0].xoffset_l-cablic_arry[0].xoffset1_l)/countx_l;
+ if(county)
+ cablic_arry[0].yoffset=(cablic_arry[0].yoffset-cablic_arry[0].yoffset1)/county;
+ if(county_l)
+ cablic_arry[0].yoffset_l=(cablic_arry[0].yoffset_l-cablic_arry[0].yoffset1_l)/county_l;
+ //printk("yemk cab_check->zoffset=%8ld,zoffset1=%8ld\n",cablic_arry[0].zoffset,cablic_arry[0].zoffset1);
+ //printk("yemk cab_check->zoffset=%d\n",cablic_arry[0].yoffset);
+ //printk("yemk2222 cab_check->zoffset=%8ld,..%8ld\n",cablic_arry[0].zoffset,cablic_arry[0].zoffset_l);
+ //printk("yemk2222 cab_check->yoffset=%8ld,..%8ld ..%d --%d\n",cablic_arry[0].yoffset,cablic_arry[0].yoffset_l,county,county_l);
+ //printk("yemk2222 cab_check->zoffset=%8ld,..%8ld ..%d --%d\n",cablic_arry[0].zoffset,cablic_arry[0].zoffset_l,countz,countz_l);
+ cablic_arry[0].zoffset1=cablic_arry[0].zoffset;
+ cablic_arry[0].zoffset1_l=cablic_arry[0].zoffset_l;
+
+ cablic_arry[0].xoffset1=cablic_arry[0].xoffset;
+ cablic_arry[0].xoffset1_l=cablic_arry[0].xoffset_l;
+
+ cablic_arry[0].yoffset1=cablic_arry[0].yoffset;
+ cablic_arry[0].yoffset1_l=cablic_arry[0].yoffset_l;
+
+ Is_cab=false;
+ count_s=0;
+ countx=0;
+ countx_l=0;
+ county=0;
+ county_l=0;
+ countz=0;
+ countz_l=0;
+ mpu6050_get=1;
+ cablic_arry[0].valid=7654321;
+
+ }
+ }else{
+ if(cablic_arry[0].valid == 7654321){
+ if(zoffs>=0){
+ //printk("zheng z=%d,zoffs=%d\n",z,zoffs);
+ data[4] = (z-cablic_arry[0].zoffset)/256;
+ data[5] = (z-cablic_arry[0].zoffset)%256;
+ }else{
+ //printk("fu z=%d,zoffs=%d\n",z,zoffs);
+ data[4] = (z-cablic_arry[0].zoffset_l)/256;
+ data[5] = (z-cablic_arry[0].zoffset_l)%256;
+ }
+
+ if(xoffs>=0){
+ data[0] = (x-cablic_arry[0].xoffset)/256;
+ data[1] = (x-cablic_arry[0].xoffset)%256;
+ }else{
+ data[0] = (x-cablic_arry[0].xoffset_l)/256;
+ data[1] = (x-cablic_arry[0].xoffset_l)%256;
+ }
+
+ if(yoffs>=0){
+ data[2] = (y-cablic_arry[0].yoffset)/256;
+ data[3] = (y-cablic_arry[0].yoffset)%256;
+ }else{
+ data[2] = (y-cablic_arry[0].yoffset_l)/256;
+ data[3] = (y-cablic_arry[0].yoffset_l)%256;
+ }
+ }
+ }
+ if(copy_to_user((unsigned char __user *)arg,data, sizeof(data)))
+ return -EFAULT;
+ return 0;
+}
/* ioctl - I/O control */
static long mpu_dev_ioctl(struct file *file,
i2c_get_adapter(pdata_slave[ii]->adapt_num);
}
slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
-
+
retval = mutex_lock_interruptible(&mpu->mutex);
if (retval) {
- dev_err(&this_client->adapter->dev,
+ dev_err(&client->adapter->dev,
"%s: mutex_lock_interruptible returned %d\n",
__func__, retval);
return retval;
}
+
switch (cmd) {
case MPU_GET_EXT_SLAVE_PLATFORM_DATA:
retval = mpu_dev_ioctl_get_ext_slave_platform_data(
slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
(struct ext_slave_config __user *)arg);
break;
- case MPU_GET_CONFIG_ACCEL:
+ case MPU_GET_CONFIG_ACCEL:
retval = slave_get_config(
mldl_cfg,
slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
complete(&mpu->completion);
break;
case MPU_READ_ACCEL:
+ //printk("###########MPU_READ_ACCEL\n");
retval = inv_slave_read(
mldl_cfg,
slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
slave[EXT_SLAVE_TYPE_ACCEL],
pdata_slave[EXT_SLAVE_TYPE_ACCEL],
(unsigned char __user *)arg);
+ mpu6050_check(arg);
break;
case MPU_READ_COMPASS:
retval = inv_slave_read(
};
mutex_unlock(&mpu->mutex);
-
-
- //dev_dbg(&client->adapter->dev, "%s: %08x, %08lx, %d\n",__func__, cmd, arg, retval);
+ dev_dbg(&client->adapter->dev, "%s: %08x, %08lx, %d\n",
+ __func__, cmd, arg, retval);
if (retval > 0)
retval = -retval;
.owner = THIS_MODULE,
.read = mpu_read,
.poll = mpu_poll,
-#if HAVE_COMPAT_IOCTL
- .compat_ioctl = mpu_dev_ioctl,
-#endif
-#if HAVE_UNLOCKED_IOCTL
.unlocked_ioctl = mpu_dev_ioctl,
-#endif
- //.unlocked_ioctl = mpu_dev_ioctl,
.open = mpu_dev_open,
.release = mpu_release,
};
}
slave_pdata->address = slave_client->addr;
- slave_pdata->irq = gpio_to_irq(slave_client->irq);
+ slave_pdata->irq = 0;
slave_pdata->adapt_num = i2c_adapter_id(slave_client->adapter);
dev_info(&slave_client->adapter->dev,
}
}
+ if (slave_descr->type == EXT_SLAVE_TYPE_ACCEL &&
+ slave_descr->id == ACCEL_ID_MPU6050 &&
+ slave_descr->config) {
+
+ /* pass a reference to the mldl_cfg data
+ structure to the mpu6050 accel "class" */
+ struct ext_slave_config config;
+ config.key = MPU_SLAVE_CONFIG_INTERNAL_REFERENCE;
+ config.len = sizeof(struct mldl_cfg *);
+ config.apply = true;
+ config.data = mldl_cfg;
+ result = slave_descr->config(
+ slave_client->adapter, slave_descr,
+ slave_pdata, &config);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ goto out_slavedescr_exit;
+ }
+ }
pdata_slave[slave_descr->type] = slave_pdata;
mpu->slave_modules[slave_descr->type] = slave_module;
mldl_cfg->slave[slave_descr->type] = slave_descr;
goto out_unlock_mutex;
+out_slavedescr_exit:
+ if (slave_descr->exit)
+ slave_descr->exit(slave_client->adapter,
+ slave_descr, slave_pdata);
out_unlock_mutex:
mutex_unlock(&mpu->mutex);
warn_result = slaveirq_init(slave_client->adapter,
slave_pdata, irq_name);
if (result)
- dev_err(&slave_client->adapter->dev,
+ dev_WARN(&slave_client->adapter->dev,
"%s irq assigned error: %d\n",
slave_descr->name, warn_result);
} else {
- dev_warn(&slave_client->adapter->dev,
+/* dev_WARN(&slave_client->adapter->dev,
"%s irq not assigned: %d %d %d\n",
slave_descr->name,
- result, (int)irq_name, slave_pdata->irq);
+ result, (int)irq_name, slave_pdata->irq);*/
}
return result;
}
EXPORT_SYMBOL(inv_mpu_unregister_slave);
+static int mpu_parse_dt(struct i2c_client *client,
+ struct mpu_platform_data *data)
+{
+ int ret;
+ struct device_node *np = client->dev.of_node;
+ //enum of_gpio_flags gpioflags;
+ int length = 0,size = 0;
+ struct property *prop;
+ int debug = 1;
+ int i;
+ char mAarray[20];
+ int orig_x,orig_y,orig_z;
+ enum of_gpio_flags irq_flags;
+ int irq_pin;
+ u32 orientation[GYRO_NUM_AXES * GYRO_NUM_AXES];
+
+
+ irq_pin=of_get_named_gpio_flags(np, "irq-gpio", 0, (enum of_gpio_flags *)&irq_flags);
+ if(irq_pin<0){
+ dev_err(&client->dev, "get irq-gpio error\n");
+ return -EIO;
+ }
+
+ if (gpio_request(irq_pin, "mpu-irq")) {
+ dev_err(&client->dev, "mpu irq request failed\n");
+ return -ENODEV;
+ }
+ client->irq=gpio_to_irq(irq_pin);
+
+ ret = of_property_read_u32(np,"mpu-int_config",&data->int_config);
+ if(ret!=0){
+ dev_err(&client->dev, "get mpu-int_config error\n");
+ return -EIO;
+ }
+
+ ret = of_property_read_u32(np,"mpu-level_shifter",&data->level_shifter);
+ if(ret!=0){
+ dev_err(&client->dev, "get mpu-level_shifter error\n");
+ return -EIO;
+ }
+
+
+ prop = of_find_property(np, "mpu-orientation", &length);
+ if (!prop){
+ dev_err(&client->dev, "get mpu-orientation length error\n");
+ return -EINVAL;
+ }
+
+ size = length / sizeof(u32);
+
+ if((size > 0)&&(size <10)){
+ ret = of_property_read_u32_array(np, "mpu-orientation",
+ orientation,
+ size);
+
+ if(ret<0){
+ dev_err(&client->dev, "get mpu-orientation data error\n");
+ return -EINVAL;
+ }
+ }
+ else{
+ printk(" use default orientation\n");
+ }
+
+ for(i=0;i<9;i++)
+ data->orientation[i]= orientation[i];
+
+ ret = of_property_read_u32(np,"orientation-x",&orig_x);
+ if(ret!=0){
+ dev_err(&client->dev, "get orientation-x error\n");
+ return -EIO;
+ }
+
+ if(orig_x>0){
+ for(i=0;i<3;i++)
+ if(data->orientation[i])
+ data->orientation[i]=-1;
+ }
+
+ ret = of_property_read_u32(np,"orientation-y",&orig_y);
+ if(ret!=0){
+ dev_err(&client->dev, "get orientation-y error\n");
+ return -EIO;
+ }
+
+ if(orig_y>0){
+ for(i=3;i<6;i++)
+ if(data->orientation[i])
+ data->orientation[i]=-1;
+ }
+
+
+ ret = of_property_read_u32(np,"orientation-z",&orig_z);
+ if(ret!=0){
+ dev_err(&client->dev, "get orientation-z error\n");
+ return -EIO;
+ }
+
+ if(orig_z>0){
+ for(i=6;i<9;i++)
+ if(data->orientation[i])
+ data->orientation[i]=-1;
+ }
+
+
+ ret = of_property_read_u32(np,"mpu-debug",&debug);
+ if(ret!=0){
+ dev_err(&client->dev, "get mpu-debug error\n");
+ return -EINVAL;
+ }
+
+ if(debug){
+ printk("int_config=%d,level_shifter=%d,client.addr=%x,client.irq=%x\n",data->int_config, \
+ data->level_shifter,client->addr,client->irq);
+
+ for(i=0;i<size;i++)
+ printk("%d ",data->orientation[i]);
+ printk("\n");
+
+ }
+ return 0;
+}
+
+
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
static const struct i2c_device_id mpu_id[] = {
struct mldl_cfg *mldl_cfg;
int res = 0;
int ii = 0;
+ int ret = 0;
+ struct mpu6050_in *mpu6050_l;
+
+ ret = mpu_parse_dt(client,&mpu_data);
+ if(ret< 0)
+ printk("parse mpu dts failed\n");
dev_info(&client->adapter->dev, "%s: %d\n", __func__, ii++);
res = -ENOMEM;
goto out_alloc_data_failed;
}
+ mpu6050_l = kzalloc(sizeof(*mpu6050_l), GFP_KERNEL);
+ if (!mpu6050_l) {
+ printk("failed to allocate device info data in mpu6050_init\n");
+ ret = -ENOMEM;
+ return ret;
+ }
mldl_cfg = &mpu->mldl_cfg;
mldl_cfg->mpu_ram = &mpu->mpu_ram;
mldl_cfg->mpu_gyro_cfg = &mpu->mpu_gyro_cfg;
}
mpu_private_data = mpu;
i2c_set_clientdata(client, mpu);
- this_client = client;
mpu->client = client;
init_waitqueue_head(&mpu->mpu_event_wait);
"Unable to register pm_notifier %d\n", res);
goto out_register_pm_notifier_failed;
}
-
- pdata = (struct mpu_platform_data *)client->dev.platform_data;
- if (!pdata) {
- dev_WARN(&client->adapter->dev,
- "Missing platform data for mpu\n");
- }
- mldl_cfg->pdata = pdata;
+ mpu6050_l->wq = create_singlethread_workqueue("mpu6050_invensen");
+ INIT_DELAYED_WORK(&mpu6050_l->delay_work, mpu_get);
+ queue_delayed_work(mpu6050_l->wq, &mpu6050_l->delay_work, msecs_to_jiffies(3000));
+
+ mldl_cfg->pdata = &mpu_data;
mldl_cfg->mpu_chip_info->addr = client->addr;
res = inv_mpu_open(&mpu->mldl_cfg, client->adapter, NULL, NULL, NULL);
dev_WARN(&client->adapter->dev,
"Missing %s IRQ\n", MPU_NAME);
}
+
+ if (!strcmp(mpu_id[1].name, devid->name)) {
+ /* Special case to re-use the inv_mpu_register_slave */
+ struct ext_slave_platform_data *slave_pdata;
+ slave_pdata = kzalloc(sizeof(*slave_pdata), GFP_KERNEL);
+ if (!slave_pdata) {
+ res = -ENOMEM;
+ goto out_slave_pdata_kzalloc_failed;
+ }
+ slave_pdata->bus = EXT_SLAVE_BUS_PRIMARY;
+ for (ii = 0; ii < 9; ii++)
+ slave_pdata->orientation[ii] = mpu_data.orientation[ii];
+ res = inv_mpu_register_slave(
+ NULL, client,
+ slave_pdata,
+ mpu6050_get_slave_descr);
+ if (res) {
+ /* if inv_mpu_register_slave fails there are no pointer
+ references to the memory allocated to slave_pdata */
+ kfree(slave_pdata);
+ goto out_slave_pdata_kzalloc_failed;
+ }
+ }
return res;
+out_slave_pdata_kzalloc_failed:
+ if (client->irq)
+ mpuirq_exit();
out_mpuirq_failed:
misc_deregister(&mpu->dev);
out_misc_register_failed:
slave_adapter[EXT_SLAVE_TYPE_COMPASS],
slave_adapter[EXT_SLAVE_TYPE_PRESSURE]);
+ if (mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL] &&
+ (mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL]->id ==
+ ACCEL_ID_MPU6050)) {
+ struct ext_slave_platform_data *slave_pdata =
+ mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL];
+ inv_mpu_unregister_slave(
+ client,
+ mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL],
+ mpu6050_get_slave_descr);
+ kfree(slave_pdata);
+ }
if (client->irq)
mpuirq_exit();
return 0;
}
+static const struct of_device_id of_mpu_match[] = {
+ { .compatible = "mpu6050" },
+ { /* Sentinel */ }
+};
+
static struct i2c_driver mpu_driver = {
.class = I2C_CLASS_HWMON,
.probe = mpu_probe,
.driver = {
.owner = THIS_MODULE,
.name = MPU_NAME,
+ .of_match_table = of_mpu_match,
},
.address_list = normal_i2c,
.shutdown = mpu_shutdown, /* optional */
.resume = mpu_dev_resume, /* optional */
};
+static ssize_t gsensor_check_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", Is_cab);
+}
+
+static ssize_t gsensor_check_store(struct device *dev,
+ struct device_attribute *attr, char *buf,size_t count)
+{
+ switch (buf[0]) {
+ case '1':
+ Is_cab=true;
+ break;
+ case '0':
+ Is_cab=false;
+ break;
+ default:
+ Is_cab=false;
+ break;
+ }
+ return count;
+
+}
+static ssize_t gsensor_clear_store(struct device *dev,
+ struct device_attribute *attr, char *buf,size_t count)
+{
+// char mtddevname[64];
+// int mtd_index;
+ memset(cablic_arry, 0x00, sizeof(cablic_arry));
+ gsensor_clear = 1;
+ return count;
+
+}
+
+static DEVICE_ATTR(gsensorcheck, 0666, gsensor_check_show, gsensor_check_store);
+static DEVICE_ATTR(gsensorclear, 0666, NULL, gsensor_clear_store);
+
+
+static int gsensor_sysfs_init(void)
+{
+ int ret ;
+
+ android_gsensor_kobj = kobject_create_and_add("android_gsensor", NULL);
+ if (android_gsensor_kobj == NULL) {
+ printk(KERN_ERR
+ "mpu6050 gsensor_sysfs_init:"\
+ "subsystem_register failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ ret = sysfs_create_file(android_gsensor_kobj, &dev_attr_gsensorclear.attr); // "gsensorclear"
+ if (ret) {
+ printk(KERN_ERR
+ "mpu6050 gsensor_sysfs_init: gsensorclear"\
+ "sysfs_create_group failed\n");
+ goto err4;
+ }
+ ret = sysfs_create_file(android_gsensor_kobj, &dev_attr_gsensorcheck.attr);
+ if (ret) {
+ printk(KERN_ERR
+ "mpu6050 gsensor_sysfs_init:"\
+ "sysfs_create_group failed\n");
+ goto err4;
+ }
+ return 0 ;
+err4:
+ kobject_del(android_gsensor_kobj);
+err:
+ return ret ;
+}
static int __init mpu_init(void)
{
int res = i2c_add_driver(&mpu_driver);
pr_info("%s: Probe name %s\n", __func__, MPU_NAME);
+ if (res)
+ pr_err("%s failed\n", __func__);
+
+ memset(cablic_arry, 0x00, sizeof(cablic_arry));
+ get_cablic=1;
+ res=gsensor_sysfs_init();
if (res)
pr_err("%s failed\n", __func__);
return res;
--- /dev/null
+/*
+ $License:
+ Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+/**
+ * @defgroup
+ * @brief
+ *
+ * @{
+ * @file mpu6050.h
+ * @brief
+ */
+
+#ifndef __MPU_H_
+#error Do not include this file directly. Include mpu.h instead.
+#endif
+
+#ifndef __MPU6050B1_H_
+#define __MPU6050B1_H_
+
+
+#define MPU_NAME "mpu6050B1"
+#define DEFAULT_MPU_SLAVEADDR 0x68
+
+/*==== MPU6050B1 REGISTER SET ====*/
+enum {
+ MPUREG_XG_OFFS_TC = 0, /* 0x00, 0 */
+ MPUREG_YG_OFFS_TC, /* 0x01, 1 */
+ MPUREG_ZG_OFFS_TC, /* 0x02, 2 */
+ MPUREG_X_FINE_GAIN, /* 0x03, 3 */
+ MPUREG_Y_FINE_GAIN, /* 0x04, 4 */
+ MPUREG_Z_FINE_GAIN, /* 0x05, 5 */
+ MPUREG_XA_OFFS_H, /* 0x06, 6 */
+ MPUREG_XA_OFFS_L, /* 0x07, 7 */
+ MPUREG_YA_OFFS_H, /* 0x08, 8 */
+ MPUREG_YA_OFFS_L, /* 0x09, 9 */
+ MPUREG_ZA_OFFS_H, /* 0x0a, 10 */
+ MPUREG_ZA_OFFS_L, /* 0x0B, 11 */
+ MPUREG_PRODUCT_ID, /* 0x0c, 12 */
+ MPUREG_0D_RSVD, /* 0x0d, 13 */
+ MPUREG_0E_RSVD, /* 0x0e, 14 */
+ MPUREG_0F_RSVD, /* 0x0f, 15 */
+ MPUREG_10_RSVD, /* 0x00, 16 */
+ MPUREG_11_RSVD, /* 0x11, 17 */
+ MPUREG_12_RSVD, /* 0x12, 18 */
+ MPUREG_XG_OFFS_USRH, /* 0x13, 19 */
+ MPUREG_XG_OFFS_USRL, /* 0x14, 20 */
+ MPUREG_YG_OFFS_USRH, /* 0x15, 21 */
+ MPUREG_YG_OFFS_USRL, /* 0x16, 22 */
+ MPUREG_ZG_OFFS_USRH, /* 0x17, 23 */
+ MPUREG_ZG_OFFS_USRL, /* 0x18, 24 */
+ MPUREG_SMPLRT_DIV, /* 0x19, 25 */
+ MPUREG_CONFIG, /* 0x1A, 26 */
+ MPUREG_GYRO_CONFIG, /* 0x1b, 27 */
+ MPUREG_ACCEL_CONFIG, /* 0x1c, 28 */
+ MPUREG_ACCEL_FF_THR, /* 0x1d, 29 */
+ MPUREG_ACCEL_FF_DUR, /* 0x1e, 30 */
+ MPUREG_ACCEL_MOT_THR, /* 0x1f, 31 */
+ MPUREG_ACCEL_MOT_DUR, /* 0x20, 32 */
+ MPUREG_ACCEL_ZRMOT_THR, /* 0x21, 33 */
+ MPUREG_ACCEL_ZRMOT_DUR, /* 0x22, 34 */
+ MPUREG_FIFO_EN, /* 0x23, 35 */
+ MPUREG_I2C_MST_CTRL, /* 0x24, 36 */
+ MPUREG_I2C_SLV0_ADDR, /* 0x25, 37 */
+ MPUREG_I2C_SLV0_REG, /* 0x26, 38 */
+ MPUREG_I2C_SLV0_CTRL, /* 0x27, 39 */
+ MPUREG_I2C_SLV1_ADDR, /* 0x28, 40 */
+ MPUREG_I2C_SLV1_REG, /* 0x29, 41 */
+ MPUREG_I2C_SLV1_CTRL, /* 0x2a, 42 */
+ MPUREG_I2C_SLV2_ADDR, /* 0x2B, 43 */
+ MPUREG_I2C_SLV2_REG, /* 0x2c, 44 */
+ MPUREG_I2C_SLV2_CTRL, /* 0x2d, 45 */
+ MPUREG_I2C_SLV3_ADDR, /* 0x2E, 46 */
+ MPUREG_I2C_SLV3_REG, /* 0x2f, 47 */
+ MPUREG_I2C_SLV3_CTRL, /* 0x30, 48 */
+ MPUREG_I2C_SLV4_ADDR, /* 0x31, 49 */
+ MPUREG_I2C_SLV4_REG, /* 0x32, 50 */
+ MPUREG_I2C_SLV4_DO, /* 0x33, 51 */
+ MPUREG_I2C_SLV4_CTRL, /* 0x34, 52 */
+ MPUREG_I2C_SLV4_DI, /* 0x35, 53 */
+ MPUREG_I2C_MST_STATUS, /* 0x36, 54 */
+ MPUREG_INT_PIN_CFG, /* 0x37, 55 */
+ MPUREG_INT_ENABLE, /* 0x38, 56 */
+ MPUREG_DMP_INT_STATUS, /* 0x39, 57 */
+ MPUREG_INT_STATUS, /* 0x3A, 58 */
+ MPUREG_ACCEL_XOUT_H, /* 0x3B, 59 */
+ MPUREG_ACCEL_XOUT_L, /* 0x3c, 60 */
+ MPUREG_ACCEL_YOUT_H, /* 0x3d, 61 */
+ MPUREG_ACCEL_YOUT_L, /* 0x3e, 62 */
+ MPUREG_ACCEL_ZOUT_H, /* 0x3f, 63 */
+ MPUREG_ACCEL_ZOUT_L, /* 0x40, 64 */
+ MPUREG_TEMP_OUT_H, /* 0x41, 65 */
+ MPUREG_TEMP_OUT_L, /* 0x42, 66 */
+ MPUREG_GYRO_XOUT_H, /* 0x43, 67 */
+ MPUREG_GYRO_XOUT_L, /* 0x44, 68 */
+ MPUREG_GYRO_YOUT_H, /* 0x45, 69 */
+ MPUREG_GYRO_YOUT_L, /* 0x46, 70 */
+ MPUREG_GYRO_ZOUT_H, /* 0x47, 71 */
+ MPUREG_GYRO_ZOUT_L, /* 0x48, 72 */
+ MPUREG_EXT_SLV_SENS_DATA_00, /* 0x49, 73 */
+ MPUREG_EXT_SLV_SENS_DATA_01, /* 0x4a, 74 */
+ MPUREG_EXT_SLV_SENS_DATA_02, /* 0x4b, 75 */
+ MPUREG_EXT_SLV_SENS_DATA_03, /* 0x4c, 76 */
+ MPUREG_EXT_SLV_SENS_DATA_04, /* 0x4d, 77 */
+ MPUREG_EXT_SLV_SENS_DATA_05, /* 0x4e, 78 */
+ MPUREG_EXT_SLV_SENS_DATA_06, /* 0x4F, 79 */
+ MPUREG_EXT_SLV_SENS_DATA_07, /* 0x50, 80 */
+ MPUREG_EXT_SLV_SENS_DATA_08, /* 0x51, 81 */
+ MPUREG_EXT_SLV_SENS_DATA_09, /* 0x52, 82 */
+ MPUREG_EXT_SLV_SENS_DATA_10, /* 0x53, 83 */
+ MPUREG_EXT_SLV_SENS_DATA_11, /* 0x54, 84 */
+ MPUREG_EXT_SLV_SENS_DATA_12, /* 0x55, 85 */
+ MPUREG_EXT_SLV_SENS_DATA_13, /* 0x56, 86 */
+ MPUREG_EXT_SLV_SENS_DATA_14, /* 0x57, 87 */
+ MPUREG_EXT_SLV_SENS_DATA_15, /* 0x58, 88 */
+ MPUREG_EXT_SLV_SENS_DATA_16, /* 0x59, 89 */
+ MPUREG_EXT_SLV_SENS_DATA_17, /* 0x5a, 90 */
+ MPUREG_EXT_SLV_SENS_DATA_18, /* 0x5B, 91 */
+ MPUREG_EXT_SLV_SENS_DATA_19, /* 0x5c, 92 */
+ MPUREG_EXT_SLV_SENS_DATA_20, /* 0x5d, 93 */
+ MPUREG_EXT_SLV_SENS_DATA_21, /* 0x5e, 94 */
+ MPUREG_EXT_SLV_SENS_DATA_22, /* 0x5f, 95 */
+ MPUREG_EXT_SLV_SENS_DATA_23, /* 0x60, 96 */
+ MPUREG_ACCEL_INTEL_STATUS, /* 0x61, 97 */
+ MPUREG_62_RSVD, /* 0x62, 98 */
+ MPUREG_I2C_SLV0_DO, /* 0x63, 99 */
+ MPUREG_I2C_SLV1_DO, /* 0x64, 100 */
+ MPUREG_I2C_SLV2_DO, /* 0x65, 101 */
+ MPUREG_I2C_SLV3_DO, /* 0x66, 102 */
+ MPUREG_I2C_MST_DELAY_CTRL, /* 0x67, 103 */
+ MPUREG_SIGNAL_PATH_RESET, /* 0x68, 104 */
+ MPUREG_ACCEL_INTEL_CTRL, /* 0x69, 105 */
+ MPUREG_USER_CTRL, /* 0x6A, 106 */
+ MPUREG_PWR_MGMT_1, /* 0x6B, 107 */
+ MPUREG_PWR_MGMT_2, /* 0x6C, 108 */
+ MPUREG_BANK_SEL, /* 0x6D, 109 */
+ MPUREG_MEM_START_ADDR, /* 0x6E, 100 */
+ MPUREG_MEM_R_W, /* 0x6F, 111 */
+ MPUREG_DMP_CFG_1, /* 0x70, 112 */
+ MPUREG_DMP_CFG_2, /* 0x71, 113 */
+ MPUREG_FIFO_COUNTH, /* 0x72, 114 */
+ MPUREG_FIFO_COUNTL, /* 0x73, 115 */
+ MPUREG_FIFO_R_W, /* 0x74, 116 */
+ MPUREG_WHOAMI, /* 0x75, 117 */
+
+ NUM_OF_MPU_REGISTERS /* = 0x76, 118 */
+};
+
+/*==== MPU6050B1 MEMORY ====*/
+enum MPU_MEMORY_BANKS {
+ MEM_RAM_BANK_0 = 0,
+ MEM_RAM_BANK_1,
+ MEM_RAM_BANK_2,
+ MEM_RAM_BANK_3,
+ MEM_RAM_BANK_4,
+ MEM_RAM_BANK_5,
+ MEM_RAM_BANK_6,
+ MEM_RAM_BANK_7,
+ MEM_RAM_BANK_8,
+ MEM_RAM_BANK_9,
+ MEM_RAM_BANK_10,
+ MEM_RAM_BANK_11,
+ MPU_MEM_NUM_RAM_BANKS,
+ MPU_MEM_OTP_BANK_0 = 16
+};
+
+
+/*==== MPU6050B1 parameters ====*/
+
+#define NUM_REGS (NUM_OF_MPU_REGISTERS)
+#define START_SENS_REGS (0x3B)
+#define NUM_SENS_REGS (0x60 - START_SENS_REGS + 1)
+
+/*---- MPU Memory ----*/
+#define NUM_BANKS (MPU_MEM_NUM_RAM_BANKS)
+#define BANK_SIZE (256)
+#define MEM_SIZE (NUM_BANKS * BANK_SIZE)
+#define MPU_MEM_BANK_SIZE (BANK_SIZE) /*alternative name */
+
+#define FIFO_HW_SIZE (1024)
+
+#define NUM_EXT_SLAVES (4)
+
+
+/*==== BITS FOR MPU6050B1 ====*/
+/*---- MPU6050B1 'XG_OFFS_TC' register (0, 1, 2) ----*/
+#define BIT_PU_SLEEP_MODE 0x80
+#define BITS_XG_OFFS_TC 0x7E
+#define BIT_OTP_BNK_VLD 0x01
+
+#define BIT_I2C_MST_VDDIO 0x80
+#define BITS_YG_OFFS_TC 0x7E
+#define BITS_ZG_OFFS_TC 0x7E
+/*---- MPU6050B1 'FIFO_EN' register (23) ----*/
+#define BIT_TEMP_OUT 0x80
+#define BIT_GYRO_XOUT 0x40
+#define BIT_GYRO_YOUT 0x20
+#define BIT_GYRO_ZOUT 0x10
+#define BIT_ACCEL 0x08
+#define BIT_SLV_2 0x04
+#define BIT_SLV_1 0x02
+#define BIT_SLV_0 0x01
+/*---- MPU6050B1 'CONFIG' register (1A) ----*/
+/*NONE 0xC0 */
+#define BITS_EXT_SYNC_SET 0x38
+#define BITS_DLPF_CFG 0x07
+/*---- MPU6050B1 'GYRO_CONFIG' register (1B) ----*/
+/* voluntarily modified label from BITS_FS_SEL to
+ * BITS_GYRO_FS_SEL to avoid confusion with MPU
+ */
+#define BITS_GYRO_FS_SEL 0x18
+/*NONE 0x07 */
+/*---- MPU6050B1 'ACCEL_CONFIG' register (1C) ----*/
+#define BITS_ACCEL_FS_SEL 0x18
+#define BITS_ACCEL_HPF 0x07
+/*---- MPU6050B1 'I2C_MST_CTRL' register (24) ----*/
+#define BIT_MULT_MST_EN 0x80
+#define BIT_WAIT_FOR_ES 0x40
+#define BIT_SLV_3_FIFO_EN 0x20
+#define BIT_I2C_MST_PSR 0x10
+#define BITS_I2C_MST_CLK 0x0F
+/*---- MPU6050B1 'I2C_SLV?_ADDR' register (27,2A,2D,30) ----*/
+#define BIT_I2C_READ 0x80
+#define BIT_I2C_WRITE 0x00
+#define BITS_I2C_ADDR 0x7F
+/*---- MPU6050B1 'I2C_SLV?_CTRL' register (27,2A,2D,30) ----*/
+#define BIT_SLV_ENABLE 0x80
+#define BIT_SLV_BYTE_SW 0x40
+#define BIT_SLV_REG_DIS 0x20
+#define BIT_SLV_GRP 0x10
+#define BITS_SLV_LENG 0x0F
+/*---- MPU6050B1 'I2C_SLV4_ADDR' register (31) ----*/
+#define BIT_I2C_SLV4_RNW 0x80
+/*---- MPU6050B1 'I2C_SLV4_CTRL' register (34) ----*/
+#define BIT_I2C_SLV4_EN 0x80
+#define BIT_SLV4_DONE_INT_EN 0x40
+#define BIT_SLV4_REG_DIS 0x20
+#define MASK_I2C_MST_DLY 0x1F
+/*---- MPU6050B1 'I2C_MST_STATUS' register (36) ----*/
+#define BIT_PASS_THROUGH 0x80
+#define BIT_I2C_SLV4_DONE 0x40
+#define BIT_I2C_LOST_ARB 0x20
+#define BIT_I2C_SLV4_NACK 0x10
+#define BIT_I2C_SLV3_NACK 0x08
+#define BIT_I2C_SLV2_NACK 0x04
+#define BIT_I2C_SLV1_NACK 0x02
+#define BIT_I2C_SLV0_NACK 0x01
+/*---- MPU6050B1 'INT_PIN_CFG' register (37) ----*/
+#define BIT_ACTL 0x80
+#define BIT_ACTL_LOW 0x80
+#define BIT_ACTL_HIGH 0x00
+#define BIT_OPEN 0x40
+#define BIT_LATCH_INT_EN 0x20
+#define BIT_INT_ANYRD_2CLEAR 0x10
+#define BIT_ACTL_FSYNC 0x08
+#define BIT_FSYNC_INT_EN 0x04
+#define BIT_BYPASS_EN 0x02
+#define BIT_CLKOUT_EN 0x01
+/*---- MPU6050B1 'INT_ENABLE' register (38) ----*/
+#define BIT_FF_EN 0x80
+#define BIT_MOT_EN 0x40
+#define BIT_ZMOT_EN 0x20
+#define BIT_FIFO_OVERFLOW_EN 0x10
+#define BIT_I2C_MST_INT_EN 0x08
+#define BIT_PLL_RDY_EN 0x04
+#define BIT_DMP_INT_EN 0x02
+#define BIT_RAW_RDY_EN 0x01
+/*---- MPU6050B1 'DMP_INT_STATUS' register (39) ----*/
+/*NONE 0x80 */
+/*NONE 0x40 */
+#define BIT_DMP_INT_5 0x20
+#define BIT_DMP_INT_4 0x10
+#define BIT_DMP_INT_3 0x08
+#define BIT_DMP_INT_2 0x04
+#define BIT_DMP_INT_1 0x02
+#define BIT_DMP_INT_0 0x01
+/*---- MPU6050B1 'INT_STATUS' register (3A) ----*/
+#define BIT_FF_INT 0x80
+#define BIT_MOT_INT 0x40
+#define BIT_ZMOT_INT 0x20
+#define BIT_FIFO_OVERFLOW_INT 0x10
+#define BIT_I2C_MST_INT 0x08
+#define BIT_PLL_RDY_INT 0x04
+#define BIT_DMP_INT 0x02
+#define BIT_RAW_DATA_RDY_INT 0x01
+/*---- MPU6050B1 'MPUREG_I2C_MST_DELAY_CTRL' register (0x67) ----*/
+#define BIT_DELAY_ES_SHADOW 0x80
+#define BIT_SLV4_DLY_EN 0x10
+#define BIT_SLV3_DLY_EN 0x08
+#define BIT_SLV2_DLY_EN 0x04
+#define BIT_SLV1_DLY_EN 0x02
+#define BIT_SLV0_DLY_EN 0x01
+/*---- MPU6050B1 'BANK_SEL' register (6D) ----*/
+#define BIT_PRFTCH_EN 0x40
+#define BIT_CFG_USER_BANK 0x20
+#define BITS_MEM_SEL 0x1f
+/*---- MPU6050B1 'USER_CTRL' register (6A) ----*/
+#define BIT_DMP_EN 0x80
+#define BIT_FIFO_EN 0x40
+#define BIT_I2C_MST_EN 0x20
+#define BIT_I2C_IF_DIS 0x10
+#define BIT_DMP_RST 0x08
+#define BIT_FIFO_RST 0x04
+#define BIT_I2C_MST_RST 0x02
+#define BIT_SIG_COND_RST 0x01
+/*---- MPU6050B1 'PWR_MGMT_1' register (6B) ----*/
+#define BIT_H_RESET 0x80
+#define BIT_SLEEP 0x40
+#define BIT_CYCLE 0x20
+#define BIT_PD_PTAT 0x08
+#define BITS_CLKSEL 0x07
+/*---- MPU6050B1 'PWR_MGMT_2' register (6C) ----*/
+#define BITS_LPA_WAKE_CTRL 0xC0
+#define BITS_LPA_WAKE_1HZ 0x00
+#define BITS_LPA_WAKE_2HZ 0x40
+#define BITS_LPA_WAKE_10HZ 0x80
+#define BITS_LPA_WAKE_40HZ 0xC0
+#define BIT_STBY_XA 0x20
+#define BIT_STBY_YA 0x10
+#define BIT_STBY_ZA 0x08
+#define BIT_STBY_XG 0x04
+#define BIT_STBY_YG 0x02
+#define BIT_STBY_ZG 0x01
+
+#define ACCEL_MOT_THR_LSB (32) /* mg */
+#define ACCEL_MOT_DUR_LSB (1)
+#define ACCEL_ZRMOT_THR_LSB_CONVERSION(mg) ((mg * 1000) / 255)
+#define ACCEL_ZRMOT_DUR_LSB (64)
+
+/*----------------------------------------------------------------------------*/
+/*---- Alternative names to take care of conflicts with current mpu3050.h ----*/
+/*----------------------------------------------------------------------------*/
+
+/*-- registers --*/
+#define MPUREG_DLPF_FS_SYNC MPUREG_CONFIG /* 0x1A */
+
+#define MPUREG_PWR_MGM MPUREG_PWR_MGMT_1 /* 0x6B */
+#define MPUREG_FIFO_EN1 MPUREG_FIFO_EN /* 0x23 */
+#define MPUREG_INT_CFG MPUREG_INT_ENABLE /* 0x38 */
+#define MPUREG_X_OFFS_USRH MPUREG_XG_OFFS_USRH /* 0x13 */
+#define MPUREG_WHO_AM_I MPUREG_WHOAMI /* 0x75 */
+#define MPUREG_23_RSVD MPUREG_EXT_SLV_SENS_DATA_00 /* 0x49 */
+
+/*-- bits --*/
+/* 'USER_CTRL' register */
+#define BIT_AUX_IF_EN BIT_I2C_MST_EN
+#define BIT_AUX_RD_LENG BIT_I2C_MST_EN
+#define BIT_IME_IF_RST BIT_I2C_MST_RST
+#define BIT_GYRO_RST BIT_SIG_COND_RST
+/* 'INT_ENABLE' register */
+#define BIT_RAW_RDY BIT_RAW_DATA_RDY_INT
+#define BIT_MPU_RDY_EN BIT_PLL_RDY_EN
+/* 'INT_STATUS' register */
+#define BIT_INT_STATUS_FIFO_OVERLOW BIT_FIFO_OVERFLOW_INT
+
+/*---- MPU6050 Silicon Revisions ----*/
+#define MPU_SILICON_REV_A2 1 /* MPU6050A2 Device */
+#define MPU_SILICON_REV_B1 2 /* MPU6050B1 Device */
+
+/*---- MPU6050 notable product revisions ----*/
+#define MPU_PRODUCT_KEY_B1_E1_5 105
+#define MPU_PRODUCT_KEY_B2_F1 431
+
+/*---- structure containing control variables used by MLDL ----*/
+/*---- MPU clock source settings ----*/
+/*---- MPU filter selections ----*/
+enum mpu_filter {
+ MPU_FILTER_256HZ_NOLPF2 = 0,
+ MPU_FILTER_188HZ,
+ MPU_FILTER_98HZ,
+ MPU_FILTER_42HZ,
+ MPU_FILTER_20HZ,
+ MPU_FILTER_10HZ,
+ MPU_FILTER_5HZ,
+ MPU_FILTER_2100HZ_NOLPF,
+ NUM_MPU_FILTER
+};
+
+enum mpu_fullscale {
+ MPU_FS_250DPS = 0,
+ MPU_FS_500DPS,
+ MPU_FS_1000DPS,
+ MPU_FS_2000DPS,
+ NUM_MPU_FS
+};
+
+enum mpu_clock_sel {
+ MPU_CLK_SEL_INTERNAL = 0,
+ MPU_CLK_SEL_PLLGYROX,
+ MPU_CLK_SEL_PLLGYROY,
+ MPU_CLK_SEL_PLLGYROZ,
+ MPU_CLK_SEL_PLLEXT32K,
+ MPU_CLK_SEL_PLLEXT19M,
+ MPU_CLK_SEL_RESERVED,
+ MPU_CLK_SEL_STOP,
+ NUM_CLK_SEL
+};
+
+enum mpu_ext_sync {
+ MPU_EXT_SYNC_NONE = 0,
+ MPU_EXT_SYNC_TEMP,
+ MPU_EXT_SYNC_GYROX,
+ MPU_EXT_SYNC_GYROY,
+ MPU_EXT_SYNC_GYROZ,
+ MPU_EXT_SYNC_ACCELX,
+ MPU_EXT_SYNC_ACCELY,
+ MPU_EXT_SYNC_ACCELZ,
+ NUM_MPU_EXT_SYNC
+};
+
+#define MPUREG_CONFIG_VALUE(ext_sync, lpf) \
+ ((ext_sync << 3) | lpf)
+
+#define MPUREG_GYRO_CONFIG_VALUE(x_st, y_st, z_st, full_scale) \
+ ((x_st ? 0x80 : 0) | \
+ (y_st ? 0x70 : 0) | \
+ (z_st ? 0x60 : 0) | \
+ (full_scale << 3))
+
+#endif /* __MPU6050_H_ */
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/io.h>
-#include <linux/gpio.h>
+
#include <linux/mpu.h>
#include "mpuirq.h"
#include "mldl_cfg.h"
dev_info(&mpu_client->adapter->dev,
"Module Param interface = %s\n", interface);
-
- mpuirq_dev_data.irq = gpio_to_irq(mpu_client->irq);
+
+ mpuirq_dev_data.irq = mpu_client->irq;
mpuirq_dev_data.pid = 0;
mpuirq_dev_data.accel_divider = -1;
mpuirq_dev_data.data_ready = 0;
else
flags = IRQF_TRIGGER_RISING;
- flags |= IRQF_SHARED;
- res =
- request_irq(mpuirq_dev_data.irq, mpuirq_handler, flags,
- interface, &mpuirq_dev_data.irq);
+ flags =IRQF_TRIGGER_RISING;//|= IRQF_SHARED;
+
+ res =devm_request_threaded_irq(&mpu_client->dev, mpuirq_dev_data.irq, NULL, mpuirq_handler, flags|IRQF_ONESHOT, interface, &mpuirq_dev_data.irq);
+ //res =
+ // request_irq(mpuirq_dev_data.irq, mpuirq_handler, flags,
+ // interface, &mpuirq_dev_data.irq);
if (res) {
dev_err(&mpu_client->adapter->dev,
"myirqtest: cannot register IRQ %d\n",
data->data.irqtime = (((long long)irqtime.tv_sec) << 32);
data->data.irqtime += irqtime.tv_usec;
data->data.data_type |= 1;
-
+
dev_dbg(data->dev->this_device,
"%s, %lld, %ld\n", __func__, data->data.irqtime,
(unsigned long)data);
"%s current->pid %d, %d, %ld\n",
__func__, current->pid, cmd, arg);
+
if (!data)
return -EFAULT;
COMPASS_ID_AK8975,
COMPASS_ID_AK8972,
+ COMPASS_ID_AK8963,
COMPASS_ID_AMI30X,
COMPASS_ID_AMI306,
COMPASS_ID_YAS529,
COMPASS_ID_LSM303DLH,
COMPASS_ID_LSM303DLM,
COMPASS_ID_MMC314X,
+ COMPASS_ID_MMC328X,
COMPASS_ID_HSCDTD002B,
COMPASS_ID_HSCDTD004A,
* column should have exactly 1 non-zero value.
*/
struct mpu_platform_data {
- __u8 int_config;
- __u8 level_shifter;
+ __u32 int_config;
+ __u32 level_shifter;
__s8 orientation[GYRO_NUM_AXES * GYRO_NUM_AXES];
};