on 977 add mpu config and update mpu code

This commit is contained in:
ywj
2014-04-04 10:52:17 +08:00
parent 8b8c76a7ab
commit 68b6dfca6b
58 changed files with 3137 additions and 479 deletions

View File

@@ -303,7 +303,7 @@
compatible = "nxp,pcf8563";
reg = <0x51>;
};
/*
sensor@1d {
compatible = "gs_mma8452";
reg = <0x1d>;
@@ -312,7 +312,9 @@
irq_enable = <1>;
poll_delay_ms = <30>;
layout = <8>;
status = "disabled";
};
sensor@0d {
compatible = "ak8975";
reg = <0x0d>;
@@ -321,7 +323,9 @@
irq_enable = <1>;
poll_delay_ms = <30>;
layout = <1>;
status = "disabled";
};
*/
sensor@10 {
compatible = "ls_cm3218";
reg = <0x10>;
@@ -331,7 +335,45 @@
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 {

1
drivers/misc/Kconfig Normal file → Executable file
View File

@@ -534,6 +534,7 @@ config SRAM
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"

1
drivers/misc/Makefile Normal file → Executable file
View File

@@ -53,4 +53,5 @@ obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
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

1
drivers/misc/inv_mpu/Kconfig Normal file → Executable file
View File

@@ -9,6 +9,7 @@ config MPU_SENSORS_TIMERIRQ
menuconfig: INV_SENSORS
tristate "Motion Processing Unit"
depends on I2C
default n
if INV_SENSORS

0
drivers/misc/inv_mpu/Makefile Normal file → Executable file
View File

0
drivers/misc/inv_mpu/README Normal file → Executable file
View File

0
drivers/misc/inv_mpu/accel/Kconfig Normal file → Executable file
View File

0
drivers/misc/inv_mpu/accel/Makefile Normal file → Executable file
View File

0
drivers/misc/inv_mpu/accel/adxl34x.c Normal file → Executable file
View File

4
drivers/misc/inv_mpu/accel/bma150.c Normal file → Executable file
View File

@@ -25,7 +25,7 @@
* @file bma150.c
* @brief Accelerometer setup and handling methods for Bosch BMA150.
*/
#define DEBUG
/* -------------------------------------------------------------------------- */
#include <linux/i2c.h>
#include <linux/module.h>
@@ -671,7 +671,7 @@ static int bma150_mod_probe(struct i2c_client *client,
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;

16
drivers/misc/inv_mpu/accel/bma222.c Normal file → Executable file
View File

@@ -51,8 +51,6 @@
#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)
@@ -337,8 +335,6 @@ static int bma222_get_config(void *mlsl_handle,
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;
};
@@ -394,8 +390,6 @@ static int bma222_config(void *mlsl_handle,
*((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;
};
@@ -512,18 +506,14 @@ static int bma222_read(void *mlsl_handle,
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 = {
@@ -565,7 +555,7 @@ static int bma222_mod_probe(struct i2c_client *client,
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)) {

0
drivers/misc/inv_mpu/accel/bma250.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/accel/cma3000.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/accel/kxsd9.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/accel/lis331.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/accel/lis3dh.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/accel/lsm303dlx_a.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/accel/mma8450.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/accel/mma845x.c Normal file → Executable file
View File

View File

@@ -0,0 +1,699 @@
/*
$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, &reg);
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, &reg);
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, &reg);
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, &reg);
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;
}
/**
* @}
*/

0
drivers/misc/inv_mpu/accel/mpu6050.h Normal file → Executable file
View File

9
drivers/misc/inv_mpu/compass/Kconfig Normal file → Executable file
View File

@@ -18,6 +18,15 @@ config MPU_SENSORS_AK8975
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

2
drivers/misc/inv_mpu/compass/Makefile Normal file → Executable file
View File

@@ -31,6 +31,8 @@ inv_mpu_hscdtd004a-objs += hscdtd004a.o
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

View File

@@ -0,0 +1,648 @@
/*
$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 = &regs[0];
unsigned char *stat2 = &regs[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, &regs[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");
/**
* @}
*/

0
drivers/misc/inv_mpu/compass/ak8972.c Normal file → Executable file
View File

View File

@@ -27,7 +27,6 @@
*/
/* -------------------------------------------------------------------------- */
#define DEBUG
#include <linux/i2c.h>
#include <linux/module.h>
@@ -68,6 +67,8 @@ struct ak8975_private_data {
struct ak8975_config init;
};
struct ext_slave_platform_data ak8975_data;
/* -------------------------------------------------------------------------- */
static int ak8975_init(void *mlsl_handle,
struct ext_slave_descr *slave,
@@ -82,7 +83,7 @@ static int ak8975_init(void *mlsl_handle,
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);
@@ -100,7 +101,7 @@ static int ak8975_init(void *mlsl_handle,
LOG_RESULT_LOCATION(result);
return result;
}
#endif
/* Wait at least 200us */
udelay(200);
@@ -117,7 +118,7 @@ static int ak8975_init(void *mlsl_handle,
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);
@@ -125,7 +126,7 @@ static int ak8975_init(void *mlsl_handle,
LOG_RESULT_LOCATION(result);
return result;
}
#endif
udelay(100);
return INV_SUCCESS;
}
@@ -390,21 +391,139 @@ struct ak8975_mod_private_data {
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);
@@ -461,6 +580,11 @@ static const struct i2c_device_id ak8975_mod_id[] = {
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,
@@ -469,6 +593,7 @@ static struct i2c_driver ak8975_mod_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "ak8975_mod",
.of_match_table = of_mpu_ak8975_match,
},
.address_list = normal_i2c,
};

0
drivers/misc/inv_mpu/compass/ami306.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/compass/ami30x.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/compass/ami_hw.h Normal file → Executable file
View File

0
drivers/misc/inv_mpu/compass/ami_sensor_def.h Normal file → Executable file
View File

0
drivers/misc/inv_mpu/compass/hmc5883.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/compass/hscdtd002b.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/compass/hscdtd004a.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/compass/lsm303dlx_m.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/compass/mmc314x.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/compass/yas529-kernel.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/compass/yas530.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/log.h Normal file → Executable file
View File

File diff suppressed because it is too large Load Diff

2
drivers/misc/inv_mpu/mldl_cfg.h Normal file → Executable file
View File

@@ -31,7 +31,7 @@
#include "mltypes.h"
#include "mlsl.h"
#include <linux/mpu.h>
#include "mpu3050.h"
#include "mpu6050b1.h"
#include "log.h"

21
drivers/misc/inv_mpu/mldl_print_cfg.c Normal file → Executable file
View File

@@ -50,16 +50,16 @@ void mldl_print_cfg(struct mldl_cfg *mldl_cfg)
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]);
@@ -75,6 +75,7 @@ void mldl_print_cfg(struct mldl_cfg *mldl_cfg)
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",

0
drivers/misc/inv_mpu/mldl_print_cfg.h Normal file → Executable file
View File

View File

@@ -20,7 +20,7 @@
#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,
@@ -42,13 +42,13 @@ 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,
@@ -87,13 +87,13 @@ static int inv_i2c_read(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,

0
drivers/misc/inv_mpu/mlsl.h Normal file → Executable file
View File

0
drivers/misc/inv_mpu/mltypes.h Normal file → Executable file
View File

View File

@@ -16,7 +16,6 @@
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>
@@ -50,6 +49,66 @@
#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 {
@@ -77,8 +136,8 @@ 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)
{
@@ -135,7 +194,7 @@ static int mpu_pm_notifier_callback(struct notifier_block *nb,
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;
@@ -148,7 +207,6 @@ static int mpu_dev_open(struct inode *inode, struct file *file)
return -EBUSY;
}
mpu->pid = current->pid;
file->private_data = &mpu->dev;
/* Reset the sensors to the default */
if (result) {
@@ -356,19 +414,24 @@ static int inv_mpu_get_config(struct mldl_cfg *mldl_cfg,
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;
@@ -380,6 +443,7 @@ static int inv_mpu_get_config(struct mldl_cfg *mldl_cfg,
retval = copy_to_user((unsigned char __user *)user_data,
config.data, config.len);
kfree(config.data);
return retval;
}
@@ -465,6 +529,55 @@ static int slave_get_config(struct mldl_cfg *mldl_cfg,
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,
@@ -561,6 +674,125 @@ static int mpu_handle_mlsl(void *sl_handle,
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,
@@ -584,15 +816,16 @@ 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(
@@ -659,7 +892,7 @@ static long mpu_dev_ioctl(struct file *file,
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],
@@ -709,6 +942,7 @@ static long mpu_dev_ioctl(struct file *file,
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],
@@ -716,6 +950,7 @@ static long mpu_dev_ioctl(struct file *file,
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(
@@ -777,9 +1012,8 @@ static long mpu_dev_ioctl(struct file *file,
};
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;
@@ -890,13 +1124,7 @@ static const struct file_operations mpu_fops = {
.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,
};
@@ -943,7 +1171,7 @@ int inv_mpu_register_slave(struct module *slave_module,
}
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,
@@ -980,12 +1208,35 @@ int inv_mpu_register_slave(struct module *slave_module,
}
}
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);
@@ -998,14 +1249,14 @@ out_unlock_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;
@@ -1052,6 +1303,130 @@ void inv_mpu_unregister_slave(struct i2c_client *slave_client,
}
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[] = {
@@ -1069,6 +1444,12 @@ int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
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++);
@@ -1082,6 +1463,12 @@ int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
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;
@@ -1098,7 +1485,6 @@ int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
}
mpu_private_data = mpu;
i2c_set_clientdata(client, mpu);
this_client = client;
mpu->client = client;
init_waitqueue_head(&mpu->mpu_event_wait);
@@ -1118,13 +1504,11 @@ int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
"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);
@@ -1156,8 +1540,34 @@ int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
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:
@@ -1201,6 +1611,17 @@ static int mpu_remove(struct i2c_client *client)
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();
@@ -1215,6 +1636,11 @@ static int mpu_remove(struct i2c_client *client)
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,
@@ -1223,6 +1649,7 @@ static struct i2c_driver mpu_driver = {
.driver = {
.owner = THIS_MODULE,
.name = MPU_NAME,
.of_match_table = of_mpu_match,
},
.address_list = normal_i2c,
.shutdown = mpu_shutdown, /* optional */
@@ -1230,11 +1657,87 @@ static struct i2c_driver mpu_driver = {
.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;

0
drivers/misc/inv_mpu/mpu-dev.h Normal file → Executable file
View File

0
drivers/misc/inv_mpu/mpu3050.h Normal file → Executable file
View File

435
drivers/misc/inv_mpu/mpu6050b1.h Executable file
View File

@@ -0,0 +1,435 @@
/*
$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_ */

View File

@@ -36,7 +36,7 @@
#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"
@@ -202,8 +202,8 @@ int mpuirq_init(struct i2c_client *mpu_client, struct mldl_cfg *mldl_cfg)
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;
@@ -217,10 +217,12 @@ int mpuirq_init(struct i2c_client *mpu_client, struct mldl_cfg *mldl_cfg)
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",

0
drivers/misc/inv_mpu/mpuirq.h Normal file → Executable file
View File

0
drivers/misc/inv_mpu/pressure/Kconfig Normal file → Executable file
View File

0
drivers/misc/inv_mpu/pressure/Makefile Normal file → Executable file
View File

0
drivers/misc/inv_mpu/pressure/bma085.c Normal file → Executable file
View File

0
drivers/misc/inv_mpu/slaveirq.h Normal file → Executable file
View File

View File

@@ -71,7 +71,7 @@ static void timerirq_handler(unsigned long arg)
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);
@@ -207,6 +207,7 @@ static long timerirq_ioctl(struct file *file,
"%s current->pid %d, %d, %ld\n",
__func__, current->pid, cmd, arg);
if (!data)
return -EFAULT;

0
drivers/misc/inv_mpu/timerirq.h Normal file → Executable file
View File

View File

@@ -153,6 +153,7 @@ enum ext_slave_id {
COMPASS_ID_AK8975,
COMPASS_ID_AK8972,
COMPASS_ID_AK8963,
COMPASS_ID_AMI30X,
COMPASS_ID_AMI306,
COMPASS_ID_YAS529,
@@ -161,6 +162,7 @@ enum ext_slave_id {
COMPASS_ID_LSM303DLH,
COMPASS_ID_LSM303DLM,
COMPASS_ID_MMC314X,
COMPASS_ID_MMC328X,
COMPASS_ID_HSCDTD002B,
COMPASS_ID_HSCDTD004A,
@@ -300,8 +302,8 @@ struct ext_slave_descr {
* 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];
};