From 1495c383330d098039a56fb0aa3f765bd3a21b6e Mon Sep 17 00:00:00 2001 From: liuji Date: Tue, 9 Aug 2011 00:53:25 +0800 Subject: [PATCH] mod/add: add mpu support --- arch/arm/mach-rk29/board-rk29-ddr3sdk.c | 59 +- arch/arm/mach-rk29/board-rk29sdk.c | 60 +- drivers/misc/mpu3050/Kconfig | 401 +++++---- drivers/misc/mpu3050/Makefile | 249 +++--- drivers/misc/mpu3050/README | 38 +- drivers/misc/mpu3050/accel/adxl346.c | 21 +- drivers/misc/mpu3050/accel/bma150.c | 23 +- drivers/misc/mpu3050/accel/bma222.c | 21 +- drivers/misc/mpu3050/accel/cma3000.c | 20 +- drivers/misc/mpu3050/accel/kxsd9.c | 22 +- drivers/misc/mpu3050/accel/kxtf9.c | 603 ++++++++++++- drivers/misc/mpu3050/accel/lis331.c | 394 +++++++-- drivers/misc/mpu3050/accel/lis3dh.c | 624 ++++++++++++++ drivers/misc/mpu3050/accel/lsm303a.c | 21 +- drivers/misc/mpu3050/accel/mantis.c | 229 ++++- drivers/misc/mpu3050/accel/mma8450.c | 31 +- drivers/misc/mpu3050/accel/mma845x.c | 158 ++++ drivers/misc/mpu3050/compass/ak8975.c | 88 +- drivers/misc/mpu3050/compass/ami306.c | 191 ++++ drivers/misc/mpu3050/compass/ami30x.c | 16 +- drivers/misc/mpu3050/compass/hmc5883.c | 16 +- drivers/misc/mpu3050/compass/hscdtd002b.c | 163 ++++ drivers/misc/mpu3050/compass/hscdtd004a.c | 162 ++++ drivers/misc/mpu3050/compass/lsm303m.c | 16 +- drivers/misc/mpu3050/compass/mmc314x.c | 16 +- drivers/misc/mpu3050/compass/yas529-kernel.c | 16 +- drivers/misc/mpu3050/compass/yas530-kernel.c | 163 ++++ drivers/misc/mpu3050/compass/yas530.c | 406 +++++++++ drivers/misc/mpu3050/log.h | 116 +-- drivers/misc/mpu3050/mldl_cfg.c | 217 +++-- drivers/misc/mpu3050/mldl_cfg.h | 26 +- drivers/misc/mpu3050/mlos-kernel.c | 15 +- drivers/misc/mpu3050/mlos.h | 15 +- drivers/misc/mpu3050/mlsl-kernel.c | 25 +- drivers/misc/mpu3050/mlsl.h | 15 +- drivers/misc/mpu3050/mltypes.h | 37 +- drivers/misc/mpu3050/mpu-dev.c | 861 ++++++++++--------- drivers/misc/mpu3050/mpu-i2c.c | 29 +- drivers/misc/mpu3050/mpu-i2c.h | 15 +- drivers/misc/mpu3050/mpuirq.c | 77 +- drivers/misc/mpu3050/mpuirq.h | 29 +- drivers/misc/mpu3050/slaveirq.c | 69 +- drivers/misc/mpu3050/slaveirq.h | 24 +- drivers/misc/mpu3050/timerirq.c | 299 +++++++ drivers/misc/mpu3050/timerirq.h | 30 + include/linux/mpu.h | 240 ++++-- include/linux/mpu3050.h | 17 +- include/linux/mpu6000.h | 194 +++-- 48 files changed, 5279 insertions(+), 1298 deletions(-) mode change 100644 => 100755 drivers/misc/mpu3050/Kconfig mode change 100644 => 100755 drivers/misc/mpu3050/Makefile mode change 100644 => 100755 drivers/misc/mpu3050/README mode change 100644 => 100755 drivers/misc/mpu3050/accel/adxl346.c mode change 100644 => 100755 drivers/misc/mpu3050/accel/bma150.c mode change 100644 => 100755 drivers/misc/mpu3050/accel/bma222.c mode change 100644 => 100755 drivers/misc/mpu3050/accel/cma3000.c mode change 100644 => 100755 drivers/misc/mpu3050/accel/kxsd9.c mode change 100644 => 100755 drivers/misc/mpu3050/accel/kxtf9.c mode change 100644 => 100755 drivers/misc/mpu3050/accel/lis331.c create mode 100755 drivers/misc/mpu3050/accel/lis3dh.c mode change 100644 => 100755 drivers/misc/mpu3050/accel/lsm303a.c mode change 100644 => 100755 drivers/misc/mpu3050/accel/mantis.c mode change 100644 => 100755 drivers/misc/mpu3050/accel/mma8450.c create mode 100755 drivers/misc/mpu3050/accel/mma845x.c mode change 100644 => 100755 drivers/misc/mpu3050/compass/ak8975.c create mode 100755 drivers/misc/mpu3050/compass/ami306.c mode change 100644 => 100755 drivers/misc/mpu3050/compass/ami30x.c mode change 100644 => 100755 drivers/misc/mpu3050/compass/hmc5883.c create mode 100755 drivers/misc/mpu3050/compass/hscdtd002b.c create mode 100755 drivers/misc/mpu3050/compass/hscdtd004a.c mode change 100644 => 100755 drivers/misc/mpu3050/compass/lsm303m.c mode change 100644 => 100755 drivers/misc/mpu3050/compass/mmc314x.c mode change 100644 => 100755 drivers/misc/mpu3050/compass/yas529-kernel.c create mode 100755 drivers/misc/mpu3050/compass/yas530-kernel.c create mode 100755 drivers/misc/mpu3050/compass/yas530.c mode change 100644 => 100755 drivers/misc/mpu3050/log.h mode change 100644 => 100755 drivers/misc/mpu3050/mldl_cfg.c mode change 100644 => 100755 drivers/misc/mpu3050/mldl_cfg.h mode change 100644 => 100755 drivers/misc/mpu3050/mlos-kernel.c mode change 100644 => 100755 drivers/misc/mpu3050/mlos.h mode change 100644 => 100755 drivers/misc/mpu3050/mlsl-kernel.c mode change 100644 => 100755 drivers/misc/mpu3050/mlsl.h mode change 100644 => 100755 drivers/misc/mpu3050/mltypes.h mode change 100644 => 100755 drivers/misc/mpu3050/mpu-dev.c mode change 100644 => 100755 drivers/misc/mpu3050/mpu-i2c.c mode change 100644 => 100755 drivers/misc/mpu3050/mpu-i2c.h mode change 100644 => 100755 drivers/misc/mpu3050/mpuirq.c mode change 100644 => 100755 drivers/misc/mpu3050/mpuirq.h mode change 100644 => 100755 drivers/misc/mpu3050/slaveirq.c mode change 100644 => 100755 drivers/misc/mpu3050/slaveirq.h create mode 100755 drivers/misc/mpu3050/timerirq.c create mode 100755 drivers/misc/mpu3050/timerirq.h mode change 100644 => 100755 include/linux/mpu.h mode change 100644 => 100755 include/linux/mpu3050.h mode change 100644 => 100755 include/linux/mpu6000.h diff --git a/arch/arm/mach-rk29/board-rk29-ddr3sdk.c b/arch/arm/mach-rk29/board-rk29-ddr3sdk.c index 6ffc986a3cdb..f4e883fa9fee 100755 --- a/arch/arm/mach-rk29/board-rk29-ddr3sdk.c +++ b/arch/arm/mach-rk29/board-rk29-ddr3sdk.c @@ -497,7 +497,55 @@ static struct mma8452_platform_data mma8452_info = { }; #endif - +#if defined (CONFIG_MPU_SENSORS_MPU3050) +/*mpu3050*/ +static struct mpu3050_platform_data mpu3050_data = { + .int_config = 0x10, + //.orientation = { 1, 0, 0,0, -1, 0,0, 0, 1 }, + //.orientation = { 0, 1, 0,-1, 0, 0,0, 0, -1 }, + //.orientation = { -1, 0, 0,0, -1, 0,0, 0, -1 }, + .orientation = { 0, 1, 0, -1, 0, 0, 0, 0, 1 }, + .level_shifter = 0, +#if defined (CONFIG_MPU_SENSORS_KXTF9) + .accel = { +#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE + .get_slave_descr = NULL , +#else + .get_slave_descr = get_accel_slave_descr , +#endif + .adapt_num = 0, // The i2c bus to which the mpu device is + // connected + //.irq = RK29_PIN0_PA3, + .bus = EXT_SLAVE_BUS_SECONDARY, //The secondary I2C of MPU + .address = 0x0f, + //.orientation = { 1, 0, 0,0, 1, 0,0, 0, 1 }, + //.orientation = { 0, -1, 0,-1, 0, 0,0, 0, -1 }, + //.orientation = { 0, 1, 0,1, 0, 0,0, 0, -1 }, + .orientation = { 0, 1 ,0, -1 ,0, 0, 0, 0, 1 }, + }, +#endif +#if defined (CONFIG_MPU_SENSORS_AK8975) + .compass = { +#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE + .get_slave_descr = NULL,/*ak5883_get_slave_descr,*/ +#else + .get_slave_descr = get_compass_slave_descr, +#endif + .adapt_num = 0, // The i2c bus to which the compass device is. + // It can be difference with mpu + // connected + //.irq = RK29_PIN0_PA4, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0d, + //.orientation = { -1, 0, 0,0, -1, 0,0, 0, 1 }, + //.orientation = { 0, -1, 0,-1, 0, 0,0, 0, -1 }, + //.orientation = { 0, 1, 0,1, 0, 0,0, 0, -1 }, + //.orientation = { 0, -1, 0, 1, 0, 0, 0, 0, 1 }, + .orientation = { 0, 1, 0, -1, 0, 0, 0, 0, 1 }, + }, +}; +#endif +#endif #if defined (CONFIG_BATTERY_BQ27510) #define DC_CHECK_PIN RK29_PIN4_PA1 #define LI_LION_BAT_NUM 2 @@ -730,6 +778,15 @@ static struct i2c_board_info __initdata board_i2c0_devices[] = { .irq = RK29_PIN0_PA4, }, #endif +#if defined (CONFIG_MPU_SENSORS_MPU3050) + { + .type = "mpu3050", + .addr = 0x68, + .flags = 0, + .irq = RK29_PIN5_PA3, + .platform_data = &mpu3050_data, + }, +#endif }; #endif diff --git a/arch/arm/mach-rk29/board-rk29sdk.c b/arch/arm/mach-rk29/board-rk29sdk.c index 9c354ef55c2b..064441f203b5 100755 --- a/arch/arm/mach-rk29/board-rk29sdk.c +++ b/arch/arm/mach-rk29/board-rk29sdk.c @@ -502,7 +502,55 @@ static struct mma8452_platform_data mma8452_info = { }; #endif - +#if defined (CONFIG_MPU_SENSORS_MPU3050) +/*mpu3050*/ +static struct mpu3050_platform_data mpu3050_data = { + .int_config = 0x10, + //.orientation = { 1, 0, 0,0, -1, 0,0, 0, 1 }, + //.orientation = { 0, 1, 0,-1, 0, 0,0, 0, -1 }, + //.orientation = { -1, 0, 0,0, -1, 0,0, 0, -1 }, + .orientation = { 0, 1, 0, -1, 0, 0, 0, 0, 1 }, + .level_shifter = 0, +#if defined (CONFIG_MPU_SENSORS_KXTF9) + .accel = { +#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE + .get_slave_descr = NULL , +#else + .get_slave_descr = get_accel_slave_descr , +#endif + .adapt_num = 0, // The i2c bus to which the mpu device is + // connected + //.irq = RK29_PIN0_PA3, + .bus = EXT_SLAVE_BUS_SECONDARY, //The secondary I2C of MPU + .address = 0x0f, + //.orientation = { 1, 0, 0,0, 1, 0,0, 0, 1 }, + //.orientation = { 0, -1, 0,-1, 0, 0,0, 0, -1 }, + //.orientation = { 0, 1, 0,1, 0, 0,0, 0, -1 }, + .orientation = { 0, 1 ,0, -1 ,0, 0, 0, 0, 1 }, + }, +#endif +#if defined (CONFIG_MPU_SENSORS_AK8975) + .compass = { +#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE + .get_slave_descr = NULL,/*ak5883_get_slave_descr,*/ +#else + .get_slave_descr = get_compass_slave_descr, +#endif + .adapt_num = 0, // The i2c bus to which the compass device is. + // It can be difference with mpu + // connected + //.irq = RK29_PIN0_PA4, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0d, + //.orientation = { -1, 0, 0,0, -1, 0,0, 0, 1 }, + //.orientation = { 0, -1, 0,-1, 0, 0,0, 0, -1 }, + //.orientation = { 0, 1, 0,1, 0, 0,0, 0, -1 }, + //.orientation = { 0, -1, 0, 1, 0, 0, 0, 0, 1 }, + .orientation = { 0, 1, 0, -1, 0, 0, 0, 0, 1 }, + }, +}; +#endif +#endif #if defined (CONFIG_BATTERY_BQ27510) #define DC_CHECK_PIN RK29_PIN4_PA1 #define LI_LION_BAT_NUM 2 @@ -735,6 +783,16 @@ static struct i2c_board_info __initdata board_i2c0_devices[] = { .irq = RK29_PIN0_PA4, }, #endif +/*mpu3050*/ +#if defined (CONFIG_MPU_SENSORS_MPU3050) + { + .type = "mpu3050", + .addr = 0x68, + .flags = 0, + .irq = RK29_PIN5_PA3, + .platform_data = &mpu3050_data, + }, +#endif }; #endif diff --git a/drivers/misc/mpu3050/Kconfig b/drivers/misc/mpu3050/Kconfig old mode 100644 new mode 100755 index 69ee20209c38..210953f35095 --- a/drivers/misc/mpu3050/Kconfig +++ b/drivers/misc/mpu3050/Kconfig @@ -1,188 +1,213 @@ - -menu "Motion Sensors Support" - -choice - tristate "Motion Processing Unit" - depends on I2C - default MPU_NONE - -config MPU_NONE - bool "None" - help - This disables support for motion processing using the MPU family of - motion processing units. - -config SENSORS_MPU3050 - tristate "MPU3050" - depends on I2C - help - If you say yes here you get support for the MPU3050 Gyroscope driver - This driver can also be built as a module. If so, the module - will be called mpu3050. - -config SENSORS_MPU6000 - tristate "MPU6000" - depends on I2C - help - If you say yes here you get support for the MPU6000 Gyroscope driver - This driver can also be built as a module. If so, the module - will be called mpu6000. - -endchoice - -choice - prompt "Accelerometer Type" - depends on SENSORS_MPU3050 - default SENSORS_BMA150 - -config SENSORS_ACCELEROMETER_NONE - bool "NONE" - depends on SENSORS_MPU3050 || SENSORS_MPU6000 - help - This disables accelerometer support for the MPU3050 - -config SENSORS_ADXL346 - bool "ADI adxl346" - depends on SENSORS_MPU3050 - help - This enables support for the ADI adxl346 accelerometer - -config SENSORS_BMA150 - bool "Bosch BMA150" - depends on SENSORS_MPU3050 - help - This enables support for the Bosch BMA150 accelerometer - -config SENSORS_BMA222 - bool "Bosch BMA222" - depends on SENSORS_MPU3050 - help - This enables support for the Bosch BMA222 accelerometer - -config SENSORS_KXSD9 - bool "Kionix KXSD9" - depends on SENSORS_MPU3050 - help - This enables support for the Kionix KXSD9 accelerometer - -config SENSORS_KXTF9 - bool "Kionix KXTF9" - depends on SENSORS_MPU3050 - help - This enables support for the Kionix KXFT9 accelerometer - -config SENSORS_LIS331DLH - bool "ST lis331dlh" - depends on SENSORS_MPU3050 - help - This enables support for the ST lis331dlh accelerometer - -config SENSORS_LSM303DLHA - bool "ST lsm303dlh" - depends on SENSORS_MPU3050 - help - This enables support for the ST lsm303dlh accelerometer - -config SENSORS_MMA8450 - bool "Freescale mma8450" - depends on SENSORS_MPU3050 - help - This enables support for the Freescale mma8450 accelerometer - -config SENSORS_MMA8451 - bool "Freescale mma8451" - depends on SENSORS_MPU3050 - help - This enables support for the Freescale mma8451 accelerometer - -endchoice - -choice - prompt "Compass Type" - depends on SENSORS_MPU6000 || SENSORS_MPU3050 - default SENSORS_AK8975 - -config SENSORS_COMPASS_NONE - bool "NONE" - depends on SENSORS_MPU6000 || SENSORS_MPU3050 - help - This disables compass support for the MPU6000 - -config SENSORS_AK8975 - bool "AKM ak8975" - depends on SENSORS_MPU6000 || SENSORS_MPU3050 - help - This enables support for the AKM ak8975 compass - -config SENSORS_MMC314X - bool "MEMSIC mmc314x" - depends on SENSORS_MPU3050 - help - This enables support for the MEMSIC mmc314x compass - -config SENSORS_AMI30X - bool "Aichi Steel ami30X" - depends on SENSORS_MPU3050 - help - This enables support for the Aichi Steel ami304/ami305 compass - -config SENSORS_HMC5883 - bool "Honeywell hmc5883" - depends on SENSORS_MPU3050 - help - This enables support for the Honeywell hmc5883 compass - -config SENSORS_LSM303DLHM - bool "ST lsm303dlh" - depends on SENSORS_MPU3050 - help - This enables support for the ST lsm303dlh compass - -config SENSORS_MMC314X - bool "MEMSIC mmc314xMS" - depends on SENSORS_MPU3050 - help - This enables support for the MEMSIC mmc314xMS compass - -config SENSORS_YAS529 - bool "Yamaha yas529" - depends on SENSORS_MPU3050 - help - This enables support for the Yamaha yas529 compass - -config SENSORS_HSCDTD00XX - bool "Alps hscdtd00XX" - depends on SENSORS_MPU3050 - help - This enables support for the Alps hscdtd002b/hscdtd004a compass - -endchoice - -choice - prompt "Pressure Type" - depends on SENSORS_MPU6000 || SENSORS_MPU3050 - default SENSORS_BMA085 - -config SENSORS_PRESSURE_NONE - bool "NONE" - depends on SENSORS_MPU6000 || SENSORS_MPU3050 - help - This disables pressure sensor support for the MPU6000 - -config SENSORS_BMA085 - bool "Bosch BMA085" - depends on SENSORS_MPU6000 || SENSORS_MPU3050 - help - This enables support for the Bosch bma085 pressure sensor - -endchoice - -config SENSORS_MPU_DEBUG - bool "MPU debug" - depends on SENSORS_MPU3050 || SENSORS_MPU6000 - help - If you say yes here you get extra debug messages from the MPU3050 - and other slave sensors. - -endmenu - + +menu "Motion Sensors Support" + +choice + tristate "Motion Processing Unit" + depends on I2C + default MPU_NONE + +config MPU_NONE + bool "None" + help + This disables support for motion processing using the MPU family of + motion processing units. + +config MPU_SENSORS_MPU3050 + tristate "MPU3050" + depends on I2C + help + If you say yes here you get support for the MPU3050 Gyroscope driver + This driver can also be built as a module. If so, the module + will be called mpu3050. + +config MPU_SENSORS_MPU6000 + tristate "MPU6000" + depends on I2C + help + If you say yes here you get support for the MPU6000 Gyroscope driver + This driver can also be built as a module. If so, the module + will be called mpu6000. + +endchoice + +choice + prompt "Accelerometer Type" + depends on MPU_SENSORS_MPU3050 + default MPU_SENSORS_BMA150 + +config MPU_SENSORS_ACCELEROMETER_NONE + bool "NONE" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6000 + help + This disables accelerometer support for the MPU3050 + +config MPU_SENSORS_ADXL346 + bool "ADI adxl346" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the ADI adxl346 accelerometer + +config MPU_SENSORS_BMA150 + bool "Bosch BMA150" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Bosch BMA150 accelerometer + +config MPU_SENSORS_BMA222 + bool "Bosch BMA222" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Bosch BMA222 accelerometer + +config MPU_SENSORS_KXSD9 + bool "Kionix KXSD9" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Kionix KXSD9 accelerometer + +config MPU_SENSORS_KXTF9 + bool "Kionix KXTF9" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Kionix KXFT9 accelerometer + +config MPU_SENSORS_LIS331DLH + bool "ST lis331dlh" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the ST lis331dlh accelerometer + +config MPU_SENSORS_LIS3DH + bool "ST lis3dh" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the ST lis3dh accelerometer + +config MPU_SENSORS_LSM303DLHA + bool "ST lsm303dlh" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the ST lsm303dlh accelerometer + +config MPU_SENSORS_MMA8450 + bool "Freescale mma8450" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Freescale mma8450 accelerometer + +config MPU_SENSORS_MMA845X + bool "Freescale mma8451/8452/8453" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Freescale mma8451/8452/8453 accelerometer + +endchoice + +choice + prompt "Compass Type" + depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 + default MPU_SENSORS_AK8975 + +config MPU_SENSORS_COMPASS_NONE + bool "NONE" + depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 + help + This disables compass support for the MPU6000 + +config MPU_SENSORS_AK8975 + bool "AKM ak8975" + depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 + help + This enables support for the AKM ak8975 compass + +config MPU_SENSORS_MMC314X + bool "MEMSIC mmc314x" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the MEMSIC mmc314x compass + +config MPU_SENSORS_AMI30X + bool "Aichi Steel ami30X" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Aichi Steel ami304/ami305 compass + +config MPU_SENSORS_AMI306 + bool "Aichi Steel ami306" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Aichi Steel ami306 compass + +config MPU_SENSORS_HMC5883 + bool "Honeywell hmc5883" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Honeywell hmc5883 compass + +config MPU_SENSORS_LSM303DLHM + bool "ST lsm303dlh" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the ST lsm303dlh compass + +config MPU_SENSORS_MMC314X + bool "MEMSIC mmc314xMS" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the MEMSIC mmc314xMS compass + +config MPU_SENSORS_YAS529 + bool "Yamaha yas529" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Yamaha yas529 compass + +config MPU_SENSORS_YAS530 + bool "Yamaha yas530" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Yamaha yas530 compass + +config MPU_SENSORS_HSCDTD002B + bool "Alps hscdtd002b" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Alps hscdtd002b compass + +config MPU_SENSORS_HSCDTD004A + bool "Alps hscdtd004a" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Alps hscdtd004a compass + +endchoice + +choice + prompt "Pressure Type" + depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 + default MPU_SENSORS_BMA085 + +config MPU_SENSORS_PRESSURE_NONE + bool "NONE" + depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 + help + This disables pressure sensor support for the MPU6000 + +config MPU_SENSORS_BMA085 + bool "Bosch BMA085" + depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 + help + This enables support for the Bosch bma085 pressure sensor + +endchoice + +config MPU_SENSORS_TIMERIRQ + tristate "Timer IRQ" + help + If you say yes here you get access to the timerirq device handle which + can be used to select on. This can be used instead of IRQ's, sleeping, + or timer threads. Reading from this device returns the same type of + information as reading from the MPU and slave IRQ's. + +endmenu + diff --git a/drivers/misc/mpu3050/Makefile b/drivers/misc/mpu3050/Makefile old mode 100644 new mode 100755 index 5114e43db83c..935915ad01dc --- a/drivers/misc/mpu3050/Makefile +++ b/drivers/misc/mpu3050/Makefile @@ -1,117 +1,132 @@ - -# Kernel makefile for motions sensors -# -# - -# MPU -obj-$(CONFIG_SENSORS_MPU3050) += mpu3050.o -mpu3050-objs += mpuirq.o \ - slaveirq.o \ - mpu-dev.o \ - mpu-i2c.o \ - mlsl-kernel.o \ - mlos-kernel.o \ - $(MLLITE_DIR)mldl_cfg.o - -# -# Accel options -# -ifdef CONFIG_SENSORS_ADXL346 -mpu3050-objs += $(MLLITE_DIR)accel/adxl346.o -endif - -ifdef CONFIG_SENSORS_BMA150 -mpu3050-objs += $(MLLITE_DIR)accel/bma150.o -endif - -ifdef CONFIG_SENSORS_BMA222 -mpu3050-objs += $(MLLITE_DIR)accel/bma222.o -endif - -ifdef CONFIG_SENSORS_KXSD9 -mpu3050-objs += $(MLLITE_DIR)accel/kxsd9.o -endif - -ifdef CONFIG_SENSORS_KXTF9 -mpu3050-objs += $(MLLITE_DIR)accel/kxtf9.o -endif - -ifdef CONFIG_SENSORS_LIS331DLH -mpu3050-objs += $(MLLITE_DIR)accel/lis331.o -endif - -ifdef CONFIG_SENSORS_LSM303DLHA -mpu3050-objs += $(MLLITE_DIR)accel/lsm303a.o -endif - -ifdef CONFIG_SENSORS_MMA8450 -mpu3050-objs += $(MLLITE_DIR)accel/mma8450.o -endif - -ifdef CONFIG_SENSORS_MMA8451 -mpu3050-objs += $(MLLITE_DIR)accel/mma8451.o -endif - -# -# Compass options -# -ifdef CONFIG_SENSORS_AK8975 -mpu3050-objs += $(MLLITE_DIR)compass/ak8975.o -endif - -ifdef CONFIG_SENSORS_AMI30X -mpu3050-objs += $(MLLITE_DIR)compass/ami30x.o -endif - -ifdef CONFIG_SENSORS_HMC5883 -mpu3050-objs += $(MLLITE_DIR)compass/hmc5883.o -endif - -ifdef CONFIG_SENSORS_LSM303DLHM -mpu3050-objs += $(MLLITE_DIR)compass/lsm303m.o -endif - -ifdef CONFIG_SENSORS_MMC314X -mpu3050-objs += $(MLLITE_DIR)compass/mmc314x.o -endif - -ifdef CONFIG_SENSORS_YAS529 -mpu3050-objs += $(MLLITE_DIR)compass/yas529-kernel.o -endif - -ifdef CONFIG_SENSORS_HSCDTD00XX -mpu3050-objs += $(MLLITE_DIR)compass/hscdtd00xx.o -endif - -# -# Pressure options -# -ifdef CONFIG_SENSORS_BMA085 -mpu3050-objs += $(MLLITE_DIR)pressure/bma085.o -endif - -EXTRA_CFLAGS += -I$(M)/$(MLLITE_DIR) \ - -I$(M)/../../include \ - -Idrivers/misc/mpu3050 \ - -Iinclude/linux - -ifdef CONFIG_SENSORS_MPU_DEBUG -EXTRA_CFLAGS += -DDEBUG -endif - -obj-$(CONFIG_SENSORS_MPU6000)= mpu6000.o -mpu6000-objs += mpuirq.o \ - mpu-dev.o \ - mpu-i2c.o \ - mlsl-kernel.o \ - mlos-kernel.o \ - $(MLLITE_DIR)mldl_cfg.o \ - $(MLLITE_DIR)accel/mantis.o - -ifdef CONFIG_SENSORS_AK8975 -mpu6000-objs += $(MLLITE_DIR)compass/ak8975.o -endif - -ifdef CONFIG_SENSORS_MPU6000 -EXTRA_CFLAGS += -DM_HW -endif + +# Kernel makefile for motions sensors +# +# + +# MPU +obj-$(CONFIG_MPU_SENSORS_MPU3050) += mpu3050.o +mpu3050-objs += mpuirq.o \ + slaveirq.o \ + mpu-dev.o \ + mpu-i2c.o \ + mlsl-kernel.o \ + mlos-kernel.o \ + $(MLLITE_DIR)mldl_cfg.o + +# +# Accel options +# +ifdef CONFIG_MPU_SENSORS_ADXL346 +mpu3050-objs += $(MLLITE_DIR)accel/adxl346.o +endif + +ifdef CONFIG_MPU_SENSORS_BMA150 +mpu3050-objs += $(MLLITE_DIR)accel/bma150.o +endif + +ifdef CONFIG_MPU_SENSORS_BMA222 +mpu3050-objs += $(MLLITE_DIR)accel/bma222.o +endif + +ifdef CONFIG_MPU_SENSORS_KXSD9 +mpu3050-objs += $(MLLITE_DIR)accel/kxsd9.o +endif + +ifdef CONFIG_MPU_SENSORS_KXTF9 +mpu3050-objs += $(MLLITE_DIR)accel/kxtf9.o +endif + +ifdef CONFIG_MPU_SENSORS_LIS331DLH +mpu3050-objs += $(MLLITE_DIR)accel/lis331.o +endif + +ifdef CONFIG_MPU_SENSORS_LIS3DH +mpu3050-objs += $(MLLITE_DIR)accel/lis3dh.o +endif + +ifdef CONFIG_MPU_SENSORS_LSM303DLHA +mpu3050-objs += $(MLLITE_DIR)accel/lsm303a.o +endif + +ifdef CONFIG_MPU_SENSORS_MMA8450 +mpu3050-objs += $(MLLITE_DIR)accel/mma8450.o +endif + +ifdef CONFIG_MPU_SENSORS_MMA845X +mpu3050-objs += $(MLLITE_DIR)accel/mma845x.o +endif + +# +# Compass options +# +ifdef CONFIG_MPU_SENSORS_AK8975 +mpu3050-objs += $(MLLITE_DIR)compass/ak8975.o +endif + +ifdef CONFIG_MPU_SENSORS_AMI30X +mpu3050-objs += $(MLLITE_DIR)compass/ami30x.o +endif + +ifdef CONFIG_MPU_SENSORS_AMI306 +mpu3050-objs += $(MLLITE_DIR)compass/ami306.o +endif + +ifdef CONFIG_MPU_SENSORS_HMC5883 +mpu3050-objs += $(MLLITE_DIR)compass/hmc5883.o +endif + +ifdef CONFIG_MPU_SENSORS_LSM303DLHM +mpu3050-objs += $(MLLITE_DIR)compass/lsm303m.o +endif + +ifdef CONFIG_MPU_SENSORS_MMC314X +mpu3050-objs += $(MLLITE_DIR)compass/mmc314x.o +endif + +ifdef CONFIG_MPU_SENSORS_YAS529 +mpu3050-objs += $(MLLITE_DIR)compass/yas529-kernel.o +endif + +ifdef CONFIG_MPU_SENSORS_YAS530 +mpu3050-objs += $(MLLITE_DIR)compass/yas530.o +endif + +ifdef CONFIG_MPU_SENSORS_HSCDTD002B +mpu3050-objs += $(MLLITE_DIR)compass/hscdtd002b.o +endif + +ifdef CONFIG_MPU_SENSORS_HSCDTD004A +mpu3050-objs += $(MLLITE_DIR)compass/hscdtd004a.o +endif +# +# Pressure options +# +ifdef CONFIG_MPU_SENSORS_BMA085 +mpu3050-objs += $(MLLITE_DIR)pressure/bma085.o +endif + +EXTRA_CFLAGS += -I$(M)/$(MLLITE_DIR) \ + -I$(M)/../../include \ + -Idrivers/misc/mpu3050 \ + -Iinclude/linux + +obj-$(CONFIG_MPU_SENSORS_MPU6000)+= mpu6000.o +mpu6000-objs += mpuirq.o \ + slaveirq.o \ + mpu-dev.o \ + mpu-i2c.o \ + mlsl-kernel.o \ + mlos-kernel.o \ + $(MLLITE_DIR)mldl_cfg.o \ + $(MLLITE_DIR)accel/mantis.o + +ifdef CONFIG_MPU_SENSORS_AK8975 +mpu6000-objs += $(MLLITE_DIR)compass/ak8975.o +endif + +ifdef CONFIG_MPU_SENSORS_MPU6000 +EXTRA_CFLAGS += -DM_HW +endif + +obj-$(CONFIG_MPU_SENSORS_TIMERIRQ)+= timerirq.o + diff --git a/drivers/misc/mpu3050/README b/drivers/misc/mpu3050/README old mode 100644 new mode 100755 index 2734dc14163e..047b6ba37c1d --- a/drivers/misc/mpu3050/README +++ b/drivers/misc/mpu3050/README @@ -108,7 +108,7 @@ should be modified for your platform. #include -#if defined(CONFIG_SENSORS_MPU3050) || defined(CONFIG_SENSORS_MPU3050_MODULE) +#if defined(CONFIG_MPU_SENSORS_MPU3050) || defined(CONFIG_MPU_SENSORS_MPU3050_MODULE) #define SENSOR_MPU_NAME "mpu3050" @@ -119,7 +119,7 @@ static struct mpu3050_platform_data mpu_data = { 0, 0, -1 }, /* accel */ .accel = { -#ifdef CONFIG_SENSORS_MPU3050_MODULE +#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE .get_slave_descr = NULL, #else .get_slave_descr = get_accel_slave_descr, @@ -133,7 +133,7 @@ static struct mpu3050_platform_data mpu_data = { }, /* compass */ .compass = { -#ifdef CONFIG_SENSORS_MPU3050_MODULE +#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE .get_slave_descr = NULL, #else .get_slave_descr = get_compass_slave_descr, @@ -147,7 +147,7 @@ static struct mpu3050_platform_data mpu_data = { }, /* pressure */ .pressure = { -#ifdef CONFIG_SENSORS_MPU3050_MODULE +#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE .get_slave_descr = NULL, #else .get_slave_descr = get_pressure_slave_descr, @@ -162,7 +162,7 @@ static struct mpu3050_platform_data mpu_data = { }; #endif -#if defined(CONFIG_SENSORS_MPU6000) || defined(CONFIG_SENSORS_MPU6000_MODULE) +#if defined(CONFIG_MPU_SENSORS_MPU6000) || defined(CONFIG_MPU_SENSORS_MPU6000_MODULE) #define SENSOR_MPU_NAME "mpu6000" @@ -173,7 +173,7 @@ static struct mpu3050_platform_data mpu_data = { 0, 0, -1 }, /* accel */ .accel = { -#ifdef CONFIG_SENSORS_MPU6000_MODULE +#ifdef CONFIG_MPU_SENSORS_MPU6000_MODULE .get_slave_descr = NULL, #else .get_slave_descr = get_accel_slave_descr, @@ -187,7 +187,7 @@ static struct mpu3050_platform_data mpu_data = { }, /* compass */ .compass = { -#ifdef CONFIG_SENSORS_MPU6000_MODULE +#ifdef CONFIG_MPU_SENSORS_MPU6000_MODULE .get_slave_descr = NULL, #else .get_slave_descr = get_compass_slave_descr, @@ -201,7 +201,7 @@ static struct mpu3050_platform_data mpu_data = { }, /* pressure */ .pressure = { -#ifdef CONFIG_SENSORS_MPU6000_MODULE +#ifdef CONFIG_MPU_SENSORS_MPU6000_MODULE .get_slave_descr = NULL, #else .get_slave_descr = get_pressure_slave_descr, @@ -234,6 +234,17 @@ done as well: gpio_request(MPU_GPIO_IRQ,"MPUIRQ"); gpio_direction_input(MPU_GPIO_IRQ) +NOTE: +===== +In previous releases, the sensors were defined using CONFIG_SENSORS_SENSORNAME convention. +From this release onwards this convention will be changed to CONFIG_MPU_SENSORS_SENSORNAME. +Please make note of this change. + +Dynamic Debug +============= + +The mpu3050 makes use of dynamic debug. For details on how to use this +refer to Documentation/dynamic-debug-howto.txt Android File Permissions ======================== @@ -243,8 +254,17 @@ To set up the file permissions on an android system, the /dev/mpu and inside the perms_ structure. static struct perms_ devperms[] = { - { "/dev/mpu" ,0640, AID_SYSTEM, AID_SYSTEM, 1 }, + { "/dev/mpu" ,0660, AID_SYSTEM, AID_SYSTEM, 1 }, }; Sufficient file permissions need to be give to read and write it by the system. +For gingerbread and later the system/core/rootdir/ueventd.rc file needs to be +modified with the appripriate lines added. + +# MPU sensors and IRQ +/dev/mpu 0660 system system +/dev/mpuirq 0660 system system +/dev/accelirq 0660 system system +/dev/compassirq 0660 system system +/dev/pressureirq 0660 system system diff --git a/drivers/misc/mpu3050/accel/adxl346.c b/drivers/misc/mpu3050/accel/adxl346.c old mode 100644 new mode 100755 index 2f76313208ec..14cb38a829ee --- a/drivers/misc/mpu3050/accel/adxl346.c +++ b/drivers/misc/mpu3050/accel/adxl346.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -116,7 +129,10 @@ int adxl346_read(void *mlsl_handle, struct ext_slave_platform_data *pdata, unsigned char *data) { - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + int result; + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + return result; } struct ext_slave_descr adxl346_descr = { @@ -126,6 +142,7 @@ struct ext_slave_descr adxl346_descr = { /*.resume = */ adxl346_resume, /*.read = */ adxl346_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "adx1346", /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, /*.id = */ ACCEL_ID_ADI346, diff --git a/drivers/misc/mpu3050/accel/bma150.c b/drivers/misc/mpu3050/accel/bma150.c old mode 100644 new mode 100755 index f5e99d1b6d63..30fed1564850 --- a/drivers/misc/mpu3050/accel/bma150.c +++ b/drivers/misc/mpu3050/accel/bma150.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -61,7 +74,7 @@ static int bma150_resume(void *mlsl_handle, result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0a, 0x02); ERROR_CHECK(result); - MLOSSleep(10); + MLOSSleep(3); result = MLSLSerialRead(mlsl_handle, pdata->address, 0x14, 1, ®); @@ -95,7 +108,10 @@ static int bma150_read(void *mlsl_handle, struct ext_slave_platform_data *pdata, unsigned char *data) { - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + int result; + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + return result; } static struct ext_slave_descr bma150_descr = { @@ -105,6 +121,7 @@ static struct ext_slave_descr bma150_descr = { /*.resume = */ bma150_resume, /*.read = */ bma150_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "bma150", /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, /*.id = */ ACCEL_ID_BMA150, diff --git a/drivers/misc/mpu3050/accel/bma222.c b/drivers/misc/mpu3050/accel/bma222.c old mode 100644 new mode 100755 index bd0c87ccd8cd..534a1e5fa64b --- a/drivers/misc/mpu3050/accel/bma222.c +++ b/drivers/misc/mpu3050/accel/bma222.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /* @@ -95,7 +108,10 @@ static int bma222_read(void *mlsl_handle, struct ext_slave_platform_data *pdata, unsigned char *data) { - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + int result; + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + return result; } static struct ext_slave_descr bma222_descr = { @@ -105,6 +121,7 @@ static struct ext_slave_descr bma222_descr = { /*.resume = */ bma222_resume, /*.read = */ bma222_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "bma222", /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, /*.id = */ ACCEL_ID_BMA222, diff --git a/drivers/misc/mpu3050/accel/cma3000.c b/drivers/misc/mpu3050/accel/cma3000.c old mode 100644 new mode 100755 index 8c6b3c8245b8..05925951c628 --- a/drivers/misc/mpu3050/accel/cma3000.c +++ b/drivers/misc/mpu3050/accel/cma3000.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -65,7 +78,10 @@ int cma3000_read(void *mlsl_handle, struct ext_slave_platform_data *pdata, unsigned char *data) { - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + int result; + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + return result; } struct ext_slave_descr cma3000_descr = { diff --git a/drivers/misc/mpu3050/accel/kxsd9.c b/drivers/misc/mpu3050/accel/kxsd9.c old mode 100644 new mode 100755 index 10ed3b2ac6db..77bc52c8e586 --- a/drivers/misc/mpu3050/accel/kxsd9.c +++ b/drivers/misc/mpu3050/accel/kxsd9.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -44,7 +57,6 @@ static int kxsd9_suspend(void *mlsl_handle, struct ext_slave_platform_data *pdata) { int result; - (void *) slave; /* CTRL_REGB: low-power standby mode */ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0d, 0x0); @@ -99,7 +111,10 @@ static int kxsd9_read(void *mlsl_handle, struct ext_slave_platform_data *pdata, unsigned char *data) { - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + int result; + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + return result; } static struct ext_slave_descr kxsd9_descr = { @@ -109,6 +124,7 @@ static struct ext_slave_descr kxsd9_descr = { /*.resume = */ kxsd9_resume, /*.read = */ kxsd9_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "kxsd9", /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, /*.id = */ ACCEL_ID_KXSD9, diff --git a/drivers/misc/mpu3050/accel/kxtf9.c b/drivers/misc/mpu3050/accel/kxtf9.c old mode 100644 new mode 100755 index 9eae342d029f..e2490af1ca77 --- a/drivers/misc/mpu3050/accel/kxtf9.c +++ b/drivers/misc/mpu3050/accel/kxtf9.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -18,6 +31,9 @@ /* - Include Files. - */ /* ------------------ */ +#undef MPL_LOG_NDEBUG +#define MPL_LOG_NDEBUG 1 + #ifdef __KERNEL__ #include #endif @@ -30,22 +46,322 @@ #undef MPL_LOG_TAG #define MPL_LOG_TAG "MPL-acc" +#define KXTF9_XOUT_HPF_L (0x00) /* 0000 0000 */ +#define KXTF9_XOUT_HPF_H (0x01) /* 0000 0001 */ +#define KXTF9_YOUT_HPF_L (0x02) /* 0000 0010 */ +#define KXTF9_YOUT_HPF_H (0x03) /* 0000 0011 */ +#define KXTF9_ZOUT_HPF_L (0x04) /* 0001 0100 */ +#define KXTF9_ZOUT_HPF_H (0x05) /* 0001 0101 */ +#define KXTF9_XOUT_L (0x06) /* 0000 0110 */ +#define KXTF9_XOUT_H (0x07) /* 0000 0111 */ +#define KXTF9_YOUT_L (0x08) /* 0000 1000 */ +#define KXTF9_YOUT_H (0x09) /* 0000 1001 */ +#define KXTF9_ZOUT_L (0x0A) /* 0001 1010 */ +#define KXTF9_ZOUT_H (0x0B) /* 0001 1011 */ +#define KXTF9_ST_RESP (0x0C) /* 0000 1100 */ +#define KXTF9_WHO_AM_I (0x0F) /* 0000 1111 */ +#define KXTF9_TILT_POS_CUR (0x10) /* 0001 0000 */ +#define KXTF9_TILT_POS_PRE (0x11) /* 0001 0001 */ +#define KXTF9_INT_SRC_REG1 (0x15) /* 0001 0101 */ +#define KXTF9_INT_SRC_REG2 (0x16) /* 0001 0110 */ +#define KXTF9_STATUS_REG (0x18) /* 0001 1000 */ +#define KXTF9_INT_REL (0x1A) /* 0001 1010 */ +#define KXTF9_CTRL_REG1 (0x1B) /* 0001 1011 */ +#define KXTF9_CTRL_REG2 (0x1C) /* 0001 1100 */ +#define KXTF9_CTRL_REG3 (0x1D) /* 0001 1101 */ +#define KXTF9_INT_CTRL_REG1 (0x1E) /* 0001 1110 */ +#define KXTF9_INT_CTRL_REG2 (0x1F) /* 0001 1111 */ +#define KXTF9_INT_CTRL_REG3 (0x20) /* 0010 0000 */ +#define KXTF9_DATA_CTRL_REG (0x21) /* 0010 0001 */ +#define KXTF9_TILT_TIMER (0x28) /* 0010 1000 */ +#define KXTF9_WUF_TIMER (0x29) /* 0010 1001 */ +#define KXTF9_TDT_TIMER (0x2B) /* 0010 1011 */ +#define KXTF9_TDT_H_THRESH (0x2C) /* 0010 1100 */ +#define KXTF9_TDT_L_THRESH (0x2D) /* 0010 1101 */ +#define KXTF9_TDT_TAP_TIMER (0x2E) /* 0010 1110 */ +#define KXTF9_TDT_TOTAL_TIMER (0x2F) /* 0010 1111 */ +#define KXTF9_TDT_LATENCY_TIMER (0x30) /* 0011 0000 */ +#define KXTF9_TDT_WINDOW_TIMER (0x31) /* 0011 0001 */ +#define KXTF9_WUF_THRESH (0x5A) /* 0101 1010 */ +#define KXTF9_TILT_ANGLE (0x5C) /* 0101 1100 */ +#define KXTF9_HYST_SET (0x5F) /* 0101 1111 */ + +#define KXTF9_MAX_DUR (0xFF) +#define KXTF9_MAX_THS (0xFF) +#define KXTF9_THS_COUNTS_P_G (32) + /* --------------------- */ /* - Variables. - */ /* --------------------- */ +struct kxtf9_config { + unsigned int odr; /* Output data rate mHz */ + unsigned int fsr; /* full scale range mg */ + unsigned int ths; /* Motion no-motion thseshold mg */ + unsigned int dur; /* Motion no-motion duration ms */ + unsigned int irq_type; + unsigned char reg_ths; + unsigned char reg_dur; + unsigned char reg_odr; + unsigned char reg_int_cfg1; + unsigned char reg_int_cfg2; + unsigned char ctrl_reg1; +}; + +struct kxtf9_private_data { + struct kxtf9_config suspend; + struct kxtf9_config resume; +}; + /***************************************** Accelerometer Initialization Functions *****************************************/ +static int kxtf9_set_ths(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, + int apply, + long ths) +{ + int result = ML_SUCCESS; + if ((ths * KXTF9_THS_COUNTS_P_G / 1000) > KXTF9_MAX_THS) + ths = (KXTF9_MAX_THS * 1000) / KXTF9_THS_COUNTS_P_G; + + if (ths < 0) + ths = 0; + + config->ths = ths; + config->reg_ths = (unsigned char) + ((long)(ths * KXTF9_THS_COUNTS_P_G) / 1000); + MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_THRESH, + config->reg_ths); + return result; +} + +static int kxtf9_set_dur(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, + int apply, + long dur) +{ + int result = ML_SUCCESS; + long reg_dur = (dur * config->odr) / 1000000; + config->dur = dur; + + if (reg_dur > KXTF9_MAX_DUR) + reg_dur = KXTF9_MAX_DUR; + + config->reg_dur = (unsigned char) reg_dur; + MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_TIMER, + (unsigned char)reg_dur); + return result; +} + +/** + * Sets the IRQ to fire when one of the IRQ events occur. Threshold and + * duration will not be used uless the type is MOT or NMOT. + * + * @param config configuration to apply to, suspend or resume + * @param irq_type The type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + */ +static int kxtf9_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, + int apply, + long irq_type) +{ + int result = ML_SUCCESS; + struct kxtf9_private_data *private_data = pdata->private_data; + + config->irq_type = (unsigned char)irq_type; + config->ctrl_reg1 &= ~0x22; + if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + config->ctrl_reg1 |= 0x20; + config->reg_int_cfg1 = 0x38; + config->reg_int_cfg2 = 0x00; + } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { + config->ctrl_reg1 |= 0x02; + if ((unsigned long) config == + (unsigned long) &private_data->suspend) + config->reg_int_cfg1 = 0x34; + else + config->reg_int_cfg1 = 0x24; + config->reg_int_cfg2 = 0xE0; + } else { + config->reg_int_cfg1 = 0x00; + config->reg_int_cfg2 = 0x00; + } + + if (apply) { + /* Must clear bit 7 before writing new configuration */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG1, + config->reg_int_cfg1); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG2, + config->reg_int_cfg2); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + config->ctrl_reg1); + } + MPL_LOGV("CTRL_REG1: %lx, INT_CFG1: %lx, INT_CFG2: %lx\n", + (unsigned long)config->ctrl_reg1, + (unsigned long)config->reg_int_cfg1, + (unsigned long)config->reg_int_cfg2); + + return result; +} + +/** + * Set the Output data rate for the particular configuration + * + * @param config Config to modify with new ODR + * @param odr Output data rate in units of 1/1000Hz + */ +static int kxtf9_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, + int apply, + long odr) +{ + unsigned char bits; + int result = ML_SUCCESS; + + /* Data sheet says there is 12.5 hz, but that seems to produce a single + * correct data value, thus we remove it from the table */ + if (odr > 400000) { + config->odr = 800000; + bits = 0x06; + } else if (odr > 200000) { + config->odr = 400000; + bits = 0x05; + } else if (odr > 100000) { + config->odr = 200000; + bits = 0x04; + } else if (odr > 50000) { + config->odr = 100000; + bits = 0x03; + } else if (odr > 25000) { + config->odr = 50000; + bits = 0x02; + } else if (odr != 0) { + config->odr = 25000; + bits = 0x01; + } else { + config->odr = 0; + bits = 0; + } + + if (odr != 0) + config->ctrl_reg1 |= 0x80; + + config->reg_odr = bits; + kxtf9_set_dur(mlsl_handle, pdata, + config, apply, config->dur); + MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1); + if (apply) { + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, + config->reg_odr); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + 0x40); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + config->ctrl_reg1); + } + return result; +} + +/** + * Set the full scale range of the accels + * + * @param config pointer to configuration + * @param fsr requested full scale range + */ +static int kxtf9_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, + int apply, + long fsr) +{ + int result = ML_SUCCESS; + + config->ctrl_reg1 = (config->ctrl_reg1 & 0xE7); + if (fsr <= 2000) { + config->fsr = 2000; + config->ctrl_reg1 |= 0x00; + } else if (fsr <= 4000) { + config->fsr = 4000; + config->ctrl_reg1 |= 0x08; + } else { + config->fsr = 8000; + config->ctrl_reg1 |= 0x10; + } + + MPL_LOGV("FSR: %d\n", config->fsr); + if (apply) { + /* Must clear bit 7 before writing new configuration */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, config->ctrl_reg1); + } + return result; +} + static int kxtf9_suspend(void *mlsl_handle, struct ext_slave_descr *slave, struct ext_slave_platform_data *pdata) { int result; - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, 0); + unsigned char data; + struct kxtf9_private_data *private_data = pdata->private_data; + + /* Wake up */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + ERROR_CHECK(result); + /* INT_CTRL_REG1: */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG1, + private_data->suspend.reg_int_cfg1); + ERROR_CHECK(result); + /* WUF_THRESH: */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_THRESH, + private_data->suspend.reg_ths); ERROR_CHECK(result); + /* DATA_CTRL_REG */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, + private_data->suspend.reg_odr); + ERROR_CHECK(result); + /* WUF_TIMER */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_TIMER, private_data->suspend.reg_dur); + ERROR_CHECK(result); + + /* Normal operation */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + private_data->suspend.ctrl_reg1); + ERROR_CHECK(result); + result = MLSLSerialRead(mlsl_handle, pdata->address, + KXTF9_INT_REL, 1, &data); + ERROR_CHECK(result); + return result; } @@ -58,53 +374,245 @@ static int kxtf9_resume(void *mlsl_handle, struct ext_slave_platform_data *pdata) { int result = ML_SUCCESS; - unsigned char reg; + unsigned char data; + struct kxtf9_private_data *private_data = pdata->private_data; - /* RAM reset */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1d, 0xcd); - ERROR_CHECK(result); - MLOSSleep(10); /* Wake up */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, 0x42); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); ERROR_CHECK(result); /* INT_CTRL_REG1: */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1e, 0x14); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG1, + private_data->resume.reg_int_cfg1); ERROR_CHECK(result); /* WUF_THRESH: */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x5a, 0x00); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_THRESH, private_data->resume.reg_ths); ERROR_CHECK(result); /* DATA_CTRL_REG */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x21, 0x04); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, + private_data->resume.reg_odr); ERROR_CHECK(result); /* WUF_TIMER */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x29, 0x02); - ERROR_CHECK(result); - - /* Full Scale */ - reg = 0xc2; - reg &= ~ACCEL_KIONIX_CTRL_MASK; - reg |= 0x00; - if (slave->range.mantissa == 4) - reg |= 0x08; - else if (slave->range.mantissa == 8) - reg |= 0x10; - else { - slave->range.mantissa = 2; - reg |= 0x00; - } - slave->range.fraction = 0; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_TIMER, private_data->resume.reg_dur); + ERROR_CHECK(result); /* Normal operation */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, reg); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + private_data->resume.ctrl_reg1); + ERROR_CHECK(result); + result = MLSLSerialRead(mlsl_handle, pdata->address, + KXTF9_INT_REL, 1, &data); ERROR_CHECK(result); - MLOSSleep(50); + + return ML_SUCCESS; +} + +static int kxtf9_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + + struct kxtf9_private_data *private_data; + int result = ML_SUCCESS; + + private_data = (struct kxtf9_private_data *) + MLOSMalloc(sizeof(struct kxtf9_private_data)); + + if (!private_data) + return ML_ERROR_MEMORY_EXAUSTED; + + /* RAM reset */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + 0x40); /* Fastest Reset */ + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, + 0x36); /* Fastest Reset */ + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG3, 0xcd); /* Reset */ + ERROR_CHECK(result); + MLOSSleep(2); + + pdata->private_data = private_data; + + private_data->resume.ctrl_reg1 = 0xC0; + private_data->suspend.ctrl_reg1 = 0x40; + + result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->suspend, + FALSE, 1000); + ERROR_CHECK(result); + result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->resume, + FALSE, 2540); + ERROR_CHECK(result); + + result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->suspend, + FALSE, 50000); + ERROR_CHECK(result); + result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->resume, + FALSE, 200000); + + result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->suspend, + FALSE, 2000); + ERROR_CHECK(result); + result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->resume, + FALSE, 2000); + ERROR_CHECK(result); + + result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->suspend, + FALSE, 80); + ERROR_CHECK(result); + result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->resume, + FALSE, 40); + ERROR_CHECK(result); + + result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->suspend, + FALSE, + MPU_SLAVE_IRQ_TYPE_NONE); + ERROR_CHECK(result); + result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->resume, + FALSE, + MPU_SLAVE_IRQ_TYPE_NONE); + ERROR_CHECK(result); + return result; +} + +static int kxtf9_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + if (pdata->private_data) + return MLOSFree(pdata->private_data); + else + return ML_SUCCESS; +} + +static int kxtf9_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct kxtf9_private_data *private_data = pdata->private_data; + if (!data->data) + return ML_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return kxtf9_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return kxtf9_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return kxtf9_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return kxtf9_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_THS: + return kxtf9_set_ths(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_THS: + return kxtf9_set_ths(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_DUR: + return kxtf9_set_dur(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_DUR: + return kxtf9_set_dur(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return kxtf9_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return kxtf9_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + default: + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return ML_SUCCESS; +} + +static int kxtf9_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct kxtf9_private_data *private_data = pdata->private_data; + if (!data->data) + return ML_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 ML_ERROR_FEATURE_NOT_IMPLEMENTED; + }; return ML_SUCCESS; } @@ -114,16 +622,29 @@ static int kxtf9_read(void *mlsl_handle, struct ext_slave_platform_data *pdata, unsigned char *data) { - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + int result; + unsigned char reg; + result = MLSLSerialRead(mlsl_handle, pdata->address, + KXTF9_INT_SRC_REG2, 1, ®); + ERROR_CHECK(result); + + if (!(reg & 0x10)) + return ML_ERROR_ACCEL_DATA_NOT_READY; + + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + ERROR_CHECK(result); + return result; } static struct ext_slave_descr kxtf9_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, + /*.init = */ kxtf9_init, + /*.exit = */ kxtf9_exit, /*.suspend = */ kxtf9_suspend, /*.resume = */ kxtf9_resume, /*.read = */ kxtf9_read, - /*.config = */ NULL, + /*.config = */ kxtf9_config, + /*.get_config = */ kxtf9_get_config, /*.name = */ "kxtf9", /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, /*.id = */ ACCEL_ID_KXTF9, diff --git a/drivers/misc/mpu3050/accel/lis331.c b/drivers/misc/mpu3050/accel/lis331.c old mode 100644 new mode 100755 index b98dbc62d135..53c599b2ef27 --- a/drivers/misc/mpu3050/accel/lis331.c +++ b/drivers/misc/mpu3050/accel/lis331.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -18,6 +31,9 @@ /* - Include Files. - */ /* ------------------ */ +#undef MPL_LOG_NDEBUG +#define MPL_LOG_NDEBUG 1 + #ifdef __KERNEL__ #include #endif @@ -73,6 +89,8 @@ struct lis331dlh_config { unsigned char reg_ths; unsigned char reg_dur; unsigned char ctrl_reg1; + unsigned char irq_type; + unsigned char mot_int1_cfg; }; struct lis331dlh_private_data { @@ -85,23 +103,36 @@ struct lis331dlh_private_data { Accelerometer Initialization Functions *****************************************/ -void lis331dlh_set_ths(struct lis331dlh_config *config, - long ths) +static int lis331dlh_set_ths(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis331dlh_config *config, + int apply, + long ths) { - if ((unsigned int) ths > 1000 * config->fsr) - ths = (long) 1000 * config->fsr; + int result = ML_SUCCESS; + if ((unsigned int) ths >= config->fsr) + ths = (long) config->fsr - 1; if (ths < 0) ths = 0; config->ths = ths; config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr)); - MPL_LOGD("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); + MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS331_INT1_THS, + config->reg_ths); + return result; } -void lis331dlh_set_dur(struct lis331dlh_config *config, - long dur) +static int lis331dlh_set_dur(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis331dlh_config *config, + int apply, + long dur) { + int result = ML_SUCCESS; long reg_dur = (dur * config->odr) / 1000000L; config->dur = dur; @@ -109,7 +140,54 @@ void lis331dlh_set_dur(struct lis331dlh_config *config, reg_dur = LIS331_MAX_DUR; config->reg_dur = (unsigned char) reg_dur; - MPL_LOGD("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); + MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS331_INT1_DURATION, + (unsigned char)reg_dur); + return result; +} + +/** + * Sets the IRQ to fire when one of the IRQ events occur. Threshold and + * duration will not be used uless the type is MOT or NMOT. + * + * @param config configuration to apply to, suspend or resume + * @param irq_type The type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + */ +static int lis331dlh_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis331dlh_config *config, + int apply, + long irq_type) +{ + int result = ML_SUCCESS; + unsigned char reg1; + unsigned char reg2; + + config->irq_type = (unsigned char)irq_type; + if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x02; + reg2 = 0x00; + } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x00; + reg2 = config->mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + + if (apply) { + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS331_CTRL_REG3, reg1); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS331_INT1_CFG, reg2); + } + + return result; } /** @@ -118,11 +196,14 @@ void lis331dlh_set_dur(struct lis331dlh_config *config, * @param config Config to modify with new ODR * @param odr Output data rate in units of 1/1000Hz */ -static void lis331dlh_set_odr( - struct lis331dlh_config *config, - long odr) +static int lis331dlh_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis331dlh_config *config, + int apply, + long odr) { unsigned char bits; + int result = ML_SUCCESS; if (odr > 400000) { config->odr = 1000000; @@ -157,31 +238,58 @@ static void lis331dlh_set_odr( } config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0x7); - lis331dlh_set_dur(config, config->dur); - MPL_LOGD("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1); + lis331dlh_set_dur(mlsl_handle, pdata, + config, apply, config->dur); + MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS331_CTRL_REG1, + config->ctrl_reg1); + return result; } -static void lis331dlh_set_fsr( - struct lis331dlh_config *config, - long fsr) +/** + * Set the full scale range of the accels + * + * @param config pointer to configuration + * @param fsr requested full scale range + */ +static int lis331dlh_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis331dlh_config *config, + int apply, + long fsr) { - if (fsr <= 2048) + unsigned char reg1 = 0x40; + int result = ML_SUCCESS; + + if (fsr <= 2048) { config->fsr = 2048; - else if (fsr <= 4096) + } else if (fsr <= 4096) { + reg1 |= 0x30; config->fsr = 4096; - else + } else { + reg1 |= 0x10; config->fsr = 8192; + } + + lis331dlh_set_ths(mlsl_handle, pdata, + config, apply, config->ths); + MPL_LOGV("FSR: %d\n", config->fsr); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS331_CTRL_REG4, reg1); - lis331dlh_set_ths(config, config->ths); - MPL_LOGD("FSR: %d\n", config->fsr); + return result; } -int lis331dlh_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) +static int lis331dlh_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) { - int result; - unsigned char reg; + int result = ML_SUCCESS; + unsigned char reg1; + unsigned char reg2; struct lis331dlh_private_data *private_data = pdata->private_data; result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, @@ -190,36 +298,49 @@ int lis331dlh_suspend(void *mlsl_handle, result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, LIS331_CTRL_REG2, 0x0f); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG3, 0x00); - reg = 0x40; + reg1 = 0x40; if (private_data->suspend.fsr == 8192) - reg |= 0x30; + reg1 |= 0x30; else if (private_data->suspend.fsr == 4096) - reg |= 0x10; + reg1 |= 0x10; /* else bits [4..5] are already zero */ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG4, reg); + LIS331_CTRL_REG4, reg1); result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, LIS331_INT1_THS, private_data->suspend.reg_ths); result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, LIS331_INT1_DURATION, private_data->suspend.reg_dur); + + if (private_data->suspend.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x02; + reg2 = 0x00; + } else if (private_data->suspend.irq_type == + MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x00; + reg2 = private_data->suspend.mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS331_CTRL_REG3, reg1); result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_CFG, 0x2a); + LIS331_INT1_CFG, reg2); result = MLSLSerialRead(mlsl_handle, pdata->address, - LIS331_HP_FILTER_RESET, 1, ®); + LIS331_HP_FILTER_RESET, 1, ®1); return result; } -int lis331dlh_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) +static int lis331dlh_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) { int result = ML_SUCCESS; - unsigned char reg; + unsigned char reg1; + unsigned char reg2; struct lis331dlh_private_data *private_data = pdata->private_data; result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, @@ -229,45 +350,66 @@ int lis331dlh_resume(void *mlsl_handle, MLOSSleep(6); /* Full Scale */ - reg = 0x40; - reg &= ~LIS331_CTRL_MASK; + reg1 = 0x40; if (private_data->resume.fsr == 8192) - reg |= 0x30; + reg1 |= 0x30; else if (private_data->resume.fsr == 4096) - reg |= 0x10; + reg1 |= 0x10; result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG4, reg); + LIS331_CTRL_REG4, reg1); ERROR_CHECK(result); /* Configure high pass filter */ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, LIS331_CTRL_REG2, 0x0F); ERROR_CHECK(result); + + if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x02; + reg2 = 0x00; + } else if (private_data->resume.irq_type == + MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x00; + reg2 = private_data->resume.mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG3, 0x00); + LIS331_CTRL_REG3, reg1); ERROR_CHECK(result); result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_THS, 0x02); + LIS331_INT1_THS, + private_data->resume.reg_ths); ERROR_CHECK(result); result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_DURATION, 0x7F); + LIS331_INT1_DURATION, + private_data->resume.reg_dur); ERROR_CHECK(result); result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_CFG, 0x95); + LIS331_INT1_CFG, reg2); ERROR_CHECK(result); result = MLSLSerialRead(mlsl_handle, pdata->address, - LIS331_HP_FILTER_RESET, 1, ®); + LIS331_HP_FILTER_RESET, 1, ®1); ERROR_CHECK(result); return result; } -int lis331dlh_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) +static int lis331dlh_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) { - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + int result = ML_SUCCESS; + result = MLSLSerialRead(mlsl_handle, pdata->address, + LIS331_STATUS_REG, 1, data); + if (data[0] & 0x0F) { + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + return result; + } else + return ML_ERROR_ACCEL_DATA_NOT_READY; } static int lis331dlh_init(void *mlsl_handle, @@ -285,15 +427,31 @@ static int lis331dlh_init(void *mlsl_handle, private_data->resume.ctrl_reg1 = 0x37; private_data->suspend.ctrl_reg1 = 0x47; - - lis331dlh_set_odr(&private_data->suspend, 50000); - lis331dlh_set_odr(&private_data->resume, 200000); - lis331dlh_set_fsr(&private_data->suspend, 2048); - lis331dlh_set_fsr(&private_data->resume, 2048); - lis331dlh_set_ths(&private_data->suspend, 80); - lis331dlh_set_ths(&private_data->resume, 40); - lis331dlh_set_dur(&private_data->suspend, 1000); - lis331dlh_set_dur(&private_data->resume, 2540); + private_data->resume.mot_int1_cfg = 0x95; + private_data->suspend.mot_int1_cfg = 0x2a; + + lis331dlh_set_odr(mlsl_handle, pdata, &private_data->suspend, + FALSE, 0); + lis331dlh_set_odr(mlsl_handle, pdata, &private_data->resume, + FALSE, 200000); + lis331dlh_set_fsr(mlsl_handle, pdata, &private_data->suspend, + FALSE, 2048); + lis331dlh_set_fsr(mlsl_handle, pdata, &private_data->resume, + FALSE, 2048); + lis331dlh_set_ths(mlsl_handle, pdata, &private_data->suspend, + FALSE, 80); + lis331dlh_set_ths(mlsl_handle, pdata, &private_data->resume, + FALSE, 40); + lis331dlh_set_dur(mlsl_handle, pdata, &private_data->suspend, + FALSE, 1000); + lis331dlh_set_dur(mlsl_handle, pdata, &private_data->resume, + FALSE, 2540); + lis331dlh_set_irq(mlsl_handle, pdata, &private_data->suspend, + FALSE, + MPU_SLAVE_IRQ_TYPE_NONE); + lis331dlh_set_irq(mlsl_handle, pdata, &private_data->resume, + FALSE, + MPU_SLAVE_IRQ_TYPE_NONE); return ML_SUCCESS; } @@ -318,36 +476,111 @@ static int lis331dlh_config(void *mlsl_handle, switch (data->key) { case MPU_SLAVE_CONFIG_ODR_SUSPEND: - lis331dlh_set_odr(&private_data->suspend, - *((long *)data->data)); + return lis331dlh_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return lis331dlh_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return lis331dlh_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return lis331dlh_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_THS: + return lis331dlh_set_ths(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_THS: + return lis331dlh_set_ths(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_DUR: + return lis331dlh_set_dur(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_DUR: + return lis331dlh_set_dur(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return lis331dlh_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return lis331dlh_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + default: + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return ML_SUCCESS; +} + +static int lis331dlh_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct lis331dlh_private_data *private_data = pdata->private_data; + if (!data->data) + return ML_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: - lis331dlh_set_odr(&private_data->resume, - *((long *)data->data)); + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.odr; break; case MPU_SLAVE_CONFIG_FSR_SUSPEND: - lis331dlh_set_fsr(&private_data->suspend, - *((long *)data->data)); + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.fsr; break; case MPU_SLAVE_CONFIG_FSR_RESUME: - lis331dlh_set_fsr(&private_data->resume, - *((long *)data->data)); + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.fsr; break; case MPU_SLAVE_CONFIG_MOT_THS: - lis331dlh_set_ths(&private_data->suspend, - *((long *)data->data)); + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.ths; break; case MPU_SLAVE_CONFIG_NMOT_THS: - lis331dlh_set_ths(&private_data->resume, - *((long *)data->data)); + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.ths; break; case MPU_SLAVE_CONFIG_MOT_DUR: - lis331dlh_set_dur(&private_data->suspend, - *((long *)data->data)); + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.dur; break; case MPU_SLAVE_CONFIG_NMOT_DUR: - lis331dlh_set_dur(&private_data->resume, - *((long *)data->data)); + (*(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 ML_ERROR_FEATURE_NOT_IMPLEMENTED; @@ -356,13 +589,14 @@ static int lis331dlh_config(void *mlsl_handle, return ML_SUCCESS; } -struct ext_slave_descr lis331dlh_descr = { +static struct ext_slave_descr lis331dlh_descr = { /*.init = */ lis331dlh_init, /*.exit = */ lis331dlh_exit, /*.suspend = */ lis331dlh_suspend, /*.resume = */ lis331dlh_resume, /*.read = */ lis331dlh_read, /*.config = */ lis331dlh_config, + /*.get_config = */ lis331dlh_get_config, /*.name = */ "lis331dlh", /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, /*.id = */ ACCEL_ID_LIS331, diff --git a/drivers/misc/mpu3050/accel/lis3dh.c b/drivers/misc/mpu3050/accel/lis3dh.c new file mode 100755 index 000000000000..ee5e3539b988 --- /dev/null +++ b/drivers/misc/mpu3050/accel/lis3dh.c @@ -0,0 +1,624 @@ +/* + $License: + Copyright (C) 2010 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 . + $ + */ + +/** + * @defgroup ACCELDL (Motion Library - Accelerometer Driver Layer) + * @brief Provides the interface to setup and handle an accelerometers + * connected to the secondary I2C interface of the gyroscope. + * + * @{ + * @file lis3dh.c + * @brief Accelerometer setup and handling methods for ST LIS3DH + */ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#undef MPL_LOG_NDEBUG +#define MPL_LOG_NDEBUG 0 + +#ifdef __KERNEL__ +#include +#endif + +#include "mpu.h" +#include "mlsl.h" +#include "mlos.h" + +#include +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +/* full scale setting - register & mask */ +#define LIS3DH_CTRL_REG1 (0x20) +#define LIS3DH_CTRL_REG2 (0x21) +#define LIS3DH_CTRL_REG3 (0x22) +#define LIS3DH_CTRL_REG4 (0x23) +#define LIS3DH_CTRL_REG5 (0x24) +#define LIS3DH_CTRL_REG6 (0x25) +#define LIS3DH_REFERENCE (0x26) +#define LIS3DH_STATUS_REG (0x27) +#define LIS3DH_OUT_X_L (0x28) +#define LIS3DH_OUT_X_H (0x29) +#define LIS3DH_OUT_Y_L (0x2a) +#define LIS3DH_OUT_Y_H (0x2b) +#define LIS3DH_OUT_Z_L (0x2b) +#define LIS3DH_OUT_Z_H (0x2d) + +#define LIS3DH_INT1_CFG (0x30) +#define LIS3DH_INT1_SRC (0x31) +#define LIS3DH_INT1_THS (0x32) +#define LIS3DH_INT1_DURATION (0x33) + +#define LIS3DH_MAX_DUR (0x7F) + + +/* --------------------- */ +/* - Variables. - */ +/* --------------------- */ + +struct lis3dh_config { + unsigned int odr; + unsigned int fsr; /* full scale range mg */ + unsigned int ths; /* Motion no-motion thseshold mg */ + unsigned int dur; /* Motion no-motion duration ms */ + unsigned char reg_ths; + unsigned char reg_dur; + unsigned char ctrl_reg1; + unsigned char irq_type; + unsigned char mot_int1_cfg; +}; + +struct lis3dh_private_data { + struct lis3dh_config suspend; + struct lis3dh_config resume; +}; + + +/***************************************** + Accelerometer Initialization Functions +*****************************************/ + +static int lis3dh_set_ths(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis3dh_config *config, + int apply, + long ths) +{ + int result = ML_SUCCESS; + if ((unsigned int) ths > 1000 * config->fsr) + ths = (long) 1000 * config->fsr; + + if (ths < 0) + ths = 0; + + config->ths = ths; + config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr)); + MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_INT1_THS, + config->reg_ths); + return result; +} + +static int lis3dh_set_dur(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis3dh_config *config, + int apply, + long dur) +{ + int result = ML_SUCCESS; + long reg_dur = (dur * config->odr) / 1000000L; + config->dur = dur; + + if (reg_dur > LIS3DH_MAX_DUR) + reg_dur = LIS3DH_MAX_DUR; + + config->reg_dur = (unsigned char) reg_dur; + MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_INT1_DURATION, + (unsigned char)reg_dur); + return result; +} + +/** + * Sets the IRQ to fire when one of the IRQ events occur. Threshold and + * duration will not be used uless the type is MOT or NMOT. + * + * @param config configuration to apply to, suspend or resume + * @param irq_type The type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + */ +static int lis3dh_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis3dh_config *config, + int apply, + long irq_type) +{ + int result = ML_SUCCESS; + unsigned char reg1; + unsigned char reg2; + + config->irq_type = (unsigned char)irq_type; + if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x10; + reg2 = 0x00; + } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x40; + reg2 = config->mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + + if (apply) { + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG3, reg1); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_INT1_CFG, reg2); + } + + return result; +} + +/** + * Set the Output data rate for the particular configuration + * + * @param config Config to modify with new ODR + * @param odr Output data rate in units of 1/1000Hz + */ +static int lis3dh_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis3dh_config *config, + int apply, + long odr) +{ + unsigned char bits; + int result = ML_SUCCESS; + + if (odr > 400000) { + config->odr = 1250000; + bits = 0x90; + } else if (odr > 200000) { + config->odr = 400000; + bits = 0x70; + } else if (odr > 100000) { + config->odr = 200000; + bits = 0x60; + } else if (odr > 50000) { + config->odr = 100000; + bits = 0x50; + } else if (odr > 25000) { + config->odr = 50000; + bits = 0x40; + } else if (odr > 10000) { + config->odr = 25000; + bits = 0x30; + } else if (odr > 1000) { + config->odr = 10000; + bits = 0x20; + } else if (odr > 500) { + config->odr = 1000; + bits = 0x10; + } else { + config->odr = 0; + bits = 0; + } + + config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0xf); + lis3dh_set_dur(mlsl_handle, pdata, + config, apply, config->dur); + MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG1, + config->ctrl_reg1); + return result; +} + +/** + * Set the full scale range of the accels + * + * @param config pointer to configuration + * @param fsr requested full scale range + */ +static int lis3dh_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis3dh_config *config, + int apply, + long fsr) +{ + int result = ML_SUCCESS; + unsigned char reg1 = 0x48; + + if (fsr <= 2048) { + config->fsr = 2048; + } else if (fsr <= 4096) { + reg1 |= 0x10; + config->fsr = 4096; + } else if (fsr <= 8192) { + reg1 |= 0x20; + config->fsr = 8192; + } else { + reg1 |= 0x30; + config->fsr = 16348; + } + + lis3dh_set_ths(mlsl_handle, pdata, + config, apply, config->ths); + MPL_LOGV("FSR: %d\n", config->fsr); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG4, reg1); + + return result; +} + +static int lis3dh_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + unsigned char reg1; + unsigned char reg2; + struct lis3dh_private_data *private_data = pdata->private_data; + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG1, + private_data->suspend.ctrl_reg1); + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG2, 0x31); + reg1 = 0x48; + if (private_data->suspend.fsr == 16384) + reg1 |= 0x30; + else if (private_data->suspend.fsr == 8192) + reg1 |= 0x20; + else if (private_data->suspend.fsr == 4096) + reg1 |= 0x10; + else if (private_data->suspend.fsr == 2048) + reg1 |= 0x00; + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG4, reg1); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_INT1_THS, + private_data->suspend.reg_ths); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_INT1_DURATION, + private_data->suspend.reg_dur); + + if (private_data->suspend.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x10; + reg2 = 0x00; + } else if (private_data->suspend.irq_type == + MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x40; + reg2 = private_data->suspend.mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG3, reg1); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_INT1_CFG, reg2); + result = MLSLSerialRead(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG6, 1, ®1); + + return result; +} + +static int lis3dh_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + tMLError result; + unsigned char reg1; + unsigned char reg2; + struct lis3dh_private_data *private_data = pdata->private_data; + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG1, + private_data->resume.ctrl_reg1); + ERROR_CHECK(result); + MLOSSleep(6); + + /* Full Scale */ + reg1 = 0x48; + if (private_data->suspend.fsr == 16384) + reg1 |= 0x30; + else if (private_data->suspend.fsr == 8192) + reg1 |= 0x20; + else if (private_data->suspend.fsr == 4096) + reg1 |= 0x10; + else if (private_data->suspend.fsr == 2048) + reg1 |= 0x00; + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG4, reg1); + ERROR_CHECK(result); + + /* Configure high pass filter */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG2, 0x31); + ERROR_CHECK(result); + + if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x10; + reg2 = 0x00; + } else if (private_data->resume.irq_type == + MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x40; + reg2 = private_data->resume.mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG3, reg1); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_INT1_THS, + private_data->resume.reg_ths); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_INT1_DURATION, + private_data->resume.reg_dur); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_INT1_CFG, reg2); + ERROR_CHECK(result); + result = MLSLSerialRead(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG6, 1, ®1); + ERROR_CHECK(result); + return result; +} + +static int lis3dh_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result = ML_SUCCESS; + result = MLSLSerialRead(mlsl_handle, pdata->address, + LIS3DH_STATUS_REG, 1, data); + if (data[0] & 0x0F) { + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + return result; + } else + return ML_ERROR_ACCEL_DATA_NOT_READY; +} + +static int lis3dh_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + tMLError result; + + struct lis3dh_private_data *private_data; + private_data = (struct lis3dh_private_data *) + MLOSMalloc(sizeof(struct lis3dh_private_data)); + + if (!private_data) + return ML_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + private_data->resume.ctrl_reg1 = 0x67; + private_data->suspend.ctrl_reg1 = 0x18; + private_data->resume.mot_int1_cfg = 0x95; + private_data->suspend.mot_int1_cfg = 0x2a; + + lis3dh_set_odr(mlsl_handle, pdata, &private_data->suspend, + FALSE, 0); + lis3dh_set_odr(mlsl_handle, pdata, &private_data->resume, + FALSE, 200000); + lis3dh_set_fsr(mlsl_handle, pdata, &private_data->suspend, + FALSE, 2048); + lis3dh_set_fsr(mlsl_handle, pdata, &private_data->resume, + FALSE, 2048); + lis3dh_set_ths(mlsl_handle, pdata, &private_data->suspend, + FALSE, 80); + lis3dh_set_ths(mlsl_handle, pdata, &private_data->resume, + FALSE, 40); + lis3dh_set_dur(mlsl_handle, pdata, &private_data->suspend, + FALSE, 1000); + lis3dh_set_dur(mlsl_handle, pdata, &private_data->resume, + FALSE, 2540); + lis3dh_set_irq(mlsl_handle, pdata, &private_data->suspend, + FALSE, + MPU_SLAVE_IRQ_TYPE_NONE); + lis3dh_set_irq(mlsl_handle, pdata, &private_data->resume, + FALSE, + MPU_SLAVE_IRQ_TYPE_NONE); + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG1, 0x07); + MLOSSleep(6); + + return ML_SUCCESS; +} + +static int lis3dh_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + if (pdata->private_data) + return MLOSFree(pdata->private_data); + else + return ML_SUCCESS; +} + +static int lis3dh_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct lis3dh_private_data *private_data = pdata->private_data; + if (!data->data) + return ML_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return lis3dh_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return lis3dh_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return lis3dh_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return lis3dh_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_THS: + return lis3dh_set_ths(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_THS: + return lis3dh_set_ths(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_DUR: + return lis3dh_set_dur(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_DUR: + return lis3dh_set_dur(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return lis3dh_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return lis3dh_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + default: + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + return ML_SUCCESS; +} + +static int lis3dh_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct lis3dh_private_data *private_data = pdata->private_data; + if (!data->data) + return ML_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 ML_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return ML_SUCCESS; +} + +static struct ext_slave_descr lis3dh_descr = { + /*.init = */ lis3dh_init, + /*.exit = */ lis3dh_exit, + /*.suspend = */ lis3dh_suspend, + /*.resume = */ lis3dh_resume, + /*.read = */ lis3dh_read, + /*.config = */ lis3dh_config, + /*.get_config = */ lis3dh_get_config, + /*.name = */ "lis3dh", + /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, + /*.id = */ ACCEL_ID_LIS3DH, + /*.reg = */ 0x28 | 0x80, /* 0x80 for burst reads */ + /*.len = */ 6, + /*.endian = */ EXT_SLAVE_BIG_ENDIAN, + /*.range = */ {2, 480}, +}; + +struct ext_slave_descr *lis3dh_get_slave_descr(void) +{ + return &lis3dh_descr; +} +EXPORT_SYMBOL(lis3dh_get_slave_descr); + +/* + * @} +*/ diff --git a/drivers/misc/mpu3050/accel/lsm303a.c b/drivers/misc/mpu3050/accel/lsm303a.c old mode 100644 new mode 100755 index 47e2ac10d1ff..b8494962d3ac --- a/drivers/misc/mpu3050/accel/lsm303a.c +++ b/drivers/misc/mpu3050/accel/lsm303a.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -131,7 +144,10 @@ int lsm303dlha_read(void *mlsl_handle, struct ext_slave_platform_data *pdata, unsigned char *data) { - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + int result; + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + return result; } struct ext_slave_descr lsm303dlha_descr = { @@ -141,6 +157,7 @@ struct ext_slave_descr lsm303dlha_descr = { /*.resume = */ lsm303dlha_resume, /*.read = */ lsm303dlha_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "lsm303dlha", /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, /*.id = */ ACCEL_ID_LSM303, diff --git a/drivers/misc/mpu3050/accel/mantis.c b/drivers/misc/mpu3050/accel/mantis.c old mode 100644 new mode 100755 index 9e6f3e442e92..1cb9847fee05 --- a/drivers/misc/mpu3050/accel/mantis.c +++ b/drivers/misc/mpu3050/accel/mantis.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** * @defgroup ACCELDL (Motion Library - Accelerometer Driver Layer) @@ -10,7 +23,7 @@ * * @{ * @file lis331.c - * @brief Accelerometer setup and handling methods for ST LIS331 + * @brief Accelerometer setup and handling methods for Invensense MANTIS */ /* ------------------ */ @@ -29,35 +42,143 @@ #undef MPL_LOG_TAG #define MPL_LOG_TAG "MPL-acc" -#define ACCEL_ST_SLEEP_REG (0x20) -#define ACCEL_ST_SLEEP_MASK (0x20) - /* --------------------- */ /* - Variables. - */ /* --------------------- */ +struct mantis_config { + unsigned int odr; /* output data rate 1/1000 Hz*/ + unsigned int fsr; /* full scale range mg */ + unsigned int ths; /* Motion no-motion thseshold mg */ + unsigned int dur; /* Motion no-motion duration ms */ +}; + +struct mantis_private_data { + struct mantis_config suspend; + struct mantis_config resume; +}; + + /***************************************** - Accelerometer Initialization Functions -*****************************************/ + *Accelerometer Initialization Functions + *****************************************/ +/** + * 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 + */ +void mantis_set_odr(struct mantis_config *config, + long odr) +{ + config->odr = odr; +} + +void mantis_set_ths(struct mantis_config *config, + long ths) +{ + if (ths < 0) + ths = 0; + + config->ths = ths; + MPL_LOGV("THS: %d\n", config->ths); +} + +void mantis_set_dur(struct mantis_config *config, + long dur) +{ + if (dur < 0) + dur = 0; + + config->dur = dur; + MPL_LOGV("DUR: %d\n", config->dur); +} + +static void mantis_set_fsr( + struct mantis_config *config, + long fsr) +{ + if (fsr <= 2000) + config->fsr = 2000; + else if (fsr <= 4000) + config->fsr = 4000; + else + config->fsr = 8000; + + MPL_LOGV("FSR: %d\n", config->fsr); +} + +static int mantis_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + struct mantis_private_data *private_data; + private_data = (struct mantis_private_data *) + MLOSMalloc(sizeof(struct mantis_private_data)); + + if (!private_data) + return ML_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + mantis_set_odr(&private_data->suspend, 0); + mantis_set_odr(&private_data->resume, 200000); + mantis_set_fsr(&private_data->suspend, 2000); + mantis_set_fsr(&private_data->resume, 2000); + mantis_set_ths(&private_data->suspend, 80); + mantis_set_ths(&private_data->resume, 40); + mantis_set_dur(&private_data->suspend, 1000); + mantis_set_dur(&private_data->resume, 2540); + return ML_SUCCESS; +} + +static int mantis_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + if (pdata->private_data) + return MLOSFree(pdata->private_data); + else + return ML_SUCCESS; +} int mantis_suspend(void *mlsl_handle, struct ext_slave_descr *slave, struct ext_slave_platform_data *pdata) { + unsigned char reg; + int result; + + result = MLSLSerialRead(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, 1, ®); + ERROR_CHECK(result); + reg |= (BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA); + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, reg); + ERROR_CHECK(result); + return ML_SUCCESS; } -/* full scale setting - register & mask */ -#define ACCEL_ST_CTRL_REG (0x23) -#define ACCEL_ST_CTRL_MASK (0x30) - int mantis_resume(void *mlsl_handle, struct ext_slave_descr *slave, struct ext_slave_platform_data *pdata) { int result = ML_SUCCESS; -#ifdef M_HW unsigned char reg; + struct mantis_private_data *private_data; + + private_data = (struct mantis_private_data *) pdata->private_data; + + MLSLSerialRead(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, 1, ®); + + reg &= ~(BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA); + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, reg); + ERROR_CHECK(result); if (slave->range.mantissa == 2) reg = 0; @@ -72,7 +193,28 @@ int mantis_resume(void *mlsl_handle, result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, MPUREG_ACCEL_CONFIG, reg); -#endif + ERROR_CHECK(result); + + reg = (unsigned char) private_data->suspend.ths / ACCEL_MOT_THR_LSB; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + MPUREG_ACCEL_MOT_THR, reg); + ERROR_CHECK(result); + + reg = (unsigned char) + ACCEL_ZRMOT_THR_LSB_CONVERSION(private_data->resume.ths); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + MPUREG_ACCEL_ZRMOT_THR, reg); + ERROR_CHECK(result); + + reg = (unsigned char) private_data->suspend.ths / ACCEL_MOT_DUR_LSB; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + MPUREG_ACCEL_MOT_DUR, reg); + ERROR_CHECK(result); + + reg = (unsigned char) private_data->resume.ths / ACCEL_ZRMOT_DUR_LSB; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + MPUREG_ACCEL_ZRMOT_DUR, reg); + ERROR_CHECK(result); return result; } @@ -80,16 +222,69 @@ int mantis_read(void *mlsl_handle, struct ext_slave_descr *slave, struct ext_slave_platform_data *pdata, unsigned char *data) { - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + int result; + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + return result; +} + +static int mantis_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct mantis_private_data *private_data = pdata->private_data; + if (!data->data) + return ML_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + mantis_set_odr(&private_data->suspend, + *((long *)data->data)); + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + mantis_set_odr(&private_data->resume, + *((long *)data->data)); + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + mantis_set_fsr(&private_data->suspend, + *((long *)data->data)); + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + mantis_set_fsr(&private_data->resume, + *((long *)data->data)); + break; + case MPU_SLAVE_CONFIG_MOT_THS: + mantis_set_ths(&private_data->suspend, + (*((long *)data->data))); + break; + case MPU_SLAVE_CONFIG_NMOT_THS: + mantis_set_ths(&private_data->resume, + (*((long *)data->data))); + break; + case MPU_SLAVE_CONFIG_MOT_DUR: + mantis_set_dur(&private_data->suspend, + (*((long *)data->data))); + break; + case MPU_SLAVE_CONFIG_NMOT_DUR: + mantis_set_dur(&private_data->resume, + (*((long *)data->data))); + break; + default: + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return ML_SUCCESS; } struct ext_slave_descr mantis_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, + /*.init = */ mantis_init, + /*.exit = */ mantis_exit, /*.suspend = */ mantis_suspend, /*.resume = */ mantis_resume, /*.read = */ mantis_read, - /*.config = */ NULL, + /*.config = */ mantis_config, + /*.get_config = */ NULL, /*.name = */ "mantis", /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, /*.id = */ ACCEL_ID_MPU6000, diff --git a/drivers/misc/mpu3050/accel/mma8450.c b/drivers/misc/mpu3050/accel/mma8450.c old mode 100644 new mode 100755 index fec9c741a3a8..ffc92fd8bbdf --- a/drivers/misc/mpu3050/accel/mma8450.c +++ b/drivers/misc/mpu3050/accel/mma8450.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -18,9 +31,11 @@ /* - Include Files. - */ /* ------------------ */ +#include #include "mpu.h" #include "mlsl.h" #include "mlos.h" +#include #include #undef MPL_LOG_TAG @@ -90,7 +105,8 @@ int mma8450_resume(void *mlsl_handle, /* XYZ_DATA_CFG: event flag enabled on all axis */ result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x16, 0x05); + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + 0x16, 0x05); ERROR_CHECK(result); /* CTRL_REG1: rate + scale config + wakeup */ result = @@ -106,7 +122,13 @@ int mma8450_read(void *mlsl_handle, struct ext_slave_platform_data *pdata, unsigned char *data) { - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + int result; + unsigned char local_data[4]; /* Status register + 3 bytes data */ + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, sizeof(local_data), local_data); + ERROR_CHECK(result); + memcpy(data, &local_data[1], (slave->len)-1); + return result; } struct ext_slave_descr mma8450_descr = { @@ -116,11 +138,12 @@ struct ext_slave_descr mma8450_descr = { /*.resume = */ mma8450_resume, /*.read = */ mma8450_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "mma8450", /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, /*.id = */ ACCEL_ID_MMA8450, /*.reg = */ 0x00, - /*.len = */ 3, + /*.len = */ 4, /*.endian = */ EXT_SLAVE_FS8_BIG_ENDIAN, /*.range = */ {2, 0}, }; diff --git a/drivers/misc/mpu3050/accel/mma845x.c b/drivers/misc/mpu3050/accel/mma845x.c new file mode 100755 index 000000000000..27150ad86994 --- /dev/null +++ b/drivers/misc/mpu3050/accel/mma845x.c @@ -0,0 +1,158 @@ +/* + $License: + Copyright (C) 2010 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 . + $ + */ + +/** + * @defgroup ACCELDL (Motion Library - Accelerometer Driver Layer) + * @brief Provides the interface to setup and handle an accelerometers + * connected to the secondary I2C interface of the gyroscope. + * + * @{ + * @file mma845x.c + * @brief Accelerometer setup and handling methods for Freescale MMA845X + */ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#ifdef __KERNEL__ +#include +#endif + +#include +#include "mpu.h" +#include "mlsl.h" +#include "mlos.h" +#include + +#include +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +#define ACCEL_MMA845X_CTRL_REG1 (0x2A) +#define ACCEL_MMA845X_SLEEP_MASK (0x01) + +/* full scale setting - register & mask */ +#define ACCEL_MMA845X_CFG_REG (0x0E) +#define ACCEL_MMA845X_CTRL_MASK (0x03) + +/* --------------------- */ +/* - Variables. - */ +/* --------------------- */ + +/***************************************** + Accelerometer Initialization Functions +*****************************************/ + +int mma845x_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char reg; + result = + MLSLSerialRead(mlsl_handle, pdata->address, + ACCEL_MMA845X_CTRL_REG1, 1, ®); + ERROR_CHECK(result); + reg &= ~ACCEL_MMA845X_SLEEP_MASK; + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + ACCEL_MMA845X_CTRL_REG1, reg); + ERROR_CHECK(result); + return result; +} + + +int mma845x_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + unsigned char reg; + + result = MLSLSerialRead(mlsl_handle, pdata->address, + ACCEL_MMA845X_CFG_REG, 1, ®); + ERROR_CHECK(result); + + /* data rate = 200Hz */ + + /* Full Scale */ + reg &= ~ACCEL_MMA845X_CTRL_MASK; + if (slave->range.mantissa == 4) + reg |= 0x1; + else if (slave->range.mantissa == 8) + reg |= 0x2; + else { + slave->range.mantissa = 2; + reg |= 0x0; + } + slave->range.fraction = 0; + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + ACCEL_MMA845X_CFG_REG, reg); + ERROR_CHECK(result); + /* 200Hz + active mode */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + ACCEL_MMA845X_CTRL_REG1, 0x11); + ERROR_CHECK(result); + + return result; +} + +int mma845x_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result; + unsigned char local_data[7]; /* Status register + 6 bytes data */ + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, sizeof(local_data), local_data); + ERROR_CHECK(result); + memcpy(data, &local_data[1], slave->len); + return result; +} + +struct ext_slave_descr mma845x_descr = { + /*.init = */ NULL, + /*.exit = */ NULL, + /*.suspend = */ mma845x_suspend, + /*.resume = */ mma845x_resume, + /*.read = */ mma845x_read, + /*.config = */ NULL, + /*.get_config = */ NULL, + /*.name = */ "mma845x", + /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, + /*.id = */ ACCEL_ID_MMA845X, + /*.reg = */ 0x00, + /*.len = */ 6, + /*.endian = */ EXT_SLAVE_FS16_BIG_ENDIAN, + /*.range = */ {2, 0}, +}; + +struct ext_slave_descr *mma845x_get_slave_descr(void) +{ + return &mma845x_descr; +} +EXPORT_SYMBOL(mma845x_get_slave_descr); + +/** + * @} + */ diff --git a/drivers/misc/mpu3050/compass/ak8975.c b/drivers/misc/mpu3050/compass/ak8975.c old mode 100644 new mode 100755 index 5f020cfad2f6..b8aed30ba39b --- a/drivers/misc/mpu3050/compass/ak8975.c +++ b/drivers/misc/mpu3050/compass/ak8975.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -147,13 +160,84 @@ int ak8975_read(void *mlsl_handle, return status; } +static int ak8975_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 ML_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_WRITE_REGISTERS: + result = MLSLSerialWrite(mlsl_handle, pdata->address, + data->len, + (unsigned char *)data->data); + ERROR_CHECK(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 ML_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return ML_SUCCESS; +} + +static int ak8975_get_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 ML_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_READ_REGISTERS: + { + unsigned char *serial_data = (unsigned char *)data->data; + result = MLSLSerialRead(mlsl_handle, pdata->address, + serial_data[0], + data->len - 1, + &serial_data[1]); + ERROR_CHECK(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 ML_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return ML_SUCCESS; +} + struct ext_slave_descr ak8975_descr = { /*.init = */ NULL, /*.exit = */ NULL, /*.suspend = */ ak8975_suspend, /*.resume = */ ak8975_resume, /*.read = */ ak8975_read, - /*.config = */ NULL, + /*.config = */ ak8975_config, + /*.get_config = */ ak8975_get_config, /*.name = */ "ak8975", /*.type = */ EXT_SLAVE_TYPE_COMPASS, /*.id = */ COMPASS_ID_AKM, diff --git a/drivers/misc/mpu3050/compass/ami306.c b/drivers/misc/mpu3050/compass/ami306.c new file mode 100755 index 000000000000..75ca007ef01c --- /dev/null +++ b/drivers/misc/mpu3050/compass/ami306.c @@ -0,0 +1,191 @@ +/* + $License: + Copyright (C) 2010 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 . + $ + */ + +/** + * @defgroup COMPASSDL (Motion Library - Accelerometer Driver Layer) + * @brief Provides the interface to setup and handle an accelerometers + * connected to the secondary I2C interface of the gyroscope. + * + * @{ + * @file ami306.c + * @brief Magnetometer setup and handling methods for Aichi AMI306 + * compass. + */ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#ifdef __KERNEL__ +#include +#endif + +#include + +#include "mpu.h" +#include "mlsl.h" +#include "mlos.h" + +#include +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +#define AMI306_REG_DATAX (0x10) +#define AMI306_REG_STAT1 (0x18) +#define AMI306_REG_CNTL1 (0x1B) +#define AMI306_REG_CNTL2 (0x1C) +#define AMI306_REG_CNTL3 (0x1D) +#define AMI306_REG_CNTL4_1 (0x5C) +#define AMI306_REG_CNTL4_2 (0x5D) + +#define AMI306_BIT_CNTL1_PC1 (0x80) +#define AMI306_BIT_CNTL1_ODR1 (0x10) +#define AMI306_BIT_CNTL1_FS1 (0x02) + +#define AMI306_BIT_CNTL2_IEN (0x10) +#define AMI306_BIT_CNTL2_DREN (0x08) +#define AMI306_BIT_CNTL2_DRP (0x04) +#define AMI306_BIT_CNTL3_F0RCE (0x40) + +int ami306_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char reg; + result = + MLSLSerialRead(mlsl_handle, pdata->address, AMI306_REG_CNTL1, + 1, ®); + ERROR_CHECK(result); + + reg &= ~(AMI306_BIT_CNTL1_PC1|AMI306_BIT_CNTL1_FS1); + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + AMI306_REG_CNTL1, reg); + ERROR_CHECK(result); + + return result; +} + +int ami306_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + unsigned char regs[] = { + AMI306_REG_CNTL4_1, + 0x7E, + 0xA0 + }; + /* Step1. Set CNTL1 reg to power model active (Write CNTL1:PC1=1) */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + AMI306_REG_CNTL1, + AMI306_BIT_CNTL1_PC1|AMI306_BIT_CNTL1_FS1); + ERROR_CHECK(result); + + /* Step2. Set CNTL2 reg to DRDY active high and enabled + (Write CNTL2:DREN=1) */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + AMI306_REG_CNTL2, + AMI306_BIT_CNTL2_DREN | + AMI306_BIT_CNTL2_DRP); + ERROR_CHECK(result); + + /* Step3. Set CNTL4 reg to for measurement speed (Write CNTL4, 0xA07E) */ + result = + MLSLSerialWrite(mlsl_handle, pdata->address, DIM(regs), regs); + ERROR_CHECK(result); + + /* Step4. skipped */ + + /* Step5. Set CNTL3 reg to forced measurement period + (Write CNTL3:FORCE=1) */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + AMI306_REG_CNTL3, AMI306_BIT_CNTL3_F0RCE); + + return result; +} + +int ami306_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, unsigned char *data) +{ + unsigned char stat; + int result = ML_SUCCESS; + int status = ML_SUCCESS; + + + /* Measurement(x,y,z) */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + AMI306_REG_CNTL3, + AMI306_BIT_CNTL3_F0RCE); + ERROR_CHECK(result); + udelay(500); + + /* Step6. Read status reg and check if data ready (DRDY) */ + result = + MLSLSerialRead(mlsl_handle, pdata->address, AMI306_REG_STAT1, + 1, &stat); + ERROR_CHECK(result); + + /* Step6. Does DRDY output the rising edge? */ + if (stat & 0x40) { + result = + MLSLSerialRead(mlsl_handle, pdata->address, + AMI306_REG_DATAX, 6, + (unsigned char *) data); + ERROR_CHECK(result); + status = ML_SUCCESS; + } else if (stat & 0x20) + status = ML_ERROR_COMPASS_DATA_OVERFLOW; + + return status; +} + +struct ext_slave_descr ami306_descr = { + /*.init = */ NULL, + /*.exit = */ NULL, + /*.suspend = */ ami306_suspend, + /*.resume = */ ami306_resume, + /*.read = */ ami306_read, + /*.config = */ NULL, + /*.get_config = */ NULL, + /*.name = */ "ami306", + /*.type = */ EXT_SLAVE_TYPE_COMPASS, + /*.id = */ COMPASS_ID_AMI306, + /*.reg = */ 0x10, + /*.len = */ 6, + /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, + /*.range = */ {5461, 3333} + /* For AMI305,the range field needs to be modified to {9830.4f}*/ +}; + +struct ext_slave_descr *ami306_get_slave_descr(void) +{ + return &ami306_descr; +} +EXPORT_SYMBOL(ami306_get_slave_descr); + +/** + * @} + */ diff --git a/drivers/misc/mpu3050/compass/ami30x.c b/drivers/misc/mpu3050/compass/ami30x.c old mode 100644 new mode 100755 index 28cd5f415ca3..5e4a33efc7f2 --- a/drivers/misc/mpu3050/compass/ami30x.c +++ b/drivers/misc/mpu3050/compass/ami30x.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -132,6 +145,7 @@ struct ext_slave_descr ami30x_descr = { /*.resume = */ ami30x_resume, /*.read = */ ami30x_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "ami30x", /*.type = */ EXT_SLAVE_TYPE_COMPASS, /*.id = */ COMPASS_ID_AMI30X, diff --git a/drivers/misc/mpu3050/compass/hmc5883.c b/drivers/misc/mpu3050/compass/hmc5883.c old mode 100644 new mode 100755 index 3e67d2e97dd9..02afd58fd7b7 --- a/drivers/misc/mpu3050/compass/hmc5883.c +++ b/drivers/misc/mpu3050/compass/hmc5883.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -220,6 +233,7 @@ struct ext_slave_descr hmc5883_descr = { /*.resume = */ hmc5883_resume, /*.read = */ hmc5883_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "hmc5883", /*.type = */ EXT_SLAVE_TYPE_COMPASS, /*.id = */ COMPASS_ID_HMC5883, diff --git a/drivers/misc/mpu3050/compass/hscdtd002b.c b/drivers/misc/mpu3050/compass/hscdtd002b.c new file mode 100755 index 000000000000..bf26cae06d2d --- /dev/null +++ b/drivers/misc/mpu3050/compass/hscdtd002b.c @@ -0,0 +1,163 @@ +/* + $License: + Copyright (C) 2010 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 . + $ + */ + +/** + * @brief Provides the interface to setup and handle a compass + * connected to the primary I2C interface of the gyroscope. + * + * @{ + * @file hscdtd002b.c + * @brief Magnetometer setup and handling methods for Alps hscdtd002b + * compass. + */ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#ifdef __KERNEL__ +#include +#endif + +#include "mpu.h" +#include "mlsl.h" +#include "mlos.h" + +#include +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/*----- ALPS HSCDTD002B Registers ------*/ +#define COMPASS_HSCDTD002B_STAT (0x18) +#define COMPASS_HSCDTD002B_CTRL1 (0x1B) +#define COMPASS_HSCDTD002B_CTRL2 (0x1C) +#define COMPASS_HSCDTD002B_CTRL3 (0x1D) +#define COMPASS_HSCDTD002B_DATAX (0x10) + +/* --------------------- */ +/* - Variables. - */ +/* --------------------- */ + +/***************************************** + Compass Initialization Functions +*****************************************/ + +int hscdtd002b_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + + /* Power mode: stand-by */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_CTRL1, 0x00); + ERROR_CHECK(result); + MLOSSleep(1); /* turn-off time */ + + return result; +} + +int hscdtd002b_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + + /* Soft reset */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_CTRL3, 0x80); + ERROR_CHECK(result); + /* Force state; Power mode: active */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_CTRL1, 0x82); + ERROR_CHECK(result); + /* Data ready enable */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_CTRL2, 0x08); + ERROR_CHECK(result); + MLOSSleep(1); /* turn-on time */ + + return result; +} + +int hscdtd002b_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + unsigned char stat; + tMLError result = ML_SUCCESS; + int status = ML_SUCCESS; + + /* Read status reg. to check if data is ready */ + result = + MLSLSerialRead(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_STAT, 1, &stat); + ERROR_CHECK(result); + if (stat & 0x40) { + result = + MLSLSerialRead(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_DATAX, 6, + (unsigned char *) data); + ERROR_CHECK(result); + status = ML_SUCCESS; + } else if (stat & 0x20) { + status = ML_ERROR_COMPASS_DATA_OVERFLOW; + } else { + status = ML_ERROR_COMPASS_DATA_NOT_READY; + } + /* trigger next measurement read */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_CTRL3, 0x40); + ERROR_CHECK(result); + + return status; +} + +struct ext_slave_descr hscdtd002b_descr = { + /*.init = */ NULL, + /*.exit = */ NULL, + /*.suspend = */ hscdtd002b_suspend, + /*.resume = */ hscdtd002b_resume, + /*.read = */ hscdtd002b_read, + /*.config = */ NULL, + /*.get_config = */ NULL, + /*.name = */ "hscdtd002b", + /*.type = */ EXT_SLAVE_TYPE_COMPASS, + /*.id = */ COMPASS_ID_HSCDTD002B, + /*.reg = */ 0x10, + /*.len = */ 6, + /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, + /*.range = */ {9830, 4000}, +}; + +struct ext_slave_descr *hscdtd002b_get_slave_descr(void) +{ + return &hscdtd002b_descr; +} +EXPORT_SYMBOL(hscdtd002b_get_slave_descr); + +/** + * @} +**/ diff --git a/drivers/misc/mpu3050/compass/hscdtd004a.c b/drivers/misc/mpu3050/compass/hscdtd004a.c new file mode 100755 index 000000000000..43fc14a23fc4 --- /dev/null +++ b/drivers/misc/mpu3050/compass/hscdtd004a.c @@ -0,0 +1,162 @@ +/* + $License: + Copyright (C) 2010 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 . + $ + */ + +/** + * @brief Provides the interface to setup and handle a compass + * connected to the primary I2C interface of the gyroscope. + * + * @{ + * @file hscdtd004a.c + * @brief Magnetometer setup and handling methods for Alps hscdtd004a + * compass. + */ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#ifdef __KERNEL__ +#include +#endif + +#include "mpu.h" +#include "mlsl.h" +#include "mlos.h" + +#include +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/*----- ALPS HSCDTD004A Registers ------*/ +#define COMPASS_HSCDTD004A_STAT (0x18) +#define COMPASS_HSCDTD004A_CTRL1 (0x1B) +#define COMPASS_HSCDTD004A_CTRL2 (0x1C) +#define COMPASS_HSCDTD004A_CTRL3 (0x1D) +#define COMPASS_HSCDTD004A_DATAX (0x10) + +/* --------------------- */ +/* - Variables. - */ +/* --------------------- */ + +/***************************************** + Compass Initialization Functions +*****************************************/ + +int hscdtd004a_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + + /* Power mode: stand-by */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_CTRL1, 0x00); + ERROR_CHECK(result); + MLOSSleep(1); /* turn-off time */ + + return result; +} + +int hscdtd004a_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + + /* Soft reset */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_CTRL3, 0x80); + ERROR_CHECK(result); + /* Normal state; Power mode: active */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_CTRL1, 0x82); + ERROR_CHECK(result); + /* Data ready enable */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_CTRL2, 0x7C); + ERROR_CHECK(result); + MLOSSleep(1); /* turn-on time */ + return result; +} + +int hscdtd004a_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + unsigned char stat; + tMLError result = ML_SUCCESS; + int status = ML_SUCCESS; + + /* Read status reg. to check if data is ready */ + result = + MLSLSerialRead(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_STAT, 1, &stat); + ERROR_CHECK(result); + if (stat & 0x48) { + result = + MLSLSerialRead(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_DATAX, 6, + (unsigned char *) data); + ERROR_CHECK(result); + status = ML_SUCCESS; + } else if (stat & 0x68) { + status = ML_ERROR_COMPASS_DATA_OVERFLOW; + } else { + status = ML_ERROR_COMPASS_DATA_NOT_READY; + } + /* trigger next measurement read */ + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_CTRL3, 0x40); + ERROR_CHECK(result); + return status; + +} + +struct ext_slave_descr hscdtd004a_descr = { + /*.init = */ NULL, + /*.exit = */ NULL, + /*.suspend = */ hscdtd004a_suspend, + /*.resume = */ hscdtd004a_resume, + /*.read = */ hscdtd004a_read, + /*.config = */ NULL, + /*.get_config = */ NULL, + /*.name = */ "hscdtd004a", + /*.type = */ EXT_SLAVE_TYPE_COMPASS, + /*.id = */ COMPASS_ID_HSCDTD004A, + /*.reg = */ 0x10, + /*.len = */ 6, + /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, + /*.range = */ {9830, 4000}, +}; + +struct ext_slave_descr *hscdtd004a_get_slave_descr(void) +{ + return &hscdtd004a_descr; +} +EXPORT_SYMBOL(hscdtd004a_get_slave_descr); + +/** + * @} +**/ diff --git a/drivers/misc/mpu3050/compass/lsm303m.c b/drivers/misc/mpu3050/compass/lsm303m.c old mode 100644 new mode 100755 index 082ee45be05f..871d002fd364 --- a/drivers/misc/mpu3050/compass/lsm303m.c +++ b/drivers/misc/mpu3050/compass/lsm303m.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -210,6 +223,7 @@ struct ext_slave_descr lsm303dlhm_descr = { /*.resume = */ lsm303dlhm_resume, /*.read = */ lsm303dlhm_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "lsm303dlhm", /*.type = */ EXT_SLAVE_TYPE_COMPASS, /*.id = */ COMPASS_ID_LSM303, diff --git a/drivers/misc/mpu3050/compass/mmc314x.c b/drivers/misc/mpu3050/compass/mmc314x.c old mode 100644 new mode 100755 index 4bff05d0cb2f..010d7a78d149 --- a/drivers/misc/mpu3050/compass/mmc314x.c +++ b/drivers/misc/mpu3050/compass/mmc314x.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -150,6 +163,7 @@ struct ext_slave_descr mmc314x_descr = { /*.resume = */ mmc314x_resume, /*.read = */ mmc314x_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "mmc314x", /*.type = */ EXT_SLAVE_TYPE_COMPASS, /*.id = */ COMPASS_ID_MMC314X, diff --git a/drivers/misc/mpu3050/compass/yas529-kernel.c b/drivers/misc/mpu3050/compass/yas529-kernel.c old mode 100644 new mode 100755 index b4be440baa14..239ab669cc1b --- a/drivers/misc/mpu3050/compass/yas529-kernel.c +++ b/drivers/misc/mpu3050/compass/yas529-kernel.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** * @defgroup ACCELDL (Motion Library - Accelerometer Driver Layer) @@ -443,6 +456,7 @@ struct ext_slave_descr yas529_descr = { /*.resume = */ yas529_resume, /*.read = */ yas529_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "yas529", /*.type = */ EXT_SLAVE_TYPE_COMPASS, /*.id = */ COMPASS_ID_YAS529, diff --git a/drivers/misc/mpu3050/compass/yas530-kernel.c b/drivers/misc/mpu3050/compass/yas530-kernel.c new file mode 100755 index 000000000000..f6dbb5691eb6 --- /dev/null +++ b/drivers/misc/mpu3050/compass/yas530-kernel.c @@ -0,0 +1,163 @@ +/* + $License: + Copyright (C) 2010 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 . + $License: + Copyright (C) 2010 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 . + $ + */ + /** + * @defgroup ACCELDL (Motion Library - Accelerometer Driver Layer) + * @brief Provides the interface to setup and handle an accelerometers + * connected to the secondary I2C interface of the gyroscope. + * + * @{ + * @file yas530.c + * @brief Magnetometer setup and handling methods for Yamaha yas530 + * compass. + */ + + /* ------------------ */ + /* - Include Files. - */ + /* ------------------ */ + +#include "mpu.h" +#include "mltypes.h" + +#include "mlsl.h" +#include "mlos.h" + +#ifdef __KERNEL__ +#include +#include +#include +#endif + +#include +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-yas530:" + + +extern int geomagnetic_api_resume(void); +extern int geomagnetic_api_suspend(void); +extern int geomagnetic_api_read(int *xyz, int *raw, int *xy1y2, int *accuracy); + + /***************************************** + Compass Initialization Functions + *****************************************/ + +static int +yas530_suspend +( + void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata +) +{ + int result = ML_SUCCESS; + + geomagnetic_api_suspend(); + + return result; +} + + +static int +yas530_resume +( + void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata +) +{ + geomagnetic_api_resume(); + return ML_SUCCESS; +} + + +static int +yas530_read +( + void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data +) +{ + int xyz[3]; + int raw[3]; + short rawfixed[3]; + int xy1y2[3]; + int accuracy; + + geomagnetic_api_read(xyz, raw, xy1y2, &accuracy); + + rawfixed[0] = (short) (xyz[0]/100); + rawfixed[1] = (short) (xyz[1]/100); + rawfixed[2] = (short) (xyz[2]/100); + + data[0] = rawfixed[0] >> 8; + data[1] = rawfixed[0] & 0xFF; + data[2] = rawfixed[1] >> 8; + data[3] = rawfixed[1] & 0xFF; + data[4] = rawfixed[2] >> 8; + data[5] = rawfixed[2] & 0xFF; + + return ML_SUCCESS; +} + + + +struct ext_slave_descr yas530_descr = { + /*.init = */ NULL, + /*.exit = */ NULL, + /*.suspend = */ yas530_suspend, + /*.resume = */ yas530_resume, + /*.read = */ yas530_read, + /*.config = */ NULL, + /*.name = */ "yas530", + /*.type = */ EXT_SLAVE_TYPE_COMPASS, + /*.id = */ COMPASS_ID_YAS530, + /*.reg = */ 0x06, + /*.len = */ 6, + /*.endian = */ EXT_SLAVE_BIG_ENDIAN, + /*.range = */ {3276, 8001}, +}; + +struct ext_slave_descr *yas530_get_slave_descr(void) +{ + return &yas530_descr; +} + +#ifdef __KERNEL__ + EXPORT_SYMBOL(yas530_get_slave_descr); +#endif + + /** + * @} + **/ diff --git a/drivers/misc/mpu3050/compass/yas530.c b/drivers/misc/mpu3050/compass/yas530.c new file mode 100755 index 000000000000..9fc9acbde65b --- /dev/null +++ b/drivers/misc/mpu3050/compass/yas530.c @@ -0,0 +1,406 @@ +/* + $License: + Copyright (C) 2010 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 . + $ + */ +/** + * @defgroup ACCELDL (Motion Library - Accelerometer Driver Layer) + * @brief Provides the interface to setup and handle an accelerometers + * connected to the secondary I2C interface of the gyroscope. + * + * @{ + * @file yas530.c + * @brief Magnetometer setup and handling methods for Yamaha yas530 + * compass. + */ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#ifdef __KERNEL__ +#include +#endif + +#include "mpu.h" +#include "mlsl.h" +#include "mlos.h" + +#include +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/*----- YAMAHA YAS529 Registers ------*/ +#define YAS530_REGADDR_DEVICE_ID (0x80) +#define YAS530_REGADDR_ACTUATE_INIT_COIL (0x81) +#define YAS530_REGADDR_MEASURE_COMMAND (0x82) +#define YAS530_REGADDR_CONFIG (0x83) +#define YAS530_REGADDR_MEASURE_INTERVAL (0x84) +#define YAS530_REGADDR_OFFSET_X (0x85) +#define YAS530_REGADDR_OFFSET_Y1 (0x86) +#define YAS530_REGADDR_OFFSET_Y2 (0x87) +#define YAS530_REGADDR_TEST1 (0x88) +#define YAS530_REGADDR_TEST2 (0x89) +#define YAS530_REGADDR_CAL (0x90) +#define YAS530_REGADDR_MEASURE_DATA (0xb0) + + +/* --------------------- */ +/* - Variables. - */ +/* --------------------- */ +static int Cx, Cy1, Cy2; +static int /*a1, */a2, a3, a4, a5, a6, a7, a8, a9; +static int k; + +static char dx, dy1, dy2; +static char d2, d3, d4, d5, d6, d7, d8, d9, d0; +static char dck; + +/***************************************** + Accelerometer Initialization Functions +*****************************************/ + +int set_hardware_offset(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + char offset_x, char offset_y1, char offset_y2) +{ + char data; + int result = ML_SUCCESS; + + data = offset_x & 0x3f; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + YAS530_REGADDR_OFFSET_X, data); + ERROR_CHECK(result); + + data = offset_y1 & 0x3f; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + YAS530_REGADDR_OFFSET_Y1, data); + ERROR_CHECK(result); + + data = offset_y2 & 0x3f; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + YAS530_REGADDR_OFFSET_Y2, data); + ERROR_CHECK(result); + + return result; +} + +int set_measure_command(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + int ldtc, int fors, int dlymes) +{ + int result = ML_SUCCESS; + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + YAS530_REGADDR_MEASURE_COMMAND, 0x01); + ERROR_CHECK(result); + + return result; +} + +int measure_normal(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + int *busy, unsigned short *t, + unsigned short *x, unsigned short *y1, unsigned short *y2) +{ + unsigned char data[8]; + unsigned short b, to, xo, y1o, y2o; + int result; + + result = set_measure_command(mlsl_handle, slave, pdata, 0, 0, 0); + MLOSSleep(2); + + result = MLSLSerialRead(mlsl_handle, pdata->address, + YAS530_REGADDR_MEASURE_DATA, 8, data); + ERROR_CHECK(result); + MLOSSleep(2); + + b = (data[0]>>7) & 0x01; + to = ((data[0]<<2) & 0x1fc) | ((data[1]>>6) & 0x03); + xo = ((data[2]<<5) & 0xfe0) | ((data[3]>>3) & 0x1f); + y1o = ((data[4]<<5) & 0xfe0) | ((data[5]>>3) & 0x1f); + y2o = ((data[6]<<5) & 0xfe0) | ((data[7]>>3) & 0x1f); + + *busy = b; + *t = to; + *x = xo; + *y1 = y1o; + *y2 = y2o; + + return result; +} + +int check_offset(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + char offset_x, char offset_y1, char offset_y2, + int *flag_x, int *flag_y1, int *flag_y2) +{ + int result; + int busy; + short t, x, y1, y2; + + result = set_hardware_offset(mlsl_handle, slave, pdata, + offset_x, offset_y1, offset_y2); + ERROR_CHECK(result); + + result = measure_normal(mlsl_handle, slave, pdata, + &busy, &t, &x, &y1, &y2); + ERROR_CHECK(result); + + *flag_x = 0; + *flag_y1 = 0; + *flag_y2 = 0; + + if (x > 2048) + *flag_x = 1; + if (y1 > 2048) + *flag_y1 = 1; + if (y2 > 2048) + *flag_y2 = 1; + if (x < 2048) + *flag_x = -1; + if (y1 < 2048) + *flag_y1 = -1; + if (y2 < 2048) + *flag_y2 = -1; + + return result; +} + +int measure_and_set_offset(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + char *offset) +{ + int i; + int result = ML_SUCCESS; + char offset_x = 0, offset_y1 = 0, offset_y2 = 0; + int flag_x = 0, flag_y1 = 0, flag_y2 = 0; + static const int correct[5] = {16, 8, 4, 2, 1}; + + for (i = 0; i < 5; i++) { + result = check_offset(mlsl_handle, slave, pdata, + offset_x, offset_y1, offset_y2, + &flag_x, &flag_y1, &flag_y2); + ERROR_CHECK(result); + + if (flag_x) + offset_x += flag_x * correct[i]; + if (flag_y1) + offset_y1 += flag_y1 * correct[i]; + if (flag_y2) + offset_y2 += flag_y2 * correct[i]; + } + + result = set_hardware_offset(mlsl_handle, slave, pdata, + offset_x, offset_y1, offset_y2); + ERROR_CHECK(result); + + offset[0] = offset_x; + offset[1] = offset_y1; + offset[2] = offset_y2; + + return result; +} + +void coordinate_conversion(short x, short y1, short y2, short t, + int *xo, int *yo, int *zo) +{ + int sx, sy1, sy2, sy, sz; + int hx, hy, hz; + + sx = x - (Cx * t) / 100; + sy1 = y1 - (Cy1 * t) / 100; + sy2 = y2 - (Cy2 * t) / 100; + + sy = sy1 - sy2; + sz = -sy1 - sy2; + + hx = k * ((100 * sx + a2 * sy + a3 * sz) / 10); + hy = k * ((a4 * sx + a5 * sy + a6 * sz) / 10); + hz = k * ((a7 * sx + a8 * sy + a9 * sz) / 10); + + *xo = hx; + *yo = hy; + *zo = hz; +} + +int yas530_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + + return result; +} + +int yas530_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + + unsigned char dummyData = 0x00; + char offset[3] = {0, 0, 0}; + unsigned char data[16]; + unsigned char read_reg[1]; + + /* =============================================== */ + + /* Step 1 - Test register initialization */ + dummyData = 0x00; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + YAS530_REGADDR_TEST1, dummyData); + ERROR_CHECK(result); + + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->address, + YAS530_REGADDR_TEST2, dummyData); + ERROR_CHECK(result); + + /* Device ID read */ + result = MLSLSerialRead(mlsl_handle, pdata->address, + YAS530_REGADDR_DEVICE_ID, 1, read_reg); + + /*Step 2 Read the CAL register */ + /* CAL data read */ + result = MLSLSerialRead(mlsl_handle, pdata->address, + YAS530_REGADDR_CAL, 16, data); + ERROR_CHECK(result); + /* CAL data Second Read */ + result = MLSLSerialRead(mlsl_handle, pdata->address, + YAS530_REGADDR_CAL, 16, data); + ERROR_CHECK(result); + + /*Cal data */ + dx = data[0]; + dy1 = data[1]; + dy2 = data[2]; + d2 = (data[3]>>2) & 0x03f; + d3 = ((data[3]<<2) & 0x0c) | ((data[4]>>6) & 0x03); + d4 = data[4] & 0x3f; + d5 = (data[5]>>2) & 0x3f; + d6 = ((data[5]<<4) & 0x30) | ((data[6]>>4) & 0x0f); + d7 = ((data[6]<<3) & 0x78) | ((data[7]>>5) & 0x07); + d8 = ((data[7]<<1) & 0x3e) | ((data[8]>>7) & 0x01); + d9 = ((data[8]<<1) & 0xfe) | ((data[9]>>7) & 0x01); + d0 = (data[9]>>2) & 0x1f; + dck = ((data[9]<<1) & 0x06) | ((data[10]>>7) & 0x01); + + + /*Correction Data */ + Cx = dx * 6 - 768; + Cy1 = dy1 * 6 - 768; + Cy2 = dy2 * 6 - 768; + a2 = d2 - 32; + a3 = d3 - 8; + a4 = d4 - 32; + a5 = d5 + 38; + a6 = d6 - 32; + a7 = d7 - 64; + a8 = d8 - 32; + a9 = d9; + k = d0 + 10; + + /*Obtain the [49:47] bits */ + dck &= 0x07; + + /*Step 3 : Storing the CONFIG with the CLK value */ + dummyData = 0x00 | (dck << 2); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + YAS530_REGADDR_CONFIG, dummyData); + ERROR_CHECK(result); + + /*Step 4 : Set Acquisition Interval Register */ + dummyData = 0x00; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + YAS530_REGADDR_MEASURE_INTERVAL, dummyData); + ERROR_CHECK(result); + + /*Step 5 : Reset Coil */ + dummyData = 0x00; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + YAS530_REGADDR_ACTUATE_INIT_COIL, dummyData); + ERROR_CHECK(result); + + /* Offset Measurement and Set*/ + result = measure_and_set_offset(mlsl_handle, slave, pdata, offset); + ERROR_CHECK(result); + + return result; +} + +int yas530_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, unsigned char *data) +{ + int result = ML_SUCCESS; + + int busy; + short t, x, y1, y2; + int xyz[3]; + short rawfixed[3]; + + result = measure_normal(mlsl_handle, slave, pdata, + &busy, &t, &x, &y1, &y2); + ERROR_CHECK(result); + + coordinate_conversion(x, y1, y2, t, &xyz[0], &xyz[1], &xyz[2]); + + rawfixed[0] = (short) (xyz[0]/100); + rawfixed[1] = (short) (xyz[1]/100); + rawfixed[2] = (short) (xyz[2]/100); + + data[0] = rawfixed[0]>>8; + data[1] = rawfixed[0] & 0xFF; + data[2] = rawfixed[1]>>8; + data[3] = rawfixed[1] & 0xFF; + data[4] = rawfixed[2]>>8; + data[5] = rawfixed[2] & 0xFF; + + return result; +} + +struct ext_slave_descr yas530_descr = { + /*.init = */ NULL, + /*.exit = */ NULL, + /*.suspend = */ yas530_suspend, + /*.resume = */ yas530_resume, + /*.read = */ yas530_read, + /*.config = */ NULL, + /*.get_config = */ NULL, + /*.name = */ "yas530", + /*.type = */ EXT_SLAVE_TYPE_COMPASS, + /*.id = */ COMPASS_ID_YAS530, + /*.reg = */ 0x06, + /*.len = */ 6, + /*.endian = */ EXT_SLAVE_BIG_ENDIAN, + /*.range = */ {3276, 8001}, +}; + +struct ext_slave_descr *yas530_get_slave_descr(void) +{ + return &yas530_descr; +} +EXPORT_SYMBOL(yas530_get_slave_descr); + +/** + * @} +**/ diff --git a/drivers/misc/mpu3050/log.h b/drivers/misc/mpu3050/log.h old mode 100644 new mode 100755 index ceee28526265..f2f9ea7ece8e --- a/drivers/misc/mpu3050/log.h +++ b/drivers/misc/mpu3050/log.h @@ -70,14 +70,14 @@ extern "C" { #else /* Based off the log priorities in android /system/core/include/android/log.h */ -#define MPL_LOG_UNKNOWN (0) -#define MPL_LOG_DEFAULT (1) -#define MPL_LOG_VERBOSE (2) -#define MPL_LOG_DEBUG (3) -#define MPL_LOG_INFO (4) -#define MPL_LOG_WARN (5) -#define MPL_LOG_ERROR (6) -#define MPL_LOG_SILENT (8) +#define MPL_LOG_UNKNOWN (0) +#define MPL_LOG_DEFAULT (1) +#define MPL_LOG_VERBOSE (2) +#define MPL_LOG_DEBUG (3) +#define MPL_LOG_INFO (4) +#define MPL_LOG_WARN (5) +#define MPL_LOG_ERROR (6) +#define MPL_LOG_SILENT (8) #endif @@ -101,9 +101,13 @@ extern "C" { */ #ifndef MPL_LOGV #if MPL_LOG_NDEBUG -#define MPL_LOGV(...) ((void)0) +#define MPL_LOGV(fmt, ...) \ + do { \ + if (0) \ + MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__VA_ARGS__);\ + } while (0) #else -#define MPL_LOGV(...) ((void)MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, __VA_ARGS__)) +#define MPL_LOGV(fmt, ...) MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__VA_ARGS__) #endif #endif @@ -113,11 +117,12 @@ extern "C" { #ifndef MPL_LOGV_IF #if MPL_LOG_NDEBUG -#define MPL_LOGV_IF(cond, ...) ((void)0) +#define MPL_LOGV_IF(cond, fmt, ...) \ + do { if (0) MPL_LOG(fmt, ##__VA_ARGS__); } while (0) #else -#define MPL_LOGV_IF(cond, ...) \ +#define MPL_LOGV_IF(cond, fmt, ...) \ ((CONDITION(cond)) \ - ? ((void)MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, __VA_ARGS__)) \ + ? MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ : (void)0) #endif #endif @@ -126,13 +131,13 @@ extern "C" { * Simplified macro to send a debug log message using the current MPL_LOG_TAG. */ #ifndef MPL_LOGD -#define MPL_LOGD(...) ((void)MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, __VA_ARGS__)) +#define MPL_LOGD(fmt, ...) MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, fmt, ##__VA_ARGS__) #endif #ifndef MPL_LOGD_IF -#define MPL_LOGD_IF(cond, ...) \ +#define MPL_LOGD_IF(cond, fmt, ...) \ ((CONDITION(cond)) \ - ? ((void)MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, __VA_ARGS__)) \ + ? MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ : (void)0) #endif @@ -140,13 +145,13 @@ extern "C" { * Simplified macro to send an info log message using the current MPL_LOG_TAG. */ #ifndef MPL_LOGI -#define MPL_LOGI(...) ((void)MPL_LOG(LOG_INFO, MPL_LOG_TAG, __VA_ARGS__)) +#define MPL_LOGI(fmt, ...) MPL_LOG(LOG_INFO, MPL_LOG_TAG, fmt, ##__VA_ARGS__) #endif #ifndef MPL_LOGI_IF -#define MPL_LOGI_IF(cond, ...) \ +#define MPL_LOGI_IF(cond, fmt, ...) \ ((CONDITION(cond)) \ - ? ((void)MPL_LOG(LOG_INFO, MPL_LOG_TAG, __VA_ARGS__)) \ + ? MPL_LOG(LOG_INFO, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ : (void)0) #endif @@ -154,13 +159,17 @@ extern "C" { * Simplified macro to send a warning log message using the current MPL_LOG_TAG. */ #ifndef MPL_LOGW -#define MPL_LOGW(...) ((void)MPL_LOG(LOG_WARN, MPL_LOG_TAG, __VA_ARGS__)) +#ifdef __KERNEL__ +#define MPL_LOGW(fmt, ...) printk(KERN_WARNING MPL_LOG_TAG fmt, ##__VA_ARGS__) +#else +#define MPL_LOGW(fmt, ...) MPL_LOG(LOG_WARN, MPL_LOG_TAG, fmt, ##__VA_ARGS__) +#endif #endif #ifndef MPL_LOGW_IF -#define MPL_LOGW_IF(cond, ...) \ +#define MPL_LOGW_IF(cond, fmt, ...) \ ((CONDITION(cond)) \ - ? ((void)MPL_LOG(LOG_WARN, MPL_LOG_TAG, __VA_ARGS__)) \ + ? MPL_LOG(LOG_WARN, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ : (void)0) #endif @@ -168,13 +177,17 @@ extern "C" { * Simplified macro to send an error log message using the current MPL_LOG_TAG. */ #ifndef MPL_LOGE -#define MPL_LOGE(...) ((void)MPL_LOG(LOG_ERROR, MPL_LOG_TAG, __VA_ARGS__)) +#ifdef __KERNEL__ +#define MPL_LOGE(fmt, ...) printk(KERN_ERR MPL_LOG_TAG fmt, ##__VA_ARGS__) +#else +#define MPL_LOGE(fmt, ...) MPL_LOG(LOG_ERROR, MPL_LOG_TAG, fmt, ##__VA_ARGS__) +#endif #endif #ifndef MPL_LOGE_IF -#define MPL_LOGE_IF(cond, ...) \ +#define MPL_LOGE_IF(cond, fmt, ...) \ ((CONDITION(cond)) \ - ? ((void)MPL_LOG(LOG_ERROR, MPL_LOG_TAG, __VA_ARGS__)) \ + ? MPL_LOG(LOG_ERROR, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ : (void)0) #endif @@ -186,35 +199,43 @@ extern "C" { * It is NOT stripped from release builds. Note that the condition test * is -inverted- from the normal assert() semantics. */ -#define MPL_LOG_ALWAYS_FATAL_IF(cond, ...) \ +#define MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ...) \ ((CONDITION(cond)) \ - ? ((void)android_printAssert(#cond, MPL_LOG_TAG, __VA_ARGS__)) \ + ? ((void)android_printAssert(#cond, MPL_LOG_TAG, \ + fmt, ##__VA_ARGS__)) \ : (void)0) -#define MPL_LOG_ALWAYS_FATAL(...) \ - (((void)android_printAssert(NULL, MPL_LOG_TAG, __VA_ARGS__))) +#define MPL_LOG_ALWAYS_FATAL(fmt, ...) \ + (((void)android_printAssert(NULL, MPL_LOG_TAG, fmt, ##__VA_ARGS__))) /* * Versions of MPL_LOG_ALWAYS_FATAL_IF and MPL_LOG_ALWAYS_FATAL that * are stripped out of release builds. */ #if MPL_LOG_NDEBUG - -#define MPL_LOG_FATAL_IF(cond, ...) ((void)0) -#define MPL_LOG_FATAL(...) ((void)0) - +#define MPL_LOG_FATAL_IF(cond, fmt, ...) \ + do { \ + if (0) \ + MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ##__VA_ARGS__); \ + } while (0) +#define MPL_LOG_FATAL(fmt, ...) \ + do { \ + if (0) \ + MPL_LOG_ALWAYS_FATAL(fmt, ##__VA_ARGS__) \ + } while (0) #else - -#define MPL_LOG_FATAL_IF(cond, ...) MPL_LOG_ALWAYS_FATAL_IF(cond, __VA_ARGS__) -#define MPL_LOG_FATAL(...) MPL_LOG_ALWAYS_FATAL(__VA_ARGS__) - +#define MPL_LOG_FATAL_IF(cond, fmt, ...) \ + MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ##__VA_ARGS__) +#define MPL_LOG_FATAL(fmt, ...) \ + MPL_LOG_ALWAYS_FATAL(fmt, ##__VA_ARGS__) #endif /* * Assertion that generates a log message when the assertion fails. * Stripped out of release builds. Uses the current MPL_LOG_TAG. */ -#define MPL_LOG_ASSERT(cond, ...) MPL_LOG_FATAL_IF(!(cond), __VA_ARGS__) +#define MPL_LOG_ASSERT(cond, fmt, ...) \ + MPL_LOG_FATAL_IF(!(cond), fmt, ##__VA_ARGS__) /* --------------------------------------------------------------------- */ @@ -227,8 +248,8 @@ extern "C" { * The second argument may be NULL or "" to indicate the "global" tag. */ #ifndef MPL_LOG -#define MPL_LOG(priority, tag, ...) \ - MPL_LOG_PRI(priority, tag, __VA_ARGS__) +#define MPL_LOG(priority, tag, fmt, ...) \ + MPL_LOG_PRI(priority, tag, fmt, ##__VA_ARGS__) #endif /* @@ -236,14 +257,14 @@ extern "C" { */ #ifndef MPL_LOG_PRI #ifdef ANDROID -#define MPL_LOG_PRI(priority, tag, ...) \ - LOG(priority, tag, __VA_ARGS__) +#define MPL_LOG_PRI(priority, tag, fmt, ...) \ + LOG(priority, tag, fmt, ##__VA_ARGS__) #elif defined __KERNEL__ -#define MPL_LOG_PRI(priority, tag, ...) \ - printk(MPL_##priority tag __VA_ARGS__) +#define MPL_LOG_PRI(priority, tag, fmt, ...) \ + pr_debug(MPL_##priority tag fmt, ##__VA_ARGS__) #else -#define MPL_LOG_PRI(priority, tag, ...) \ - _MLPrintLog(MPL_##priority, tag, __VA_ARGS__) +#define MPL_LOG_PRI(priority, tag, fmt, ...) \ + _MLPrintLog(MPL_##priority, tag, fmt, ##__VA_ARGS__) #endif #endif @@ -255,8 +276,7 @@ extern "C" { #define MPL_LOG_PRI_VA(priority, tag, fmt, args) \ android_vprintLog(priority, NULL, tag, fmt, args) #elif defined __KERNEL__ -#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \ - vprintk(MPL_##priority tag fmt, args) +/* not allowed in the Kernel because there is no dev_dbg that takes a va_list */ #else #define MPL_LOG_PRI_VA(priority, tag, fmt, args) \ _MLPrintVaLog(priority, NULL, tag, fmt, args) diff --git a/drivers/misc/mpu3050/mldl_cfg.c b/drivers/misc/mpu3050/mldl_cfg.c old mode 100644 new mode 100755 index 220103bb2b0b..9cc4cf690386 --- a/drivers/misc/mpu3050/mldl_cfg.c +++ b/drivers/misc/mpu3050/mldl_cfg.c @@ -1,13 +1,21 @@ /* $License: Copyright (C) 2010 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 . + $ */ -/******************************************************************************* - * - * $Id: mldl_cfg.c 4635 2011-01-27 07:49:49Z nroyer $ - * - ******************************************************************************/ /** * @addtogroup MLDL @@ -289,7 +297,7 @@ static int MLDLGetSiliconRev(struct mldl_cfg *pdata, result = MLSLSerialReadMem(mlsl_handle, pdata->addr, memAddr, 1, &index); - ERROR_CHECK(result) + ERROR_CHECK(result); if (result) return result; index >>= 2; @@ -298,7 +306,7 @@ static int MLDLGetSiliconRev(struct mldl_cfg *pdata, result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, MPUREG_BANK_SEL, 0); - ERROR_CHECK(result) + ERROR_CHECK(result); if (result) return result; @@ -322,20 +330,28 @@ static int MLDLGetSiliconRev(struct mldl_cfg *pdata, } /** - * @brief Enable/Disable the use MPU's VDDIO level shifters. - * When enabled the voltage interface with AUX or other external - * accelerometer is using Vlogic instead of VDD (supply). + * @brief Enable / Disable the use MPU's secondary I2C interface level + * shifters. + * When enabled the secondary I2C interface to which the external + * device is connected runs at VDD voltage (main supply). + * When disabled the 2nd interface runs at VDDIO voltage. + * See the device specification for more details. + * + * @note using this API may produce unpredictable results, depending on how + * the MPU and slave device are setup on the target platform. + * Use of this API should entirely be restricted to system + * integrators. Once the correct value is found, there should be no + * need to change the level shifter at runtime. * - * @note Must be called after MLSerialOpen(). - * @note Typically be called before MLDmpOpen(). - * If called after MLDmpOpen(), must be followed by a call to - * MLDLApplyLevelShifterBit() to write the setting on the hw. + * @pre Must be called after MLSerialOpen(). + * @note Typically called before MLDmpOpen(). * - * @param[in] enable - * 1 to enable, 0 to disable + * @param[in] enable: + * 0 to run at VDDIO (default), + * 1 to run at VDD. * - * @return ML_SUCCESS if successfull, a non-zero error code otherwise. -**/ + * @return ML_SUCCESS if successfull, a non-zero error code otherwise. + */ static int MLDLSetLevelShifterBit(struct mldl_cfg *pdata, void *mlsl_handle, unsigned char enable) @@ -350,9 +366,9 @@ static int MLDLSetLevelShifterBit(struct mldl_cfg *pdata, return ML_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 --*/ + 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 ((pdata->silicon_revision & 0xf) < MPU_SILICON_REV_B6) { reg = MPUREG_ACCEL_BURST_ADDR; mask = 0x80; @@ -551,6 +567,7 @@ static int MLDLPowerMgmtMPU(struct mldl_cfg *pdata, /* Reset if requested */ if (reset) { + MPL_LOGV("Reset MPU3050\n"); result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, MPUREG_PWR_MGM, b | BIT_H_RESET); ERROR_CHECK(result); @@ -1114,6 +1131,7 @@ int mpu3050_open(struct mldl_cfg *mldl_cfg, { int result; /* Default is Logic HIGH, pushpull, latch disabled, anyread to clear */ + mldl_cfg->ignore_system_suspend = FALSE; mldl_cfg->int_config = BIT_INT_ANYRD_2CLEAR | BIT_DMP_INT_EN; mldl_cfg->clk_src = MPU_CLK_SEL_PLLGYROZ; mldl_cfg->lpf = MPU_FILTER_42HZ; @@ -1294,7 +1312,10 @@ int mpu3050_close(struct mldl_cfg *mldl_cfg, /** * @brief resume the MPU3050 device and all the other sensor * devices from their low power state. - * @param mlsl_handle + * + * @param mldl_cfg + * pointer to the configuration structure + * @param gyro_handle * the main file handle to the MPU3050 device. * @param accel_handle * an handle to the accelerometer device, if sitting @@ -1311,6 +1332,10 @@ int mpu3050_close(struct mldl_cfg *mldl_cfg, * onto a separate bus. Can match mlsl_handle if * the pressure sensor device operates on the same * primary bus of MPU. + * @param resume_gyro + * whether resuming the gyroscope device is + * actually needed (if the device supports low power + * mode of some sort). * @param resume_accel * whether resuming the accelerometer device is * actually needed (if the device supports low power @@ -1337,7 +1362,7 @@ int mpu3050_resume(struct mldl_cfg *mldl_cfg, { int result = ML_SUCCESS; -#ifdef CONFIG_SENSORS_MPU_DEBUG +#ifdef CONFIG_MPU_SENSORS_DEBUG mpu_print_cfg(mldl_cfg); #endif @@ -1367,15 +1392,15 @@ int mpu3050_resume(struct mldl_cfg *mldl_cfg, &mldl_cfg->pdata->accel); ERROR_CHECK(result); mldl_cfg->accel_is_suspended = FALSE; + } - if (!mldl_cfg->gyro_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) { - result = mpu_set_slave(mldl_cfg, - gyro_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel); - ERROR_CHECK(result); - } + if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->accel_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) { + result = mpu_set_slave(mldl_cfg, + gyro_handle, + mldl_cfg->accel, + &mldl_cfg->pdata->accel); + ERROR_CHECK(result); } if (resume_compass && mldl_cfg->compass_is_suspended) { @@ -1390,15 +1415,15 @@ int mpu3050_resume(struct mldl_cfg *mldl_cfg, compass); ERROR_CHECK(result); mldl_cfg->compass_is_suspended = FALSE; + } - if (!mldl_cfg->gyro_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) { - result = mpu_set_slave(mldl_cfg, - gyro_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass); - ERROR_CHECK(result); - } + if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->compass_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) { + result = mpu_set_slave(mldl_cfg, + gyro_handle, + mldl_cfg->compass, + &mldl_cfg->pdata->compass); + ERROR_CHECK(result); } if (resume_pressure && mldl_cfg->pressure_is_suspended) { @@ -1412,17 +1437,18 @@ int mpu3050_resume(struct mldl_cfg *mldl_cfg, &mldl_cfg->pdata-> pressure); ERROR_CHECK(result); - if (!mldl_cfg->gyro_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) { - result = mpu_set_slave(mldl_cfg, - gyro_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure); - ERROR_CHECK(result); - } mldl_cfg->pressure_is_suspended = FALSE; } + if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->pressure_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) { + result = mpu_set_slave(mldl_cfg, + gyro_handle, + mldl_cfg->pressure, + &mldl_cfg->pdata->pressure); + ERROR_CHECK(result); + } + /* Now start */ if (resume_gyro) { result = dmp_start(mldl_cfg, gyro_handle); @@ -1432,7 +1458,6 @@ int mpu3050_resume(struct mldl_cfg *mldl_cfg, return result; } - /** * @brief suspend the MPU3050 device and all the other sensor * devices into their low power state. @@ -1481,13 +1506,14 @@ int mpu3050_suspend(struct mldl_cfg *mldl_cfg, if (suspend_gyro && !mldl_cfg->gyro_is_suspended) { #ifdef M_HW + return ML_SUCCESS; /* This puts the bus into bypass mode */ result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, 1); ERROR_CHECK(result); result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, 0, SLEEP); #else result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, - 0, SLEEP, 0, 0, 0); + 0, SLEEP, 0, 0, 0); #endif ERROR_CHECK(result); } @@ -1545,6 +1571,10 @@ int mpu3050_suspend(struct mldl_cfg *mldl_cfg, /** * @brief read raw sensor data from the accelerometer device * in use. + * @param mldl_cfg + * A pointer to the struct mldl_cfg data structure. + * @param accel_handle + * The handle to the device the accelerometer is connected to. * @param data * a buffer to store the raw sensor data. * @return ML_SUCCESS if successful, a non-zero error code otherwise. @@ -1553,10 +1583,14 @@ int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, void *accel_handle, unsigned char *data) { if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->read) - return mldl_cfg->accel->read(accel_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel, - data); + if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) + && (!mldl_cfg->gyro_is_bypassed)) + return ML_ERROR_FEATURE_NOT_ENABLED; + else + return mldl_cfg->accel->read(accel_handle, + mldl_cfg->accel, + &mldl_cfg->pdata->accel, + data); else return ML_ERROR_FEATURE_NOT_IMPLEMENTED; } @@ -1564,6 +1598,10 @@ int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, /** * @brief read raw sensor data from the compass device * in use. + * @param mldl_cfg + * A pointer to the struct mldl_cfg data structure. + * @param compass_handle + * The handle to the device the compass is connected to. * @param data * a buffer to store the raw sensor data. * @return ML_SUCCESS if successful, a non-zero error code otherwise. @@ -1572,10 +1610,14 @@ int mpu3050_read_compass(struct mldl_cfg *mldl_cfg, void *compass_handle, unsigned char *data) { if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->read) - return mldl_cfg->compass->read(compass_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass, - data); + if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) + && (!mldl_cfg->gyro_is_bypassed)) + return ML_ERROR_FEATURE_NOT_ENABLED; + else + return mldl_cfg->compass->read(compass_handle, + mldl_cfg->compass, + &mldl_cfg->pdata->compass, + data); else return ML_ERROR_FEATURE_NOT_IMPLEMENTED; } @@ -1583,6 +1625,10 @@ int mpu3050_read_compass(struct mldl_cfg *mldl_cfg, /** * @brief read raw sensor data from the pressure device * in use. + * @param mldl_cfg + * A pointer to the struct mldl_cfg data structure. + * @param pressure_handle + * The handle to the device the pressure sensor is connected to. * @param data * a buffer to store the raw sensor data. * @return ML_SUCCESS if successful, a non-zero error code otherwise. @@ -1591,10 +1637,15 @@ int mpu3050_read_pressure(struct mldl_cfg *mldl_cfg, void *pressure_handle, unsigned char *data) { if (NULL != mldl_cfg->pressure && NULL != mldl_cfg->pressure->read) - return mldl_cfg->pressure->read(pressure_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure, - data); + if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) + && (!mldl_cfg->gyro_is_bypassed)) + return ML_ERROR_FEATURE_NOT_ENABLED; + else + return mldl_cfg->pressure->read( + pressure_handle, + mldl_cfg->pressure, + &mldl_cfg->pdata->pressure, + data); else return ML_ERROR_FEATURE_NOT_IMPLEMENTED; } @@ -1640,6 +1691,48 @@ int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg, return ML_ERROR_FEATURE_NOT_IMPLEMENTED; } +int mpu3050_get_config_accel(struct mldl_cfg *mldl_cfg, + void *accel_handle, + struct ext_slave_config *data) +{ + if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->get_config) + return mldl_cfg->accel->get_config(accel_handle, + mldl_cfg->accel, + &mldl_cfg->pdata->accel, + data); + else + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + +} + +int mpu3050_get_config_compass(struct mldl_cfg *mldl_cfg, + void *compass_handle, + struct ext_slave_config *data) +{ + if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->get_config) + return mldl_cfg->compass->get_config(compass_handle, + mldl_cfg->compass, + &mldl_cfg->pdata->compass, + data); + else + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + +} + +int mpu3050_get_config_pressure(struct mldl_cfg *mldl_cfg, + void *pressure_handle, + struct ext_slave_config *data) +{ + if (NULL != mldl_cfg->pressure && + NULL != mldl_cfg->pressure->get_config) + return mldl_cfg->pressure->get_config(pressure_handle, + mldl_cfg->pressure, + &mldl_cfg->pdata->pressure, + data); + else + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; +} + /** *@} diff --git a/drivers/misc/mpu3050/mldl_cfg.h b/drivers/misc/mpu3050/mldl_cfg.h old mode 100644 new mode 100755 index 91f349ef2748..ad6a211c5d86 --- a/drivers/misc/mpu3050/mldl_cfg.h +++ b/drivers/misc/mpu3050/mldl_cfg.h @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -80,6 +93,7 @@ struct mldl_cfg { /* MPU related configuration */ unsigned long requested_sensors; + unsigned char ignore_system_suspend; unsigned char addr; unsigned char int_config; unsigned char ext_sync; @@ -167,6 +181,16 @@ int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg, void *pressure_handle, struct ext_slave_config *data); +int mpu3050_get_config_accel(struct mldl_cfg *mldl_cfg, + void *accel_handle, + struct ext_slave_config *data); +int mpu3050_get_config_compass(struct mldl_cfg *mldl_cfg, + void *compass_handle, + struct ext_slave_config *data); +int mpu3050_get_config_pressure(struct mldl_cfg *mldl_cfg, + void *pressure_handle, + struct ext_slave_config *data); + #endif /* __MLDL_CFG_H__ */ diff --git a/drivers/misc/mpu3050/mlos-kernel.c b/drivers/misc/mpu3050/mlos-kernel.c old mode 100644 new mode 100755 index 091c0a60b784..ced9ba4f6f3c --- a/drivers/misc/mpu3050/mlos-kernel.c +++ b/drivers/misc/mpu3050/mlos-kernel.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** * @defgroup diff --git a/drivers/misc/mpu3050/mlos.h b/drivers/misc/mpu3050/mlos.h old mode 100644 new mode 100755 index e65dd62da4d3..4ebb86c9fa5c --- a/drivers/misc/mpu3050/mlos.h +++ b/drivers/misc/mpu3050/mlos.h @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ #ifndef _MLOS_H diff --git a/drivers/misc/mpu3050/mlsl-kernel.c b/drivers/misc/mpu3050/mlsl-kernel.c old mode 100644 new mode 100755 index d1bcf8815561..cb1605131cbf --- a/drivers/misc/mpu3050/mlsl-kernel.c +++ b/drivers/misc/mpu3050/mlsl-kernel.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ #include "mlsl.h" @@ -83,7 +96,8 @@ tMLError MLSLSerialWriteSingle(void *sl_handle, */ tMLError MLSLSerialWrite(void *sl_handle, unsigned char slaveAddr, - unsigned short length, unsigned char const *data) + unsigned short length, + unsigned char const *data) { tMLError result; const unsigned short dataLength = length - 1; @@ -174,10 +188,9 @@ tMLError MLSLSerialWriteMem(void *sl_handle, unsigned short bytesWritten = 0; if ((memAddr & 0xFF) + length > MPU_MEM_BANK_SIZE) { - printk - ("memory read length (%d B) extends beyond its limits (%d) " - "if started at location %d\n", length, - MPU_MEM_BANK_SIZE, memAddr & 0xFF); + pr_err("memory read length (%d B) extends beyond its" + " limits (%d) if started at location %d\n", length, + MPU_MEM_BANK_SIZE, memAddr & 0xFF); return ML_ERROR_INVALID_PARAMETER; } while (bytesWritten < length) { diff --git a/drivers/misc/mpu3050/mlsl.h b/drivers/misc/mpu3050/mlsl.h old mode 100644 new mode 100755 index 4f012937d877..76f69c77ba98 --- a/drivers/misc/mpu3050/mlsl.h +++ b/drivers/misc/mpu3050/mlsl.h @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ #ifndef __MSSL_H__ diff --git a/drivers/misc/mpu3050/mltypes.h b/drivers/misc/mpu3050/mltypes.h old mode 100644 new mode 100755 index 3521c00974bd..d0b27fa89e78 --- a/drivers/misc/mpu3050/mltypes.h +++ b/drivers/misc/mpu3050/mltypes.h @@ -1,13 +1,21 @@ /* $License: Copyright (C) 2010 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 . + $ */ -/****************************************************************************** - * - * $Id: mltypes.h 4598 2011-01-25 19:33:13Z prao $ - * - *****************************************************************************/ /** * @defgroup MLERROR @@ -81,11 +89,12 @@ ---------------------------*/ /** - * @struct tMLError The MPL Error Code return type. + * @struct tMLError mltypes.h "mltypes" + * @brief The MPL Error Code return type. * - * @code + * @code * typedef unsigned char tMLError; - * @endcode + * @endcode */ typedef unsigned char tMLError; @@ -127,13 +136,13 @@ typedef int_fast8_t bool; /* - ML Errors. - */ #define ERROR_NAME(x) (#x) #define ERROR_CHECK(x) \ - { \ + do { \ if (ML_SUCCESS != x) { \ MPL_LOGE("%s|%s|%d returning %d\n", \ __FILE__, __func__, __LINE__, x); \ return x; \ } \ - } + } while (0) #define ERROR_CHECK_FIRST(first, x) \ { if (ML_SUCCESS == first) first = x; } @@ -200,6 +209,12 @@ typedef int_fast8_t bool; #define ML_ERROR_CALIBRATION_LEN (77) #define ML_ERROR_CALIBRATION_CHECKSUM (78) +/* Accel errors */ +#define ML_ERROR_ACCEL_DATA_OVERFLOW (79) +#define ML_ERROR_ACCEL_DATA_UNDERFLOW (80) +#define ML_ERROR_ACCEL_DATA_NOT_READY (81) +#define ML_ERROR_ACCEL_DATA_ERROR (82) + /* For Linux coding compliance */ #ifndef __KERNEL__ #define EXPORT_SYMBOL(x) diff --git a/drivers/misc/mpu3050/mpu-dev.c b/drivers/misc/mpu3050/mpu-dev.c old mode 100644 new mode 100755 index 26bcebcff4e1..e84b63f97faa --- a/drivers/misc/mpu3050/mpu-dev.c +++ b/drivers/misc/mpu3050/mpu-dev.c @@ -1,9 +1,5 @@ /* - mpu-dev.c - mpu3050 char device interface - - Copyright (C) 1995-97 Simon G. Vogl - Copyright (C) 1998-99 Frodo Looijaard - Copyright (C) 2003 Greg Kroah-Hartman + $License: Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. This program is free software; you can redistribute it and/or modify @@ -18,8 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . -*/ -/* Code inside mpudev_ioctl_rdrw is copied from i2c-dev.c + $ */ #include #include @@ -36,7 +31,9 @@ #include #include #include - +#include +#include +#include #ifdef CONFIG_HAS_EARLYSUSPEND #include #endif @@ -65,44 +62,97 @@ struct mpu_private_data { #ifdef CONFIG_HAS_EARLYSUSPEND struct early_suspend early_suspend; #endif + struct mutex mutex; + wait_queue_head_t mpu_event_wait; + struct completion completion; + struct timer_list timeout; + struct notifier_block nb; + struct mpuirq_data mpu_pm_event; + int response_timeout; /* In seconds */ + unsigned long event; + int pid; }; -static int pid; -struct i2c_msg1 { - __u16 addr; /* slave address */ - __u16 flags; -#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ -#define I2C_M_RD 0x0001 /* read data, from slave to master */ -#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */ -#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */ -#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ -#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ -#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ - __u16 len; /* msg length */ - __u8 *buf; /* pointer to msg data */ -}; -struct i2c_rdwr_ioctl_data1 { - struct i2c_msg1 __user *msgs; /* pointers to i2c_msgs */ - __u32 nmsgs; /* number of i2c_msgs */ -}; static struct i2c_client *this_client; + +static void +mpu_pm_timeout(u_long data) +{ + struct mpu_private_data *mpu = (struct mpu_private_data *) data; + dev_dbg(&this_client->adapter->dev, "%s\n", __func__); + complete(&mpu->completion); +} + +static int mpu_pm_notifier_callback(struct notifier_block *nb, + unsigned long event, + void *unused) +{ + struct mpu_private_data *mpu = + container_of(nb, struct mpu_private_data, nb); + struct timeval event_time; + dev_dbg(&this_client->adapter->dev, "%s: %ld\n", __func__, event); + + /* Prevent the file handle from being closed before we initialize + the completion event */ + mutex_lock(&mpu->mutex); + if (!(mpu->pid) || + (event != PM_SUSPEND_PREPARE && event != PM_POST_SUSPEND)) { + mutex_unlock(&mpu->mutex); + return NOTIFY_OK; + } + + do_gettimeofday(&event_time); + mpu->mpu_pm_event.interruptcount++; + mpu->mpu_pm_event.irqtime = + (((long long) event_time.tv_sec) << 32) + + event_time.tv_usec; + mpu->mpu_pm_event.data_type = MPUIRQ_DATA_TYPE_PM_EVENT; + mpu->mpu_pm_event.data_size = sizeof(unsigned long); + mpu->mpu_pm_event.data = &mpu->event; + + if (event == PM_SUSPEND_PREPARE) + mpu->event = MPU_PM_EVENT_SUSPEND_PREPARE; + if (event == PM_POST_SUSPEND) + mpu->event = MPU_PM_EVENT_POST_SUSPEND; + + if (mpu->response_timeout > 0) { + mpu->timeout.expires = jiffies + mpu->response_timeout * HZ; + add_timer(&mpu->timeout); + } + INIT_COMPLETION(mpu->completion); + mutex_unlock(&mpu->mutex); + + wake_up_interruptible(&mpu->mpu_event_wait); + wait_for_completion(&mpu->completion); + del_timer_sync(&mpu->timeout); + dev_dbg(&this_client->adapter->dev, "%s: %ld DONE\n", __func__, event); + return NOTIFY_OK; +} + static int mpu_open(struct inode *inode, struct file *file) { struct mpu_private_data *mpu = (struct mpu_private_data *) i2c_get_clientdata(this_client); struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; - + int result; dev_dbg(&this_client->adapter->dev, "mpu_open\n"); dev_dbg(&this_client->adapter->dev, "current->pid %d\n", current->pid); - pid = current->pid; + mpu->pid = current->pid; file->private_data = this_client; /* we could do some checking on the flags supplied by "open" */ /* i.e. O_NONBLOCK */ /* -> set some flag to disable interruptible_sleep_on in mpu_read */ /* Reset the sensors to the default */ + result = mutex_lock_interruptible(&mpu->mutex); + if (result) { + dev_err(&this_client->adapter->dev, + "%s: mutex_lock_interruptible returned %d\n", + __func__, result); + return result; + } mldl_cfg->requested_sensors = ML_THREE_AXIS_GYRO; if (mldl_cfg->accel && mldl_cfg->accel->resume) mldl_cfg->requested_sensors |= ML_THREE_AXIS_ACCEL; @@ -112,7 +162,7 @@ static int mpu_open(struct inode *inode, struct file *file) if (mldl_cfg->pressure && mldl_cfg->pressure->resume) mldl_cfg->requested_sensors |= ML_THREE_AXIS_PRESSURE; - + mutex_unlock(&mpu->mutex); return 0; } @@ -129,136 +179,80 @@ static int mpu_release(struct inode *inode, struct file *file) struct i2c_adapter *pressure_adapter; int result = 0; - pid = 0; - accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); pressure_adapter = i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); + + mutex_lock(&mpu->mutex); result = mpu3050_suspend(mldl_cfg, client->adapter, accel_adapter, compass_adapter, pressure_adapter, TRUE, TRUE, TRUE, TRUE); - + mpu->pid = 0; + mutex_unlock(&mpu->mutex); + complete(&mpu->completion); dev_dbg(&this_client->adapter->dev, "mpu_release\n"); return result; } -static noinline int mpudev_ioctl_rdrw(struct i2c_client *client, - unsigned long arg) +/* read function called when from /dev/mpu is read. Read from the FIFO */ +static ssize_t mpu_read(struct file *file, + char __user *buf, size_t count, loff_t *offset) { - struct i2c_rdwr_ioctl_data1 rdwr_arg; - struct i2c_msg1 *rdwr_pa; - struct i2c_msg *msgs; - u8 __user **data_ptrs; - int i, res; - - if (copy_from_user(&rdwr_arg, - (struct i2c_rdwr_ioctl_data1 __user *) arg, - sizeof(rdwr_arg))) - return -EFAULT; + struct mpuirq_data local_mpu_pm_event; + struct i2c_client *client = + (struct i2c_client *) file->private_data; + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(client); + size_t len = sizeof(mpu->mpu_pm_event) + sizeof(unsigned long); + int err; - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) - return -EINVAL; - msgs = (struct i2c_msg *)kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); - rdwr_pa = (struct i2c_msg1 *) - kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg1), GFP_KERNEL); - if (!rdwr_pa) - return -ENOMEM; + if (!mpu->event && (!(file->f_flags & O_NONBLOCK))) + wait_event_interruptible(mpu->mpu_event_wait, mpu->event); - if (copy_from_user(rdwr_pa, rdwr_arg.msgs, - rdwr_arg.nmsgs * sizeof(struct i2c_msg1))) { - kfree(rdwr_pa); - return -EFAULT; - } + if (!mpu->event || NULL == buf + || count < sizeof(mpu->mpu_pm_event) + sizeof(unsigned long)) + return 0; - data_ptrs = - kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); - if (data_ptrs == NULL) { - kfree(rdwr_pa); - return -ENOMEM; + err = copy_from_user(&local_mpu_pm_event, buf, + sizeof(mpu->mpu_pm_event)); + if (err != 0) { + dev_err(&this_client->adapter->dev, + "Copy from user returned %d\n", err); + return -EFAULT; } - res = 0; - for (i = 0; i < rdwr_arg.nmsgs; i++) { - /* Limit the size of the message to a sane amount; - * and don't let length change either. */ - if ((rdwr_pa[i].len > 8192) || - (rdwr_pa[i].flags & I2C_M_RECV_LEN)) { - res = -EINVAL; - break; - } - data_ptrs[i] = (u8 __user *) rdwr_pa[i].buf; - rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL); - if (rdwr_pa[i].buf == NULL) { - res = -ENOMEM; - break; - } - if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i], - rdwr_pa[i].len)) { - ++i; /* Needs to be kfreed too */ - res = -EFAULT; - break; - } - msgs[i].buf = rdwr_pa[i].buf; - msgs[i].len = rdwr_pa[i].len; - msgs[i].flags = rdwr_pa[i].flags; - msgs[i].addr = rdwr_pa[i].addr; - - msgs[i].scl_rate = 400 * 1000; - } - if (res < 0) { - int j; - for (j = 0; j < i; ++j) - kfree(rdwr_pa[j].buf); - kfree(data_ptrs); - kfree(rdwr_pa); - kfree(msgs); - return res; + mpu->mpu_pm_event.data = local_mpu_pm_event.data; + err = copy_to_user((unsigned long __user *)local_mpu_pm_event.data, + &mpu->event, + sizeof(mpu->event)); + if (err != 0) { + dev_err(&this_client->adapter->dev, + "Copy to user returned %d\n", err); + return -EFAULT; } - - res = i2c_transfer(client->adapter, msgs,rdwr_arg.nmsgs); - while (i-- > 0) { - if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) { - if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf, - rdwr_pa[i].len)) - res = -EFAULT; - } - kfree(rdwr_pa[i].buf); + err = copy_to_user(buf, &mpu->mpu_pm_event, sizeof(mpu->mpu_pm_event)); + if (err != 0) { + dev_err(&this_client->adapter->dev, + "Copy to user returned %d\n", err); + return -EFAULT; } - kfree(data_ptrs); - kfree(rdwr_pa); - kfree(msgs); - return res; + mpu->event = 0; + return len; } -/* read function called when from /dev/mpu is read. Read from the FIFO */ -static ssize_t mpu_read(struct file *file, - char __user *buf, size_t count, loff_t *offset) +static unsigned int mpu_poll(struct file *file, struct poll_table_struct *poll) { - char *tmp; - int ret; - struct i2c_client *client = (struct i2c_client *) file->private_data; + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(client); + int mask = 0; - if (count > 8192) - count = 8192; - - tmp = kmalloc(count, GFP_KERNEL); - if (tmp == NULL) - return -ENOMEM; - - pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n", - iminor(file->f_path.dentry->d_inode), count); - -/* @todo fix this to do a i2c trasnfer from the FIFO */ - ret = i2c_master_recv(client, tmp, count); - if (ret >= 0) - ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret; - kfree(tmp); - return ret; + poll_wait(file, &mpu->mpu_event_wait, poll); + if (mpu->event) + mask |= POLLIN | POLLRDNORM; + return mask; } static int @@ -403,51 +397,245 @@ mpu_ioctl_get_mpu_config(struct i2c_client *client, unsigned long arg) retval = copy_from_user(local_mldl_cfg, (struct mldl_cfg __user *) arg, sizeof(struct mldl_cfg)); - if (retval) + if (retval) { + dev_err(&this_client->adapter->dev, + "%s|%s:%d: EFAULT on arg\n", + __FILE__, __func__, __LINE__); + retval = -EFAULT; goto out; + } /* Fill in the accel, compass, pressure and pdata pointers */ if (mldl_cfg->accel) { retval = copy_to_user((void __user *)local_mldl_cfg->accel, mldl_cfg->accel, sizeof(*mldl_cfg->accel)); - if (retval) + if (retval) { + dev_err(&this_client->adapter->dev, + "%s|%s:%d: EFAULT on accel\n", + __FILE__, __func__, __LINE__); + retval = -EFAULT; goto out; + } } if (mldl_cfg->compass) { retval = copy_to_user((void __user *)local_mldl_cfg->compass, mldl_cfg->compass, sizeof(*mldl_cfg->compass)); - if (retval) + if (retval) { + dev_err(&this_client->adapter->dev, + "%s|%s:%d: EFAULT on compass\n", + __FILE__, __func__, __LINE__); + retval = -EFAULT; goto out; + } } if (mldl_cfg->pressure) { - retval = copy_to_user(local_mldl_cfg->pressure, + retval = copy_to_user((void __user *)local_mldl_cfg->pressure, mldl_cfg->pressure, sizeof(*mldl_cfg->pressure)); - if (retval) + if (retval) { + dev_err(&this_client->adapter->dev, + "%s|%s:%d: EFAULT on pressure\n", + __FILE__, __func__, __LINE__); + retval = -EFAULT; goto out; + } } if (mldl_cfg->pdata) { retval = copy_to_user((void __user *)local_mldl_cfg->pdata, mldl_cfg->pdata, sizeof(*mldl_cfg->pdata)); - if (retval) + if (retval) { + dev_err(&this_client->adapter->dev, + "%s|%s:%d: EFAULT on pdata\n", + __FILE__, __func__, __LINE__); + retval = -EFAULT; goto out; + } } /* Do not modify the accel, compass, pressure and pdata pointers */ retval = copy_to_user((struct mldl_cfg __user *) arg, mldl_cfg, offsetof(struct mldl_cfg, accel)); + if (retval) + retval = -EFAULT; out: kfree(local_mldl_cfg); return retval; } +/** + * Pass a requested slave configuration to the slave sensor + * + * @param adapter the adaptor to use to communicate with the slave + * @param mldl_cfg the mldl configuration structuer + * @param slave pointer to the slave descriptor + * @param usr_config The configuration to pass to the slave sensor + * + * @return 0 or non-zero error code + */ +static int slave_config(void *adapter, + struct mldl_cfg *mldl_cfg, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config __user *usr_config) +{ + int retval = ML_SUCCESS; + struct ext_slave_config config; + if ((!slave) || (!slave->config)) + return retval; + + retval = copy_from_user(&config, usr_config, sizeof(config)); + if (retval) + return -EFAULT; + + if (config.len && config.data) { + int *data; + data = kzalloc(config.len, GFP_KERNEL); + if (!data) + return ML_ERROR_MEMORY_EXAUSTED; + + retval = copy_from_user(data, + (void __user *)config.data, + config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = slave->config(adapter, slave, pdata, &config); + kfree(config.data); + return retval; +} + +/** + * Get a requested slave configuration from the slave sensor + * + * @param adapter the adaptor to use to communicate with the slave + * @param mldl_cfg the mldl configuration structuer + * @param slave pointer to the slave descriptor + * @param usr_config The configuration for the slave to fill out + * + * @return 0 or non-zero error code + */ +static int slave_get_config(void *adapter, + struct mldl_cfg *mldl_cfg, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config __user *usr_config) +{ + int retval = ML_SUCCESS; + struct ext_slave_config config; + void *user_data; + if (!(slave) || !(slave->get_config)) + return ML_SUCCESS; + + retval = copy_from_user(&config, usr_config, sizeof(config)); + if (retval) + return -EFAULT; + + user_data = config.data; + if (config.len && config.data) { + int *data; + data = kzalloc(config.len, GFP_KERNEL); + if (!data) + return ML_ERROR_MEMORY_EXAUSTED; + + retval = copy_from_user(data, + (void __user *)config.data, + config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = slave->get_config(adapter, slave, pdata, &config); + if (retval) { + kfree(config.data); + return retval; + } + retval = copy_to_user((unsigned char __user *) user_data, + config.data, + config.len); + kfree(config.data); + return retval; +} + +static int mpu_handle_mlsl(void *sl_handle, + unsigned char addr, + unsigned int cmd, + struct mpu_read_write __user *usr_msg) +{ + int retval = ML_SUCCESS; + struct mpu_read_write msg; + unsigned char *user_data; + retval = copy_from_user(&msg, usr_msg, sizeof(msg)); + if (retval) + return -EFAULT; + + user_data = msg.data; + if (msg.length && msg.data) { + unsigned char *data; + data = kzalloc(msg.length, GFP_KERNEL); + if (!data) + return ML_ERROR_MEMORY_EXAUSTED; + + retval = copy_from_user(data, + (void __user *)msg.data, + msg.length); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + msg.data = data; + } else { + return ML_ERROR_INVALID_PARAMETER; + } + + switch (cmd) { + case MPU_READ: + retval = MLSLSerialRead(sl_handle, addr, + msg.address, msg.length, msg.data); + break; + case MPU_WRITE: + retval = MLSLSerialWrite(sl_handle, addr, + msg.length, msg.data); + break; + case MPU_READ_MEM: + retval = MLSLSerialReadMem(sl_handle, addr, + msg.address, msg.length, msg.data); + break; + case MPU_WRITE_MEM: + retval = MLSLSerialWriteMem(sl_handle, addr, + msg.address, msg.length, msg.data); + break; + case MPU_READ_FIFO: + retval = MLSLSerialReadFifo(sl_handle, addr, + msg.length, msg.data); + break; + case MPU_WRITE_FIFO: + retval = MLSLSerialWriteFifo(sl_handle, addr, + msg.length, msg.data); + break; + + }; + retval = copy_to_user((unsigned char __user *) user_data, + msg.data, + msg.length); + kfree(msg.data); + return retval; +} + /* ioctl - I/O control */ static long mpu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -468,233 +656,69 @@ static long mpu_ioctl(struct file *file, pressure_adapter = i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); + retval = mutex_lock_interruptible(&mpu->mutex); + if (retval) { + dev_err(&this_client->adapter->dev, + "%s: mutex_lock_interruptible returned %d\n", + __func__, retval); + return retval; + } + switch (cmd) { - case I2C_RDWR: - mpudev_ioctl_rdrw(client, arg); - break; - case I2C_SLAVE: - if ((arg & 0x7E) != (client->addr & 0x7E)) { - dev_err(&this_client->adapter->dev, - "%s: Invalid I2C_SLAVE arg %lu\n", - __func__, arg); - } - break; case MPU_SET_MPU_CONFIG: retval = mpu_ioctl_set_mpu_config(client, arg); break; - case MPU_SET_INT_CONFIG: - mldl_cfg->int_config = (unsigned char) arg; - break; - case MPU_SET_EXT_SYNC: - mldl_cfg->ext_sync = (enum mpu_ext_sync) arg; - break; - case MPU_SET_FULL_SCALE: - mldl_cfg->full_scale = (enum mpu_fullscale) arg; - break; - case MPU_SET_LPF: - mldl_cfg->lpf = (enum mpu_filter) arg; - break; - case MPU_SET_CLK_SRC: - mldl_cfg->clk_src = (enum mpu_clock_sel) arg; - break; - case MPU_SET_DIVIDER: - mldl_cfg->divider = (unsigned char) arg; - break; - case MPU_SET_LEVEL_SHIFTER: - mldl_cfg->pdata->level_shifter = (unsigned char) arg; - break; - case MPU_SET_DMP_ENABLE: - mldl_cfg->dmp_enable = (unsigned char) arg; - break; - case MPU_SET_FIFO_ENABLE: - mldl_cfg->fifo_enable = (unsigned char) arg; - break; - case MPU_SET_DMP_CFG1: - mldl_cfg->dmp_cfg1 = (unsigned char) arg; - break; - case MPU_SET_DMP_CFG2: - mldl_cfg->dmp_cfg2 = (unsigned char) arg; - break; - case MPU_SET_OFFSET_TC: - retval = copy_from_user(mldl_cfg->offset_tc, - (unsigned char __user *) arg, - sizeof(mldl_cfg->offset_tc)); - break; - case MPU_SET_RAM: - retval = copy_from_user(mldl_cfg->ram, - (unsigned char __user *) arg, - sizeof(mldl_cfg->ram)); - break; case MPU_SET_PLATFORM_DATA: retval = mpu_ioctl_set_mpu_pdata(client, arg); break; case MPU_GET_MPU_CONFIG: retval = mpu_ioctl_get_mpu_config(client, arg); break; - case MPU_GET_INT_CONFIG: - retval = put_user(mldl_cfg->int_config, - (unsigned char __user *) arg); - break; - case MPU_GET_EXT_SYNC: - retval = put_user(mldl_cfg->ext_sync, - (unsigned char __user *) arg); - break; - case MPU_GET_FULL_SCALE: - retval = put_user(mldl_cfg->full_scale, - (unsigned char __user *) arg); - break; - case MPU_GET_LPF: - retval = put_user(mldl_cfg->lpf, - (unsigned char __user *) arg); - break; - case MPU_GET_CLK_SRC: - retval = put_user(mldl_cfg->clk_src, - (unsigned char __user *) arg); - break; - case MPU_GET_DIVIDER: - retval = put_user(mldl_cfg->divider, - (unsigned char __user *) arg); - break; - case MPU_GET_LEVEL_SHIFTER: - retval = put_user(mldl_cfg->pdata->level_shifter, - (unsigned char __user *) arg); - break; - case MPU_GET_DMP_ENABLE: - retval = put_user(mldl_cfg->dmp_enable, - (unsigned char __user *) arg); - break; - case MPU_GET_FIFO_ENABLE: - retval = put_user(mldl_cfg->fifo_enable, - (unsigned char __user *) arg); - break; - case MPU_GET_DMP_CFG1: - retval = put_user(mldl_cfg->dmp_cfg1, - (unsigned char __user *) arg); - break; - case MPU_GET_DMP_CFG2: - retval = put_user(mldl_cfg->dmp_cfg2, - (unsigned char __user *) arg); - break; - case MPU_GET_OFFSET_TC: - retval = copy_to_user((unsigned char __user *) arg, - mldl_cfg->offset_tc, - sizeof(mldl_cfg->offset_tc)); - break; - case MPU_GET_RAM: - retval = copy_to_user((unsigned char __user *) arg, - mldl_cfg->ram, - sizeof(mldl_cfg->ram)); + case MPU_READ: + case MPU_WRITE: + case MPU_READ_MEM: + case MPU_WRITE_MEM: + case MPU_READ_FIFO: + case MPU_WRITE_FIFO: + retval = mpu_handle_mlsl(client->adapter, mldl_cfg->addr, cmd, + (struct mpu_read_write __user *) arg); break; case MPU_CONFIG_ACCEL: - { - if ((mldl_cfg->accel) && (mldl_cfg->accel->config)) { - struct ext_slave_config config; - retval = copy_from_user( - &config, - (struct ext_slave_config *)arg, - sizeof(config)); - if (retval) - break; - - if (config.len && config.data) { - int *data; - data = kzalloc(config.len, GFP_KERNEL); - if (!data) { - retval = ML_ERROR_MEMORY_EXAUSTED; - break; - } - retval = copy_from_user(data, - (void *)config.data, - config.len); - if (retval) { - kfree(data); - break; - } - config.data = data; - } - retval = mldl_cfg->accel->config( - accel_adapter, + retval = slave_config(accel_adapter, mldl_cfg, mldl_cfg->accel, &mldl_cfg->pdata->accel, - &config); - kfree(config.data); - } + (struct ext_slave_config __user *) arg); break; - } case MPU_CONFIG_COMPASS: - { - if ((mldl_cfg->compass) && (mldl_cfg->compass->config)) { - struct ext_slave_config config; - retval = copy_from_user( - &config, - (struct ext_slave_config *)arg, - sizeof(config)); - if (retval) - break; - - if (config.len && config.data) { - int *data; - data = kzalloc(config.len, GFP_KERNEL); - if (!data) { - retval = ML_ERROR_MEMORY_EXAUSTED; - break; - } - retval = copy_from_user(data, - (void *)config.data, - config.len); - if (retval) { - kfree(data); - break; - } - config.data = data; - } - retval = mldl_cfg->compass->config( - compass_adapter, + retval = slave_config(compass_adapter, mldl_cfg, mldl_cfg->compass, &mldl_cfg->pdata->compass, - &config); - kfree(config.data); - } + (struct ext_slave_config __user *) arg); break; - } case MPU_CONFIG_PRESSURE: - { - if ((mldl_cfg->pressure) && (mldl_cfg->pressure->config)) { - struct ext_slave_config config; - retval = copy_from_user( - &config, - (struct ext_slave_config *)arg, - sizeof(config)); - if (retval) - break; - - if (config.len && config.data) { - int *data; - data = kzalloc(config.len, GFP_KERNEL); - if (!data) { - retval = ML_ERROR_MEMORY_EXAUSTED; - break; - } - retval = copy_from_user(data, - (void *)config.data, - config.len); - if (retval) { - kfree(data); - break; - } - config.data = data; - } - retval = mldl_cfg->pressure->config( - pressure_adapter, + retval = slave_config(pressure_adapter, mldl_cfg, mldl_cfg->pressure, &mldl_cfg->pdata->pressure, - &config); - kfree(config.data); - } + (struct ext_slave_config __user *) arg); + break; + case MPU_GET_CONFIG_ACCEL: + retval = slave_get_config(accel_adapter, mldl_cfg, + mldl_cfg->accel, + &mldl_cfg->pdata->accel, + (struct ext_slave_config __user *) arg); + break; + case MPU_GET_CONFIG_COMPASS: + retval = slave_get_config(compass_adapter, mldl_cfg, + mldl_cfg->compass, + &mldl_cfg->pdata->compass, + (struct ext_slave_config __user *) arg); + break; + case MPU_GET_CONFIG_PRESSURE: + retval = slave_get_config(pressure_adapter, mldl_cfg, + mldl_cfg->pressure, + &mldl_cfg->pdata->pressure, + (struct ext_slave_config __user *) arg); break; - } - case MPU_READ_MEMORY: - case MPU_WRITE_MEMORY: case MPU_SUSPEND: { unsigned long sensors; @@ -729,55 +753,59 @@ static long mpu_ioctl(struct file *file, sensors & ML_THREE_AXIS_PRESSURE); } break; - case MPU_READ_ACCEL: - { - unsigned char data[6]; - retval = - mpu3050_read_accel(mldl_cfg, client->adapter, - data); - if (ML_SUCCESS == retval) - retval = - copy_to_user((unsigned char __user *) arg, - data, sizeof(data)); - } + case MPU_PM_EVENT_HANDLED: + dev_dbg(&this_client->adapter->dev, + "%s: %d\n", __func__, cmd); + complete(&mpu->completion); break; + case MPU_READ_ACCEL: + { + unsigned char data[6]; + retval = mpu3050_read_accel(mldl_cfg, client->adapter, + data); + if ((ML_SUCCESS == retval) && + (copy_to_user((unsigned char __user *) arg, + data, sizeof(data)))) + retval = -EFAULT; + } + break; case MPU_READ_COMPASS: - { - unsigned char data[6]; - struct i2c_adapter *compass_adapt = - i2c_get_adapter(mldl_cfg->pdata->compass. - adapt_num); - retval = - mpu3050_read_compass(mldl_cfg, compass_adapt, + { + unsigned char data[6]; + struct i2c_adapter *compass_adapt = + i2c_get_adapter(mldl_cfg->pdata->compass. + adapt_num); + retval = mpu3050_read_compass(mldl_cfg, compass_adapt, data); - if (ML_SUCCESS == retval) - retval = - copy_to_user((unsigned char *) arg, - data, sizeof(data)); - } - break; + if ((ML_SUCCESS == retval) && + (copy_to_user((unsigned char *) arg, + data, sizeof(data)))) + retval = -EFAULT; + } + break; case MPU_READ_PRESSURE: - { - unsigned char data[3]; - struct i2c_adapter *pressure_adapt = - i2c_get_adapter(mldl_cfg->pdata->pressure. - adapt_num); - retval = - mpu3050_read_pressure(mldl_cfg, pressure_adapt, - data); - if (ML_SUCCESS == retval) - retval = - copy_to_user((unsigned char __user *) arg, - data, sizeof(data)); - } - break; + { + unsigned char data[3]; + struct i2c_adapter *pressure_adapt = + i2c_get_adapter(mldl_cfg->pdata->pressure. + adapt_num); + retval = + mpu3050_read_pressure(mldl_cfg, pressure_adapt, + data); + if ((ML_SUCCESS == retval) && + (copy_to_user((unsigned char __user *) arg, + data, sizeof(data)))) + retval = -EFAULT; + } + break; default: dev_err(&this_client->adapter->dev, - "%s: Unknown cmd %d, arg %lu\n", __func__, cmd, + "%s: Unknown cmd %x, arg %lu\n", __func__, cmd, arg); retval = -EINVAL; } + mutex_unlock(&mpu->mutex); return retval; } @@ -801,10 +829,13 @@ void mpu3050_early_suspend(struct early_suspend *h) dev_dbg(&this_client->adapter->dev, "%s: %d, %d\n", __func__, h->level, mpu->mldl_cfg.gyro_is_suspended); - if (MPU3050_EARLY_SUSPEND_IN_DRIVER) + if (MPU3050_EARLY_SUSPEND_IN_DRIVER) { + mutex_lock(&mpu->mutex); (void) mpu3050_suspend(mldl_cfg, this_client->adapter, accel_adapter, compass_adapter, pressure_adapter, TRUE, TRUE, TRUE, TRUE); + mutex_unlock(&mpu->mutex); + } } void mpu3050_early_resume(struct early_suspend *h) @@ -825,8 +856,9 @@ void mpu3050_early_resume(struct early_suspend *h) i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); if (MPU3050_EARLY_SUSPEND_IN_DRIVER) { - if (pid) { + if (mpu->pid) { unsigned long sensors = mldl_cfg->requested_sensors; + mutex_lock(&mpu->mutex); (void) mpu3050_resume(mldl_cfg, this_client->adapter, accel_adapter, @@ -836,8 +868,9 @@ void mpu3050_early_resume(struct early_suspend *h) sensors & ML_THREE_AXIS_ACCEL, sensors & ML_THREE_AXIS_COMPASS, sensors & ML_THREE_AXIS_PRESSURE); + mutex_unlock(&mpu->mutex); dev_dbg(&this_client->adapter->dev, - "%s for pid %d\n", __func__, pid); + "%s for pid %d\n", __func__, mpu->pid); } } dev_dbg(&this_client->adapter->dev, "%s: %d\n", __func__, h->level); @@ -859,9 +892,11 @@ void mpu_shutdown(struct i2c_client *client) pressure_adapter = i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); + mutex_lock(&mpu->mutex); (void) mpu3050_suspend(mldl_cfg, this_client->adapter, accel_adapter, compass_adapter, pressure_adapter, TRUE, TRUE, TRUE, TRUE); + mutex_unlock(&mpu->mutex); dev_dbg(&this_client->adapter->dev, "%s\n", __func__); } @@ -880,7 +915,8 @@ int mpu_suspend(struct i2c_client *client, pm_message_t mesg) pressure_adapter = i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - if (!mpu->mldl_cfg.gyro_is_suspended) { + mutex_lock(&mpu->mutex); + if (!mldl_cfg->ignore_system_suspend) { dev_dbg(&this_client->adapter->dev, "%s: suspending on event %d\n", __func__, mesg.event); @@ -893,6 +929,7 @@ int mpu_suspend(struct i2c_client *client, pm_message_t mesg) "%s: Already suspended %d\n", __func__, mesg.event); } + mutex_unlock(&mpu->mutex); return 0; } @@ -911,7 +948,8 @@ int mpu_resume(struct i2c_client *client) pressure_adapter = i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - if (pid) { + mutex_lock(&mpu->mutex); + if (mpu->pid && !mldl_cfg->ignore_system_suspend) { unsigned long sensors = mldl_cfg->requested_sensors; (void) mpu3050_resume(mldl_cfg, this_client->adapter, accel_adapter, @@ -922,8 +960,9 @@ int mpu_resume(struct i2c_client *client) sensors & ML_THREE_AXIS_COMPASS, sensors & ML_THREE_AXIS_PRESSURE); dev_dbg(&this_client->adapter->dev, - "%s for pid %d\n", __func__, pid); + "%s for pid %d\n", __func__, mpu->pid); } + mutex_unlock(&mpu->mutex); return 0; } @@ -931,6 +970,8 @@ int mpu_resume(struct i2c_client *client) static const struct file_operations mpu_fops = { .owner = THIS_MODULE, .read = mpu_read, + .poll = mpu_poll, + #if HAVE_COMPAT_IOCTL .compat_ioctl = mpu_ioctl, #endif @@ -981,15 +1022,30 @@ int mpu3050_probe(struct i2c_client *client, i2c_set_clientdata(client, mpu); this_client = client; mldl_cfg = &mpu->mldl_cfg; + + init_waitqueue_head(&mpu->mpu_event_wait); + + mutex_init(&mpu->mutex); + init_completion(&mpu->completion); + + mpu->response_timeout = 60; /* Seconds */ + mpu->timeout.function = mpu_pm_timeout; + mpu->timeout.data = (u_long) mpu; + init_timer(&mpu->timeout); + + mpu->nb.notifier_call = mpu_pm_notifier_callback; + mpu->nb.priority = 0; + register_pm_notifier(&mpu->nb); + pdata = (struct mpu3050_platform_data *) client->dev.platform_data; if (!pdata) { - dev_warn(&this_client->adapter->dev, - "Warning no platform data for mpu3050\n"); + dev_WARN(&this_client->adapter->dev, + "Missing platform data for mpu3050\n"); } else { mldl_cfg->pdata = pdata; -#if defined(CONFIG_SENSORS_MPU3050_MODULE) || \ - defined(CONFIG_SENSORS_MPU6000_MODULE) +#if defined(CONFIG_MPU_SENSORS_MPU3050_MODULE) || \ + defined(CONFIG_MPU_SENSORS_MPU6000_MODULE) pdata->accel.get_slave_descr = get_accel_slave_descr; pdata->compass.get_slave_descr = get_compass_slave_descr; pdata->pressure.get_slave_descr = get_pressure_slave_descr; @@ -1013,7 +1069,7 @@ int mpu3050_probe(struct i2c_client *client, if (res) goto out_accelirq_failed; } else { - dev_warn(&this_client->adapter->dev, + dev_WARN(&this_client->adapter->dev, "WARNING: Accel irq not assigned\n"); } } else { @@ -1100,8 +1156,8 @@ int mpu3050_probe(struct i2c_client *client, if (res) goto out_mpuirq_failed; } else { - dev_warn(&this_client->adapter->dev, - "WARNING: %s irq not assigned\n", MPU_NAME); + dev_WARN(&this_client->adapter->dev, + "Missing %s IRQ\n", MPU_NAME); } @@ -1220,20 +1276,17 @@ static struct i2c_driver mpu3050_driver = { static int __init mpu_init(void) { - printk("xxm -> enter mpu_init\n"); int res = i2c_add_driver(&mpu3050_driver); - pid = 0; - printk(KERN_DEBUG "%s\n", __func__); - printk("xxm-> end mpu_init\n"); - if (res){ - dev_err(&this_client->adapter->dev, "%s\n", + pr_debug("%s\n", __func__); + if (res) + pr_err("%s failed\n", __func__); return res; - } } + static void __exit mpu_exit(void) { - printk(KERN_DEBUG "%s\n", __func__); + pr_debug("%s\n", __func__); i2c_del_driver(&mpu3050_driver); } diff --git a/drivers/misc/mpu3050/mpu-i2c.c b/drivers/misc/mpu3050/mpu-i2c.c old mode 100644 new mode 100755 index 3c7e3efcc472..b1298d313abf --- a/drivers/misc/mpu3050/mpu-i2c.c +++ b/drivers/misc/mpu3050/mpu-i2c.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -17,7 +30,6 @@ #include #include "mpu.h" -#define MPU_SPEED 400 * 1000 int sensor_i2c_write(struct i2c_adapter *i2c_adap, unsigned char address, unsigned int len, unsigned char const *data) @@ -32,7 +44,6 @@ int sensor_i2c_write(struct i2c_adapter *i2c_adap, msgs[0].flags = 0; /* write */ msgs[0].buf = (unsigned char *) data; msgs[0].len = len; - msgs[0].scl_rate = MPU_SPEED; res = i2c_transfer(i2c_adap, msgs, 1); if (res < 1) @@ -51,6 +62,7 @@ int sensor_i2c_write_register(struct i2c_adapter *i2c_adap, data[1] = value; return sensor_i2c_write(i2c_adap, address, 2, data); } + int sensor_i2c_read(struct i2c_adapter *i2c_adap, unsigned char address, unsigned char reg, @@ -66,13 +78,11 @@ int sensor_i2c_read(struct i2c_adapter *i2c_adap, msgs[0].flags = 0; /* write */ msgs[0].buf = ® msgs[0].len = 1; - msgs[0].scl_rate = MPU_SPEED; msgs[1].addr = address; msgs[1].flags = I2C_M_RD; msgs[1].buf = data; msgs[1].len = len; - msgs[1].scl_rate = MPU_SPEED; res = i2c_transfer(i2c_adap, msgs, 2); if (res < 2) @@ -109,25 +119,21 @@ int mpu_memory_read(struct i2c_adapter *i2c_adap, msgs[0].flags = 0; msgs[0].buf = bank; msgs[0].len = sizeof(bank); - msgs[0].scl_rate = MPU_SPEED; msgs[1].addr = mpu_addr; msgs[1].flags = 0; msgs[1].buf = addr; msgs[1].len = sizeof(addr); - msgs[1].scl_rate = MPU_SPEED; msgs[2].addr = mpu_addr; msgs[2].flags = 0; msgs[2].buf = &buf; msgs[2].len = 1; - msgs[2].scl_rate = MPU_SPEED; msgs[3].addr = mpu_addr; msgs[3].flags = I2C_M_RD; msgs[3].buf = data; msgs[3].len = len; - msgs[3].scl_rate = MPU_SPEED; ret = i2c_transfer(i2c_adap, msgs, 4); if (ret != 4) @@ -167,20 +173,17 @@ int mpu_memory_write(struct i2c_adapter *i2c_adap, msgs[0].flags = 0; msgs[0].buf = bank; msgs[0].len = sizeof(bank); - msgs[0].scl_rate = MPU_SPEED; msgs[1].addr = mpu_addr; msgs[1].flags = 0; msgs[1].buf = addr; msgs[1].len = sizeof(addr); - msgs[1].scl_rate = MPU_SPEED; msgs[2].addr = mpu_addr; msgs[2].flags = 0; msgs[2].buf = (unsigned char *) buf; msgs[2].len = len + 1; - msgs[2].scl_rate = MPU_SPEED; - + ret = i2c_transfer(i2c_adap, msgs, 3); if (ret != 3) return ret; diff --git a/drivers/misc/mpu3050/mpu-i2c.h b/drivers/misc/mpu3050/mpu-i2c.h old mode 100644 new mode 100755 index 7d58027977b2..0bbc8c64594e --- a/drivers/misc/mpu3050/mpu-i2c.h +++ b/drivers/misc/mpu3050/mpu-i2c.h @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** * @defgroup diff --git a/drivers/misc/mpu3050/mpuirq.c b/drivers/misc/mpu3050/mpuirq.c old mode 100644 new mode 100755 index 01ab307ec9a7..ce1ad409cbf4 --- a/drivers/misc/mpu3050/mpuirq.c +++ b/drivers/misc/mpu3050/mpuirq.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ #include #include @@ -16,8 +29,6 @@ #include #include #include -#include -#include #include #include @@ -50,7 +61,7 @@ struct mpuirq_dev_data { }; static struct mpuirq_dev_data mpuirq_dev_data; -static struct irq_data mpuirq_data; +static struct mpuirq_data mpuirq_data; static char *interface = MPUIRQ_NAME; static void mpu_accel_data_work_fcn(struct work_struct *work); @@ -61,9 +72,6 @@ static int mpuirq_open(struct inode *inode, struct file *file) "%s current->pid %d\n", __func__, current->pid); mpuirq_dev_data.pid = current->pid; file->private_data = &mpuirq_dev_data; - /* we could do some checking on the flags supplied by "open" */ - /* i.e. O_NONBLOCK */ - /* -> set some flag to disable interruptible_sleep_on in mpuirq_read */ return 0; } @@ -81,7 +89,9 @@ static ssize_t mpuirq_read(struct file *file, int len, err; struct mpuirq_dev_data *p_mpuirq_dev_data = file->private_data; - if (!mpuirq_dev_data.data_ready) { + if (!mpuirq_dev_data.data_ready && + mpuirq_dev_data.timeout && + (!(file->f_flags & O_NONBLOCK))) { wait_event_interruptible_timeout(mpuirq_wait, mpuirq_dev_data. data_ready, @@ -195,23 +205,20 @@ static irqreturn_t mpuirq_handler(int irq, void *dev_id) /* wake up (unblock) for reading data from userspace */ /* and ignore first interrupt generated in module init */ - if (mpuirq_data.interruptcount > 1) { - mpuirq_dev_data.data_ready = 1; - - do_gettimeofday(&irqtime); - mpuirq_data.irqtime = (((long long) irqtime.tv_sec) << 32); - mpuirq_data.irqtime += irqtime.tv_usec; - - if ((mpuirq_dev_data.accel_divider >= 0) && - (0 == - (mycount % (mpuirq_dev_data.accel_divider + 1)))) { - schedule_work((struct work_struct - *) (&mpuirq_dev_data)); - } + mpuirq_dev_data.data_ready = 1; + + do_gettimeofday(&irqtime); + mpuirq_data.irqtime = (((long long) irqtime.tv_sec) << 32); + mpuirq_data.irqtime += irqtime.tv_usec; - wake_up_interruptible(&mpuirq_wait); + if ((mpuirq_dev_data.accel_divider >= 0) && + (0 == (mycount % (mpuirq_dev_data.accel_divider + 1)))) { + schedule_work((struct work_struct + *) (&mpuirq_dev_data)); } + wake_up_interruptible(&mpuirq_wait); + return IRQ_HANDLED; } @@ -267,28 +274,14 @@ int mpuirq_init(struct i2c_client *mpu_client) flags = IRQF_TRIGGER_FALLING; else flags = IRQF_TRIGGER_RISING; - /* mpu irq register xxm*/ - res = gpio_request(mpuirq_dev_data.irq, "mpu3050_int"); - if(res) - { - printk("failed to request mpu3050_int GPIO %d\n", - gpio_to_irq(mpuirq_dev_data.irq)); - return res; - } - res = gpio_direction_input(mpuirq_dev_data.irq); - if(res) - { - printk("failed to set mpu3050_int GPIO input\n"); - return res; - } - printk("gpio_to_irq(mpuirq_dev_data.irq) == %d \r\n", - gpio_to_irq(mpuirq_dev_data.irq)); - res =request_irq(gpio_to_irq(mpuirq_dev_data.irq), mpuirq_handler, flags, - 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,return value is %d\n", - gpio_to_irq(mpuirq_dev_data.irq),res); + "myirqtest: cannot register IRQ %d\n", + mpuirq_dev_data.irq); } else { res = misc_register(&mpuirq_device); if (res < 0) { diff --git a/drivers/misc/mpu3050/mpuirq.h b/drivers/misc/mpu3050/mpuirq.h old mode 100644 new mode 100755 index 374cd337b239..a71c79c75e8c --- a/drivers/misc/mpu3050/mpuirq.h +++ b/drivers/misc/mpu3050/mpuirq.h @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ #ifndef __MPUIRQ__ @@ -9,15 +22,15 @@ #ifdef __KERNEL__ #include +#include +#else +#include #endif -#define MPUIRQ_ENABLE_DEBUG (1) -#define MPUIRQ_GET_INTERRUPT_CNT (2) -#define MPUIRQ_GET_IRQ_TIME (3) -#define MPUIRQ_GET_LED_VALUE (4) -#define MPUIRQ_SET_TIMEOUT (5) -#define MPUIRQ_SET_ACCEL_INFO (6) -#define MPUIRQ_SET_FREQUENCY_DIVIDER (7) +#define MPUIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x40, unsigned long) +#define MPUIRQ_GET_INTERRUPT_CNT _IOR(MPU_IOCTL, 0x41, unsigned long) +#define MPUIRQ_GET_IRQ_TIME _IOR(MPU_IOCTL, 0x42, struct timeval) +#define MPUIRQ_SET_FREQUENCY_DIVIDER _IOW(MPU_IOCTL, 0x43, unsigned long) #ifdef __KERNEL__ diff --git a/drivers/misc/mpu3050/slaveirq.c b/drivers/misc/mpu3050/slaveirq.c old mode 100644 new mode 100755 index e66da3b3edeb..a3c7bfec4b4b --- a/drivers/misc/mpu3050/slaveirq.c +++ b/drivers/misc/mpu3050/slaveirq.c @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ #include #include @@ -15,8 +28,6 @@ #include #include #include -#include -#include #include #include @@ -25,19 +36,20 @@ #include #include #include +#include +#include #include "mpu.h" #include "slaveirq.h" #include "mldl_cfg.h" #include "mpu-i2c.h" -#include -#include + /* function which gets slave data and sends it to SLAVE */ struct slaveirq_dev_data { struct miscdevice dev; struct i2c_client *slave_client; - struct irq_data data; + struct mpuirq_data data; wait_queue_head_t slaveirq_wait; int irq; int pid; @@ -77,7 +89,9 @@ static ssize_t slaveirq_read(struct file *file, struct slaveirq_dev_data *data = container_of(file->private_data, struct slaveirq_dev_data, dev); - if (!data->data_ready) { + if (!data->data_ready && + data->timeout && + !(file->f_flags & O_NONBLOCK)) { wait_event_interruptible_timeout(data->slaveirq_wait, data->data_ready, data->timeout); @@ -100,7 +114,8 @@ static ssize_t slaveirq_read(struct file *file, return len; } -unsigned int slaveirq_poll(struct file *file, struct poll_table_struct *poll) +static unsigned int slaveirq_poll(struct file *file, + struct poll_table_struct *poll) { int mask = 0; struct slaveirq_dev_data *data = @@ -156,17 +171,14 @@ static irqreturn_t slaveirq_handler(int irq, void *dev_id) data->data.interruptcount++; /* wake up (unblock) for reading data from userspace */ - /* and ignore first interrupt generated in module init */ - if (data->data.interruptcount > 1) { - data->data_ready = 1; + data->data_ready = 1; - do_gettimeofday(&irqtime); - data->data.irqtime = (((long long) irqtime.tv_sec) << 32); - data->data.irqtime += irqtime.tv_usec; - data->data.data_type |= 1; + do_gettimeofday(&irqtime); + data->data.irqtime = (((long long) irqtime.tv_sec) << 32); + data->data.irqtime += irqtime.tv_usec; + data->data.data_type |= 1; - wake_up_interruptible(&data->slaveirq_wait); - } + wake_up_interruptible(&data->slaveirq_wait); return IRQ_HANDLED; @@ -213,24 +225,10 @@ int slaveirq_init(struct i2c_adapter *slave_adapter, data->data_ready = 0; data->timeout = 0; - /* mpu irq register xxm*/ - res = gpio_request(data->irq, name); - if(res) - { - printk("failed to request %s GPIO %d\n", - name,data->irq); - return res; - } - res = gpio_direction_input(data->irq); - if(res) - { - printk("failed to set %s GPIO input\n",name); - return res; - } - printk("%s registing irq == %d \r\n",name,gpio_to_irq(data->irq)); - //gpio_pull_updown(data->irq, GPIOPullUp); - //gpio_set_value(data->irq,GPIO_HIGH); - res = request_irq(gpio_to_irq(data->irq), slaveirq_handler, IRQF_TRIGGER_FALLING,data->dev.name, data); + init_waitqueue_head(&data->slaveirq_wait); + + res = request_irq(data->irq, slaveirq_handler, IRQF_TRIGGER_RISING, + data->dev.name, data); if (res) { dev_err(&slave_adapter->dev, @@ -247,7 +245,6 @@ int slaveirq_init(struct i2c_adapter *slave_adapter, goto out_misc_register; } - init_waitqueue_head(&data->slaveirq_wait); return res; out_misc_register: diff --git a/drivers/misc/mpu3050/slaveirq.h b/drivers/misc/mpu3050/slaveirq.h old mode 100644 new mode 100755 index ac53f1e9225a..b4e1115f1b0a --- a/drivers/misc/mpu3050/slaveirq.h +++ b/drivers/misc/mpu3050/slaveirq.h @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ #ifndef __SLAVEIRQ__ @@ -14,12 +27,9 @@ #include "mpu.h" #include "mpuirq.h" -#define SLAVEIRQ_ENABLE_DEBUG (1) -#define SLAVEIRQ_GET_INTERRUPT_CNT (2) -#define SLAVEIRQ_GET_IRQ_TIME (3) -#define SLAVEIRQ_GET_LED_VALUE (4) -#define SLAVEIRQ_SET_TIMEOUT (5) -#define SLAVEIRQ_SET_SLAVE_INFO (6) +#define SLAVEIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x50, unsigned long) +#define SLAVEIRQ_GET_INTERRUPT_CNT _IOR(MPU_IOCTL, 0x51, unsigned long) +#define SLAVEIRQ_GET_IRQ_TIME _IOR(MPU_IOCTL, 0x52, unsigned long) #ifdef __KERNEL__ diff --git a/drivers/misc/mpu3050/timerirq.c b/drivers/misc/mpu3050/timerirq.c new file mode 100755 index 000000000000..41c3ac981016 --- /dev/null +++ b/drivers/misc/mpu3050/timerirq.c @@ -0,0 +1,299 @@ +/* + $License: + Copyright (C) 2010 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 . + $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpu.h" +#include "mltypes.h" +#include "timerirq.h" + +/* function which gets timer data and sends it to TIMER */ +struct timerirq_data { + int pid; + int data_ready; + int run; + int timeout; + unsigned long period; + struct mpuirq_data data; + struct completion timer_done; + wait_queue_head_t timerirq_wait; + struct timer_list timer; + struct miscdevice *dev; +}; + +static struct miscdevice *timerirq_dev_data; + +static void timerirq_handler(unsigned long arg) +{ + struct timerirq_data *data = (struct timerirq_data *)arg; + struct timeval irqtime; + + data->data.interruptcount++; + + data->data_ready = 1; + + do_gettimeofday(&irqtime); + 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); + + wake_up_interruptible(&data->timerirq_wait); + + if (data->run) + mod_timer(&data->timer, + jiffies + msecs_to_jiffies(data->period)); + else + complete(&data->timer_done); +} + +static int start_timerirq(struct timerirq_data *data) +{ + dev_dbg(data->dev->this_device, + "%s current->pid %d\n", __func__, current->pid); + + /* Timer already running... success */ + if (data->run) + return 0; + + /* Don't allow a period of 0 since this would fire constantly */ + if (!data->period) + return -EINVAL; + + data->run = TRUE; + data->data_ready = FALSE; + + init_completion(&data->timer_done); + setup_timer(&data->timer, timerirq_handler, (unsigned long)data); + + return mod_timer(&data->timer, + jiffies + msecs_to_jiffies(data->period)); +} + +static int stop_timerirq(struct timerirq_data *data) +{ + dev_dbg(data->dev->this_device, + "%s current->pid %lx\n", __func__, (unsigned long)data); + + if (data->run) { + data->run = FALSE; + mod_timer(&data->timer, jiffies + 1); + wait_for_completion(&data->timer_done); + } + return 0; +} + +/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28 + * drivers: misc: pass miscdevice pointer via file private data + */ +static int timerirq_open(struct inode *inode, struct file *file) +{ + /* Device node is availabe in the file->private_data, this is + * exactly what we want so we leave it there */ + struct miscdevice *dev_data = file->private_data; + struct timerirq_data *data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev_data; + file->private_data = data; + data->pid = current->pid; + init_waitqueue_head(&data->timerirq_wait); + + dev_dbg(data->dev->this_device, + "%s current->pid %d\n", __func__, current->pid); + return 0; +} + +static int timerirq_release(struct inode *inode, struct file *file) +{ + struct timerirq_data *data = file->private_data; + dev_dbg(data->dev->this_device, "timerirq_release\n"); + if (data->run) + stop_timerirq(data); + kfree(data); + return 0; +} + +/* read function called when from /dev/timerirq is read */ +static ssize_t timerirq_read(struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + int len, err; + struct timerirq_data *data = file->private_data; + + if (!data->data_ready && + data->timeout && + !(file->f_flags & O_NONBLOCK)) { + wait_event_interruptible_timeout(data->timerirq_wait, + data->data_ready, + data->timeout); + } + + if (data->data_ready && NULL != buf + && count >= sizeof(data->data)) { + err = copy_to_user(buf, &data->data, sizeof(data->data)); + data->data.data_type = 0; + } else { + return 0; + } + if (err != 0) { + dev_err(data->dev->this_device, + "Copy to user returned %d\n", err); + return -EFAULT; + } + data->data_ready = 0; + len = sizeof(data->data); + return len; +} + +static unsigned int timerirq_poll(struct file *file, + struct poll_table_struct *poll) +{ + int mask = 0; + struct timerirq_data *data = file->private_data; + + poll_wait(file, &data->timerirq_wait, poll); + if (data->data_ready) + mask |= POLLIN | POLLRDNORM; + return mask; +} + +/* ioctl - I/O control */ +static long timerirq_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + int tmp; + struct timerirq_data *data = file->private_data; + + dev_dbg(data->dev->this_device, + "%s current->pid %d, %d, %ld\n", + __func__, current->pid, cmd, arg); + + if (!data) + return -EFAULT; + + switch (cmd) { + case TIMERIRQ_SET_TIMEOUT: + data->timeout = arg; + break; + case TIMERIRQ_GET_INTERRUPT_CNT: + tmp = data->data.interruptcount - 1; + if (data->data.interruptcount > 1) + data->data.interruptcount = 1; + + if (copy_to_user((int *) arg, &tmp, sizeof(int))) + return -EFAULT; + break; + case TIMERIRQ_START: + data->period = arg; + retval = start_timerirq(data); + break; + case TIMERIRQ_STOP: + retval = stop_timerirq(data); + break; + default: + retval = -EINVAL; + } + return retval; +} + +/* define which file operations are supported */ +static const struct file_operations timerirq_fops = { + .owner = THIS_MODULE, + .read = timerirq_read, + .poll = timerirq_poll, + +#if HAVE_COMPAT_IOCTL + .compat_ioctl = timerirq_ioctl, +#endif +#if HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = timerirq_ioctl, +#endif + .open = timerirq_open, + .release = timerirq_release, +}; + +static int __init timerirq_init(void) +{ + + int res; + static struct miscdevice *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + timerirq_dev_data = data; + data->minor = MISC_DYNAMIC_MINOR; + data->name = "timerirq"; + data->fops = &timerirq_fops; + + res = misc_register(data); + if (res < 0) { + dev_err(data->this_device, + "misc_register returned %d\n", + res); + return res; + } + + return res; +} +module_init(timerirq_init); + +static void __exit timerirq_exit(void) +{ + struct miscdevice *data = timerirq_dev_data; + + dev_info(data->this_device, "Unregistering %s\n", + data->name); + + misc_deregister(data); + kfree(data); + + timerirq_dev_data = NULL; +} +module_exit(timerirq_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Timer IRQ device driver."); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("timerirq"); diff --git a/drivers/misc/mpu3050/timerirq.h b/drivers/misc/mpu3050/timerirq.h new file mode 100755 index 000000000000..ec2c1e29f080 --- /dev/null +++ b/drivers/misc/mpu3050/timerirq.h @@ -0,0 +1,30 @@ +/* + $License: + Copyright (C) 2010 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 . + $ + */ + +#ifndef __TIMERIRQ__ +#define __TIMERIRQ__ + +#include "mpu.h" + +#define TIMERIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x60, unsigned long) +#define TIMERIRQ_GET_INTERRUPT_CNT _IOW(MPU_IOCTL, 0x61, unsigned long) +#define TIMERIRQ_START _IOW(MPU_IOCTL, 0x62, unsigned long) +#define TIMERIRQ_STOP _IO(MPU_IOCTL, 0x63) + +#endif diff --git a/include/linux/mpu.h b/include/linux/mpu.h old mode 100644 new mode 100755 index da1c6bc1aea0..d66d9e76b9af --- a/include/linux/mpu.h +++ b/include/linux/mpu.h @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ #ifndef __MPU_H_ @@ -9,6 +22,9 @@ #ifdef __KERNEL__ #include +#include +#elif defined LINUX +#include #endif #ifdef M_HW @@ -22,94 +38,110 @@ #define ACCEL_NUM_AXES (3) #define COMPASS_NUM_AXES (3) +#if defined __KERNEL__ || defined LINUX +#define MPU_IOCTL (0x81) /* Magic number for MPU Iocts */ /* IOCTL commands for /dev/mpu */ -#define MPU_SET_MPU_CONFIG (0x00) -#define MPU_SET_INT_CONFIG (0x01) -#define MPU_SET_EXT_SYNC (0x02) -#define MPU_SET_FULL_SCALE (0x03) -#define MPU_SET_LPF (0x04) -#define MPU_SET_CLK_SRC (0x05) -#define MPU_SET_DIVIDER (0x06) -#define MPU_SET_LEVEL_SHIFTER (0x07) -#define MPU_SET_DMP_ENABLE (0x08) -#define MPU_SET_FIFO_ENABLE (0x09) -#define MPU_SET_DMP_CFG1 (0x0a) -#define MPU_SET_DMP_CFG2 (0x0b) -#define MPU_SET_OFFSET_TC (0x0c) -#define MPU_SET_RAM (0x0d) - -#define MPU_SET_PLATFORM_DATA (0x0e) - -#define MPU_GET_MPU_CONFIG (0x80) -#define MPU_GET_INT_CONFIG (0x81) -#define MPU_GET_EXT_SYNC (0x82) -#define MPU_GET_FULL_SCALE (0x83) -#define MPU_GET_LPF (0x84) -#define MPU_GET_CLK_SRC (0x85) -#define MPU_GET_DIVIDER (0x86) -#define MPU_GET_LEVEL_SHIFTER (0x87) -#define MPU_GET_DMP_ENABLE (0x88) -#define MPU_GET_FIFO_ENABLE (0x89) -#define MPU_GET_DMP_CFG1 (0x8a) -#define MPU_GET_DMP_CFG2 (0x8b) -#define MPU_GET_OFFSET_TC (0x8c) -#define MPU_GET_RAM (0x8d) - -#define MPU_READ_REGISTER (0x40) -#define MPU_WRITE_REGISTER (0x41) -#define MPU_READ_MEMORY (0x42) -#define MPU_WRITE_MEMORY (0x43) - -#define MPU_SUSPEND (0x44) -#define MPU_RESUME (0x45) -#define MPU_READ_COMPASS (0x46) -#define MPU_READ_ACCEL (0x47) -#define MPU_READ_PRESSURE (0x48) - -#define MPU_CONFIG_ACCEL (0x20) -#define MPU_CONFIG_COMPASS (0x21) -#define MPU_CONFIG_PRESSURE (0x22) +#define MPU_SET_MPU_CONFIG _IOW(MPU_IOCTL, 0x00, struct mldl_cfg) +#define MPU_GET_MPU_CONFIG _IOR(MPU_IOCTL, 0x00, struct mldl_cfg) + +#define MPU_SET_PLATFORM_DATA _IOW(MPU_IOCTL, 0x01, struct mldl_cfg) + +#define MPU_READ _IOR(MPU_IOCTL, 0x10, struct mpu_read_write) +#define MPU_WRITE _IOW(MPU_IOCTL, 0x10, struct mpu_read_write) +#define MPU_READ_MEM _IOR(MPU_IOCTL, 0x11, struct mpu_read_write) +#define MPU_WRITE_MEM _IOW(MPU_IOCTL, 0x11, struct mpu_read_write) +#define MPU_READ_FIFO _IOR(MPU_IOCTL, 0x12, struct mpu_read_write) +#define MPU_WRITE_FIFO _IOW(MPU_IOCTL, 0x12, struct mpu_read_write) + +#define MPU_READ_COMPASS _IOR(MPU_IOCTL, 0x12, unsigned char) +#define MPU_READ_ACCEL _IOR(MPU_IOCTL, 0x13, unsigned char) +#define MPU_READ_PRESSURE _IOR(MPU_IOCTL, 0x14, unsigned char) + +#define MPU_CONFIG_ACCEL _IOW(MPU_IOCTL, 0x20, struct ext_slave_config) +#define MPU_CONFIG_COMPASS _IOW(MPU_IOCTL, 0x21, struct ext_slave_config) +#define MPU_CONFIG_PRESSURE _IOW(MPU_IOCTL, 0x22, struct ext_slave_config) + +#define MPU_GET_CONFIG_ACCEL _IOR(MPU_IOCTL, 0x20, struct ext_slave_config) +#define MPU_GET_CONFIG_COMPASS _IOR(MPU_IOCTL, 0x21, struct ext_slave_config) +#define MPU_GET_CONFIG_PRESSURE _IOR(MPU_IOCTL, 0x22, struct ext_slave_config) +#define MPU_SUSPEND _IO(MPU_IOCTL, 0x30) +#define MPU_RESUME _IO(MPU_IOCTL, 0x31) +/* Userspace PM Event response */ +#define MPU_PM_EVENT_HANDLED _IO(MPU_IOCTL, 0x32) + +#endif /* Structure for the following IOCTL's: - MPU_SET_RAM - MPU_GET_RAM - MPU_READ_REGISTER - MPU_WRITE_REGISTER - MPU_READ_MEMORY - MPU_WRITE_MEMORY + MPU_READ + MPU_WRITE + MPU_READ_MEM + MPU_WRITE_MEM + MPU_READ_FIFO + MPU_WRITE_FIFO */ struct mpu_read_write { + /* Memory address or register address depending on ioctl */ unsigned short address; unsigned short length; unsigned char *data; }; -struct irq_data { +enum mpuirq_data_type { + MPUIRQ_DATA_TYPE_MPU_IRQ, + MPUIRQ_DATA_TYPE_SLAVE_IRQ, + MPUIRQ_DATA_TYPE_PM_EVENT, + MPUIRQ_DATA_TYPE_NUM_TYPES, +}; + +/* User space PM event notification */ +#define MPU_PM_EVENT_SUSPEND_PREPARE (3) +#define MPU_PM_EVENT_POST_SUSPEND (4) + +#define MAX_MPUIRQ_DATA_SIZE (32) + +struct mpuirq_data { int interruptcount; unsigned long long irqtime; int data_type; int data_size; void *data; }; + enum ext_slave_config_key { - MPU_SLAVE_CONFIG_ODR_SUSPEND, - MPU_SLAVE_CONFIG_ODR_RESUME, - MPU_SLAVE_CONFIG_FSR_SUSPEND, - MPU_SLAVE_CONFIG_FSR_RESUME, - MPU_SLAVE_CONFIG_MOT_THS, - MPU_SLAVE_CONFIG_NMOT_THS, - MPU_SLAVE_CONFIG_MOT_DUR, - MPU_SLAVE_CONFIG_NMOT_DUR, - MPU_SLAVE_CONFIG_NUM_CONFIG_KEYS, + MPU_SLAVE_CONFIG_ODR_SUSPEND, + MPU_SLAVE_CONFIG_ODR_RESUME, + MPU_SLAVE_CONFIG_FSR_SUSPEND, + MPU_SLAVE_CONFIG_FSR_RESUME, + MPU_SLAVE_CONFIG_MOT_THS, + MPU_SLAVE_CONFIG_NMOT_THS, + MPU_SLAVE_CONFIG_MOT_DUR, + MPU_SLAVE_CONFIG_NMOT_DUR, + MPU_SLAVE_CONFIG_IRQ_SUSPEND, + MPU_SLAVE_CONFIG_IRQ_RESUME, + MPU_SLAVE_WRITE_REGISTERS, + MPU_SLAVE_READ_REGISTERS, + MPU_SLAVE_CONFIG_NUM_CONFIG_KEYS, }; + +/* For the MPU_SLAVE_CONFIG_IRQ_SUSPEND and MPU_SLAVE_CONFIG_IRQ_RESUME */ +enum ext_slave_config_irq_type { + MPU_SLAVE_IRQ_TYPE_NONE, + MPU_SLAVE_IRQ_TYPE_MOTION, + MPU_SLAVE_IRQ_TYPE_DATA_READY, +}; + /* Structure for the following IOCTS's * MPU_CONFIG_ACCEL * MPU_CONFIG_COMPASS * MPU_CONFIG_PRESSURE + * MPU_GET_CONFIG_ACCEL + * MPU_GET_CONFIG_COMPASS + * MPU_GET_CONFIG_PRESSURE */ struct ext_slave_config { int key; int len; + int apply; void *data; }; @@ -126,22 +158,26 @@ enum ext_slave_id { ACCEL_ID_LIS331, ACCEL_ID_LSM303, + ACCEL_ID_LIS3DH, ACCEL_ID_KXSD9, ACCEL_ID_KXTF9, ACCEL_ID_BMA150, ACCEL_ID_BMA222, ACCEL_ID_ADI346, ACCEL_ID_MMA8450, - ACCEL_ID_MMA8451, + ACCEL_ID_MMA845X, ACCEL_ID_MPU6000, COMPASS_ID_AKM, COMPASS_ID_AMI30X, + COMPASS_ID_AMI306, COMPASS_ID_YAS529, + COMPASS_ID_YAS530, COMPASS_ID_HMC5883, COMPASS_ID_LSM303, COMPASS_ID_MMC314X, - COMPASS_ID_HSCDTD00XX, + COMPASS_ID_HSCDTD002B, + COMPASS_ID_HSCDTD004A, PRESSURE_ID_BMA085, }; @@ -205,6 +241,7 @@ struct tFixPntRange { * @init: function used to preallocate memory used by the driver * @exit: function used to free memory allocated for the driver * @config: function used to configure the device + * @get_config:function used to get the device's configuration * * @name: text name of the device * @type: device type. enum ext_slave_type @@ -238,6 +275,10 @@ struct ext_slave_descr { struct ext_slave_descr *slave, struct ext_slave_platform_data *pdata, struct ext_slave_config *config); + int (*get_config) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *config); char *name; unsigned char type; @@ -278,65 +319,73 @@ struct mpu3050_platform_data { */ #define get_accel_slave_descr NULL -#ifdef CONFIG_SENSORS_ADXL346 /* ADI accelerometer */ +#ifdef CONFIG_MPU_SENSORS_ADXL346 /* ADI accelerometer */ struct ext_slave_descr *adxl346_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr adxl346_get_slave_descr #endif -#ifdef CONFIG_SENSORS_BMA150 /* Bosch accelerometer */ +#ifdef CONFIG_MPU_SENSORS_BMA150 /* Bosch accelerometer */ struct ext_slave_descr *bma150_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr bma150_get_slave_descr #endif -#ifdef CONFIG_SENSORS_BMA222 /* Bosch 222 accelerometer */ +#ifdef CONFIG_MPU_SENSORS_BMA222 /* Bosch 222 accelerometer */ struct ext_slave_descr *bma222_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr bma222_get_slave_descr #endif -#ifdef CONFIG_SENSORS_KXSD9 /* Kionix accelerometer */ +#ifdef CONFIG_MPU_SENSORS_KXSD9 /* Kionix accelerometer */ struct ext_slave_descr *kxsd9_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr kxsd9_get_slave_descr #endif -#ifdef CONFIG_SENSORS_KXTF9 /* Kionix accelerometer */ +#ifdef CONFIG_MPU_SENSORS_KXTF9 /* Kionix accelerometer */ struct ext_slave_descr *kxtf9_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr kxtf9_get_slave_descr #endif -#ifdef CONFIG_SENSORS_LIS331DLH /* ST accelerometer */ +#ifdef CONFIG_MPU_SENSORS_LIS331DLH /* ST accelerometer */ struct ext_slave_descr *lis331dlh_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr lis331dlh_get_slave_descr #endif -#ifdef CONFIG_SENSORS_LSM303DLHA /* ST accelerometer */ + +#ifdef CONFIG_MPU_SENSORS_LIS3DH /* ST accelerometer */ +struct ext_slave_descr *lis3dh_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr lis3dh_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_LSM303DLHA /* ST accelerometer */ struct ext_slave_descr *lsm303dlha_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr lsm303dlha_get_slave_descr #endif /* MPU6000 Accel */ -#if defined(CONFIG_SENSORS_MPU6000) || defined(CONFIG_SENSORS_MPU6000_MODULE) +#if defined(CONFIG_MPU_SENSORS_MPU6000) || \ + defined(CONFIG_MPU_SENSORS_MPU6000_MODULE) struct ext_slave_descr *mantis_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr mantis_get_slave_descr #endif -#ifdef CONFIG_SENSORS_MMA8450 /* Freescale accelerometer */ +#ifdef CONFIG_MPU_SENSORS_MMA8450 /* Freescale accelerometer */ struct ext_slave_descr *mma8450_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr mma8450_get_slave_descr #endif -#ifdef CONFIG_SENSORS_MMA8451 /* Freescale accelerometer */ -struct ext_slave_descr *mma8451_get_slave_descr(void); +#ifdef CONFIG_MPU_SENSORS_MMA845X /* Freescale accelerometer */ +struct ext_slave_descr *mma845x_get_slave_descr(void); #undef get_accel_slave_descr -#define get_accel_slave_descr mma8451_get_slave_descr +#define get_accel_slave_descr mma845x_get_slave_descr #endif @@ -345,54 +394,71 @@ struct ext_slave_descr *mma8451_get_slave_descr(void); */ #define get_compass_slave_descr NULL -#ifdef CONFIG_SENSORS_AK8975 /* AKM compass */ +#ifdef CONFIG_MPU_SENSORS_AK8975 /* AKM compass */ struct ext_slave_descr *ak8975_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr ak8975_get_slave_descr #endif -#ifdef CONFIG_SENSORS_AMI30X /* AICHI Steel compass */ +#ifdef CONFIG_MPU_SENSORS_AMI30X /* AICHI Steel AMI304/305 compass */ struct ext_slave_descr *ami30x_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr ami30x_get_slave_descr #endif -#ifdef CONFIG_SENSORS_HMC5883 /* Honeywell compass */ +#ifdef CONFIG_MPU_SENSORS_AMI306 /* AICHI Steel AMI306 compass */ +struct ext_slave_descr *ami306_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr ami306_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_HMC5883 /* Honeywell compass */ struct ext_slave_descr *hmc5883_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr hmc5883_get_slave_descr #endif -#ifdef CONFIG_SENSORS_MMC314X /* MEMSIC compass */ +#ifdef CONFIG_MPU_SENSORS_MMC314X /* MEMSIC compass */ struct ext_slave_descr *mmc314x_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr mmc314x_get_slave_descr #endif -#ifdef CONFIG_SENSORS_LSM303DLHM /* ST compass */ +#ifdef CONFIG_MPU_SENSORS_LSM303DLHM /* ST compass */ struct ext_slave_descr *lsm303dlhm_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr lsm303dlhm_get_slave_descr #endif -#ifdef CONFIG_SENSORS_YAS529 /* Yamaha compass */ +#ifdef CONFIG_MPU_SENSORS_YAS529 /* Yamaha compass */ struct ext_slave_descr *yas529_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr yas529_get_slave_descr #endif -#ifdef CONFIG_SENSORS_HSCDTD00XX /* Alps compass */ -struct ext_slave_descr *hscdtd00xx_get_slave_descr(void); +#ifdef CONFIG_MPU_SENSORS_YAS530 /* Yamaha compass */ +struct ext_slave_descr *yas530_get_slave_descr(void); #undef get_compass_slave_descr -#define get_compass_slave_descr hscdtd00xx_get_slave_descr +#define get_compass_slave_descr yas530_get_slave_descr #endif +#ifdef CONFIG_MPU_SENSORS_HSCDTD002B /* Alps HSCDTD002B compass */ +struct ext_slave_descr *hscdtd002b_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr hscdtd002b_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_HSCDTD004A /* Alps HSCDTD004A compass */ +struct ext_slave_descr *hscdtd004a_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr hscdtd004a_get_slave_descr +#endif /* Pressure */ #define get_pressure_slave_descr NULL -#ifdef CONFIG_SENSORS_BMA085 /* BMA pressure */ +#ifdef CONFIG_MPU_SENSORS_BMA085 /* BMA pressure */ struct ext_slave_descr *bma085_get_slave_descr(void); #undef get_pressure_slave_descr #define get_pressure_slave_descr bma085_get_slave_descr diff --git a/include/linux/mpu3050.h b/include/linux/mpu3050.h old mode 100644 new mode 100755 index e2578239b76a..a8dcd5a9473f --- a/include/linux/mpu3050.h +++ b/include/linux/mpu3050.h @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ #ifndef __MPU3050_H_ @@ -17,7 +30,7 @@ #define MPU_NAME "mpu3050" #define DEFAULT_MPU_SLAVEADDR 0x68 -#include "mpu.h" + /*==== MPU REGISTER SET ====*/ enum mpu_register { MPUREG_WHO_AM_I = 0, /* 00 0x00 */ diff --git a/include/linux/mpu6000.h b/include/linux/mpu6000.h old mode 100644 new mode 100755 index c02859a8bd49..5a63c8f07b70 --- a/include/linux/mpu6000.h +++ b/include/linux/mpu6000.h @@ -1,7 +1,20 @@ /* $License: Copyright (C) 2010 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 . + $ */ /** @@ -21,122 +34,122 @@ /*==== M_HW REGISTER SET ====*/ enum { - MPUREG_XG_OFFS_TC = 0, - MPUREG_YG_OFFS_TC, - MPUREG_ZG_OFFS_TC, - MPUREG_X_FINE_GAIN, - MPUREG_Y_FINE_GAIN, - MPUREG_Z_FINE_GAIN, - MPUREG_XA_OFFS_H, - MPUREG_XA_OFFS_L_TC, - MPUREG_YA_OFFS_H, - MPUREG_YA_OFFS_L_TC, - MPUREG_ZA_OFFS_H, + MPUREG_XG_OFFS_TC = 0, /* 0x00 */ + MPUREG_YG_OFFS_TC, /* 0x00 */ + MPUREG_ZG_OFFS_TC, /* 0x00 */ + MPUREG_X_FINE_GAIN, /* 0x00 */ + MPUREG_Y_FINE_GAIN, /* 0x00 */ + MPUREG_Z_FINE_GAIN, /* 0x00 */ + MPUREG_XA_OFFS_H, /* 0x00 */ + MPUREG_XA_OFFS_L_TC, /* 0x00 */ + MPUREG_YA_OFFS_H, /* 0x00 */ + MPUREG_YA_OFFS_L_TC, /* 0x00 */ + MPUREG_ZA_OFFS_H, /* 0x00 */ MPUREG_ZA_OFFS_L_TC, /* 0xB */ - MPUREG_0C_RSVD, - MPUREG_0D_RSVD, - MPUREG_0E_RSVD, - MPUREG_0F_RSVD, - MPUREG_10_RSVD, - MPUREG_11_RSVD, - MPUREG_12_RSVD, - MPUREG_XG_OFFS_USRH, - MPUREG_XG_OFFS_USRL, - MPUREG_YG_OFFS_USRH, - MPUREG_YG_OFFS_USRL, - MPUREG_ZG_OFFS_USRH, - MPUREG_ZG_OFFS_USRL, + MPUREG_0C_RSVD, /* 0x00 */ + MPUREG_0D_RSVD, /* 0x00 */ + MPUREG_0E_RSVD, /* 0x00 */ + MPUREG_0F_RSVD, /* 0x00 */ + MPUREG_10_RSVD, /* 0x00 */ + MPUREG_11_RSVD, /* 0x00 */ + MPUREG_12_RSVD, /* 0x00 */ + MPUREG_XG_OFFS_USRH, /* 0x00 */ + MPUREG_XG_OFFS_USRL, /* 0x00 */ + MPUREG_YG_OFFS_USRH, /* 0x00 */ + MPUREG_YG_OFFS_USRL, /* 0x00 */ + MPUREG_ZG_OFFS_USRH, /* 0x00 */ + MPUREG_ZG_OFFS_USRL, /* 0x00 */ MPUREG_SMPLRT_DIV, /* 0x19 */ MPUREG_CONFIG, /* 0x1A ==> DLPF_FS_SYNC */ - MPUREG_GYRO_CONFIG, - MPUREG_ACCEL_CONFIG, - MPUREG_ACCEL_FF_THR, - MPUREG_ACCEL_FF_DUR, - MPUREG_ACCEL_MOT_THR, - MPUREG_ACCEL_MOT_DUR, - MPUREG_ACCEL_ZRMOT_THR, - MPUREG_ACCEL_ZRMOT_DUR, + MPUREG_GYRO_CONFIG, /* 0x00 */ + MPUREG_ACCEL_CONFIG, /* 0x00 */ + MPUREG_ACCEL_FF_THR, /* 0x00 */ + MPUREG_ACCEL_FF_DUR, /* 0x00 */ + MPUREG_ACCEL_MOT_THR, /* 0x00 */ + MPUREG_ACCEL_MOT_DUR, /* 0x00 */ + MPUREG_ACCEL_ZRMOT_THR, /* 0x00 */ + MPUREG_ACCEL_ZRMOT_DUR, /* 0x00 */ MPUREG_FIFO_EN, /* 0x23 */ - MPUREG_I2C_MST_CTRL, + MPUREG_I2C_MST_CTRL, /* 0x00 */ MPUREG_I2C_SLV0_ADDR, /* 0x25 */ - MPUREG_I2C_SLV0_REG, - MPUREG_I2C_SLV0_CTRL, + MPUREG_I2C_SLV0_REG, /* 0x00 */ + MPUREG_I2C_SLV0_CTRL, /* 0x00 */ MPUREG_I2C_SLV1_ADDR, /* 0x28 */ - MPUREG_I2C_SLV1_REG_PASSWORD, - MPUREG_I2C_SLV1_CTRL, + MPUREG_I2C_SLV1_REG_PASSWORD, /* 0x00 */ + MPUREG_I2C_SLV1_CTRL, /* 0x00 */ MPUREG_I2C_SLV2_ADDR, /* 0x2B */ - MPUREG_I2C_SLV2_REG, - MPUREG_I2C_SLV2_CTRL, + MPUREG_I2C_SLV2_REG, /* 0x00 */ + MPUREG_I2C_SLV2_CTRL, /* 0x00 */ MPUREG_I2C_SLV3_ADDR, /* 0x2E */ - MPUREG_I2C_SLV3_REG, - MPUREG_I2C_SLV3_CTRL, + MPUREG_I2C_SLV3_REG, /* 0x00 */ + MPUREG_I2C_SLV3_CTRL, /* 0x00 */ MPUREG_I2C_SLV4_ADDR, /* 0x31 */ - MPUREG_I2C_SLV4_REG, - MPUREG_I2C_SLV4_DO, - MPUREG_I2C_SLV4_CTRL, - MPUREG_I2C_SLV4_DI, + MPUREG_I2C_SLV4_REG, /* 0x00 */ + MPUREG_I2C_SLV4_DO, /* 0x00 */ + MPUREG_I2C_SLV4_CTRL, /* 0x00 */ + MPUREG_I2C_SLV4_DI, /* 0x00 */ MPUREG_I2C_MST_STATUS, /* 0x36 */ MPUREG_INT_PIN_CFG, /* 0x37 ==> -* INT_CFG */ MPUREG_INT_ENABLE, /* 0x38 ==> / */ MPUREG_DMP_INT_STATUS, /* 0x39 */ MPUREG_INT_STATUS, /* 0x3A */ MPUREG_ACCEL_XOUT_H, /* 0x3B */ - MPUREG_ACCEL_XOUT_L, - MPUREG_ACCEL_YOUT_H, - MPUREG_ACCEL_YOUT_L, - MPUREG_ACCEL_ZOUT_H, - MPUREG_ACCEL_ZOUT_L, + MPUREG_ACCEL_XOUT_L, /* 0x00 */ + MPUREG_ACCEL_YOUT_H, /* 0x00 */ + MPUREG_ACCEL_YOUT_L, /* 0x00 */ + MPUREG_ACCEL_ZOUT_H, /* 0x00 */ + MPUREG_ACCEL_ZOUT_L, /* 0x00 */ MPUREG_TEMP_OUT_H, /* 0x41 */ - MPUREG_TEMP_OUT_L, + MPUREG_TEMP_OUT_L, /* 0x00 */ MPUREG_GYRO_XOUT_H, /* 0x43 */ - MPUREG_GYRO_XOUT_L, - MPUREG_GYRO_YOUT_H, - MPUREG_GYRO_YOUT_L, - MPUREG_GYRO_ZOUT_H, - MPUREG_GYRO_ZOUT_L, + MPUREG_GYRO_XOUT_L, /* 0x00 */ + MPUREG_GYRO_YOUT_H, /* 0x00 */ + MPUREG_GYRO_YOUT_L, /* 0x00 */ + MPUREG_GYRO_ZOUT_H, /* 0x00 */ + MPUREG_GYRO_ZOUT_L, /* 0x00 */ MPUREG_EXT_SLV_SENS_DATA_00, /* 0x49 */ - MPUREG_EXT_SLV_SENS_DATA_01, - MPUREG_EXT_SLV_SENS_DATA_02, - MPUREG_EXT_SLV_SENS_DATA_03, - MPUREG_EXT_SLV_SENS_DATA_04, - MPUREG_EXT_SLV_SENS_DATA_05, + MPUREG_EXT_SLV_SENS_DATA_01, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_02, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_03, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_04, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_05, /* 0x00 */ MPUREG_EXT_SLV_SENS_DATA_06, /* 0x4F */ - MPUREG_EXT_SLV_SENS_DATA_07, - MPUREG_EXT_SLV_SENS_DATA_08, - MPUREG_EXT_SLV_SENS_DATA_09, - MPUREG_EXT_SLV_SENS_DATA_10, - MPUREG_EXT_SLV_SENS_DATA_11, + MPUREG_EXT_SLV_SENS_DATA_07, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_08, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_09, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_10, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_11, /* 0x00 */ MPUREG_EXT_SLV_SENS_DATA_12, /* 0x55 */ - MPUREG_EXT_SLV_SENS_DATA_13, - MPUREG_EXT_SLV_SENS_DATA_14, - MPUREG_EXT_SLV_SENS_DATA_15, - MPUREG_EXT_SLV_SENS_DATA_16, - MPUREG_EXT_SLV_SENS_DATA_17, + MPUREG_EXT_SLV_SENS_DATA_13, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_14, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_15, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_16, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_17, /* 0x00 */ MPUREG_EXT_SLV_SENS_DATA_18, /* 0x5B */ - MPUREG_EXT_SLV_SENS_DATA_19, - MPUREG_EXT_SLV_SENS_DATA_20, - MPUREG_EXT_SLV_SENS_DATA_21, - MPUREG_EXT_SLV_SENS_DATA_22, - MPUREG_EXT_SLV_SENS_DATA_23, + MPUREG_EXT_SLV_SENS_DATA_19, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_20, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_21, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_22, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_23, /* 0x00 */ ACCEL_INTEL_STATUS, /* 0x61 */ - MPUREG_62_RSVD, - MPUREG_63_RSVD, - MPUREG_64_RSVD, - MPUREG_65_RSVD, - MPUREG_66_RSVD, - MPUREG_67_RSVD, + MPUREG_62_RSVD, /* 0x00 */ + MPUREG_63_RSVD, /* 0x00 */ + MPUREG_64_RSVD, /* 0x00 */ + MPUREG_65_RSVD, /* 0x00 */ + MPUREG_66_RSVD, /* 0x00 */ + MPUREG_67_RSVD, /* 0x00 */ SIGNAL_PATH_RESET, /* 0x68 */ ACCEL_INTEL_CTRL, /* 0x69 */ MPUREG_USER_CTRL, /* 0x6A */ MPUREG_PWR_MGMT_1, /* 0x6B */ - MPUREG_PWR_MGMT_2, + MPUREG_PWR_MGMT_2, /* 0x00 */ MPUREG_BANK_SEL, /* 0x6D */ MPUREG_MEM_START_ADDR, /* 0x6E */ MPUREG_MEM_R_W, /* 0x6F */ - MPUREG_PRGM_STRT_ADDRH, - MPUREG_PRGM_STRT_ADDRL, + MPUREG_PRGM_STRT_ADDRH, /* 0x00 */ + MPUREG_PRGM_STRT_ADDRL, /* 0x00 */ MPUREG_FIFO_COUNTH, /* 0x72 */ - MPUREG_FIFO_COUNTL, + MPUREG_FIFO_COUNTL, /* 0x00 */ MPUREG_FIFO_R_W, /* 0x74 */ MPUREG_WHOAMI, /* 0x75,117 */ @@ -296,7 +309,12 @@ enum MPU_MEMORY_BANKS { #define BIT_STBY_ZG 0x01 /* although it has 6, this refers to the gyros */ -#define MPU_NUM_AXES (3) +#define MPU_NUM_AXES (3) + +#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 ----*/ -- 2.34.1