diff options
author | Robert Collins <rcollins@nvidia.com> | 2011-04-20 13:23:12 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:46:34 -0800 |
commit | e5512fc51e5ff029b68b1749a7434c9536430a33 (patch) | |
tree | ea59755ce8d4716fcd57cb3623fc2dbfe9d6b89c | |
parent | 7c794b5c6d257ac62694e02860abb80613f66d1a (diff) |
mpu3050: Motion Libraries: Update MPU kernel to v3.3.4.
Update 1 of 3: MPU kernel files. Depends on board file and
defconfig file.
BUG 808052
Original-Change-Id: I42b08570d3a8dac090860276e04f6d2ab7545461
Reviewed-on: http://git-master/r/29724
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Reviewed-by: Robert R Collins <rcollins@nvidia.com>
Tested-by: Robert R Collins <rcollins@nvidia.com>
Rebase-Id: R13b53bb717968041f18f76031f32377fabdf8c43
-rw-r--r-- | drivers/misc/mpu3050/Makefile | 12 | ||||
-rw-r--r-- | drivers/misc/mpu3050/compass/ak8975.c | 74 | ||||
-rw-r--r-- | drivers/misc/mpu3050/log.h | 116 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mldl_cfg.c | 41 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mldl_cfg.h | 1 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mlsl-kernel.c | 10 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mltypes.h | 4 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mpu-dev.c | 626 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mpuirq.c | 7 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mpuirq.h | 14 | ||||
-rw-r--r-- | drivers/misc/mpu3050/slaveirq.c | 11 | ||||
-rw-r--r-- | drivers/misc/mpu3050/slaveirq.h | 9 | ||||
-rw-r--r-- | drivers/misc/mpu3050/timerirq.c | 14 | ||||
-rw-r--r-- | drivers/misc/mpu3050/timerirq.h | 10 | ||||
-rw-r--r-- | include/linux/mpu.h | 131 |
15 files changed, 610 insertions, 470 deletions
diff --git a/drivers/misc/mpu3050/Makefile b/drivers/misc/mpu3050/Makefile index c7e1b863e588..89ac46fdac5b 100644 --- a/drivers/misc/mpu3050/Makefile +++ b/drivers/misc/mpu3050/Makefile @@ -67,6 +67,10 @@ 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 @@ -83,6 +87,10 @@ 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 @@ -122,7 +130,3 @@ endif obj-$(CONFIG_MPU_SENSORS_TIMERIRQ)+= timerirq.o -ifdef CONFIG_MPU_SENSORS_DEBUG -EXTRA_CFLAGS += -DDEBUG -endif - diff --git a/drivers/misc/mpu3050/compass/ak8975.c b/drivers/misc/mpu3050/compass/ak8975.c index 991de77dbd01..b8aed30ba39b 100644 --- a/drivers/misc/mpu3050/compass/ak8975.c +++ b/drivers/misc/mpu3050/compass/ak8975.c @@ -160,14 +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, - /*.get_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/log.h b/drivers/misc/mpu3050/log.h index ceee28526265..f2f9ea7ece8e 100644 --- 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 index 66f447e7ba85..9cc4cf690386 100644 --- a/drivers/misc/mpu3050/mldl_cfg.c +++ b/drivers/misc/mpu3050/mldl_cfg.c @@ -297,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; @@ -306,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; @@ -330,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 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. + * @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. * - * @param[in] enable - * 1 to enable, 0 to disable + * @pre Must be called after MLSerialOpen(). + * @note Typically called before MLDmpOpen(). * - * @return ML_SUCCESS if successfull, a non-zero error code otherwise. -**/ + * @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. + */ static int MLDLSetLevelShifterBit(struct mldl_cfg *pdata, void *mlsl_handle, unsigned char enable) @@ -358,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; @@ -1123,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; diff --git a/drivers/misc/mpu3050/mldl_cfg.h b/drivers/misc/mpu3050/mldl_cfg.h index ee3a1e3dd05f..ad6a211c5d86 100644 --- a/drivers/misc/mpu3050/mldl_cfg.h +++ b/drivers/misc/mpu3050/mldl_cfg.h @@ -93,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; diff --git a/drivers/misc/mpu3050/mlsl-kernel.c b/drivers/misc/mpu3050/mlsl-kernel.c index 908b16f16b24..cb1605131cbf 100644 --- a/drivers/misc/mpu3050/mlsl-kernel.c +++ b/drivers/misc/mpu3050/mlsl-kernel.c @@ -96,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; @@ -187,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/mltypes.h b/drivers/misc/mpu3050/mltypes.h index 5c1b684e5b50..d0b27fa89e78 100644 --- a/drivers/misc/mpu3050/mltypes.h +++ b/drivers/misc/mpu3050/mltypes.h @@ -136,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; } diff --git a/drivers/misc/mpu3050/mpu-dev.c b/drivers/misc/mpu3050/mpu-dev.c index 115639f84704..e7ddd1cb45ac 100644 --- a/drivers/misc/mpu3050/mpu-dev.c +++ b/drivers/misc/mpu3050/mpu-dev.c @@ -1,9 +1,10 @@ /* - mpu-dev.c - mpu3050 char device interface + mpu-dev.c - mpu3050 char device interface 2 $License: Copyright (C) 1995-97 Simon G. Vogl Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl> Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. This program is free software; you can redistribute it and/or modify @@ -18,8 +19,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -/* Code inside mpudev_ioctl_rdrw is copied from i2c-dev.c */ #include <linux/i2c.h> #include <linux/i2c-dev.h> @@ -36,7 +35,9 @@ #include <linux/slab.h> #include <linux/version.h> #include <linux/pm.h> - +#include <linux/mutex.h> +#include <linux/suspend.h> +#include <linux/poll.h> #ifdef CONFIG_HAS_EARLYSUSPEND #include <linux/earlysuspend.h> #endif @@ -65,28 +66,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; - 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; @@ -96,7 +166,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; } @@ -113,130 +183,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_data rdwr_arg; - struct i2c_msg *rdwr_pa; - u8 __user **data_ptrs; - int i, res; - - if (copy_from_user(&rdwr_arg, - (struct i2c_rdwr_ioctl_data __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; + if (!mpu->event && (!(file->f_flags & O_NONBLOCK))) + wait_event_interruptible(mpu->mpu_event_wait, mpu->event); - rdwr_pa = (struct i2c_msg *) - kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); - if (!rdwr_pa) - return -ENOMEM; + if (!mpu->event || NULL == buf + || count < sizeof(mpu->mpu_pm_event) + sizeof(unsigned long)) + return 0; - if (copy_from_user(rdwr_pa, rdwr_arg.msgs, - rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { - kfree(rdwr_pa); + 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; } - data_ptrs = - kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); - if (data_ptrs == NULL) { - kfree(rdwr_pa); - return -ENOMEM; - } - - 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; - } - } - if (res < 0) { - int j; - for (j = 0; j < i; ++j) - kfree(rdwr_pa[j].buf); - kfree(data_ptrs); - kfree(rdwr_pa); - 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, rdwr_pa, 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); - 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; - if (ret) - ret = -EFAULT; - } - kfree(tmp); - return ret; + poll_wait(file, &mpu->mpu_event_wait, poll); + if (mpu->event) + mask |= POLLIN | POLLRDNORM; + return mask; } static int @@ -466,40 +486,36 @@ out: 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; - if ((slave) && (slave->config)) { - struct ext_slave_config config; - 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; + 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; } - retval = slave->config(adapter, - slave, - &mldl_cfg->pdata->accel, - &config); - kfree(config.data); + config.data = data; } + retval = slave->config(adapter, slave, pdata, &config); + kfree(config.data); return retval; } @@ -516,49 +532,111 @@ static int slave_config(void *adapter, 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; - if ((slave) && (slave->get_config)) { - struct ext_slave_config config; - void *user_data; - 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, - &mldl_cfg->pdata->accel, - &config); + 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) { - kfree(config.data); + retval = -EFAULT; + kfree(data); return retval; } - retval = copy_to_user((unsigned char __user *) user_data, - config.data, - config.len); + 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; } @@ -582,160 +660,67 @@ 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)); - if (retval) - retval = -EFAULT; - - break; - case MPU_SET_RAM: - retval = copy_from_user(mldl_cfg->ram, - (unsigned char __user *) arg, - sizeof(mldl_cfg->ram)); - if (retval) - retval = -EFAULT; - 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)); - if (retval) - retval = -EFAULT; - break; - case MPU_GET_RAM: - retval = copy_to_user((unsigned char __user *) arg, - mldl_cfg->ram, - sizeof(mldl_cfg->ram)); - if (retval) - retval = -EFAULT; + 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: retval = slave_config(accel_adapter, mldl_cfg, mldl_cfg->accel, + &mldl_cfg->pdata->accel, (struct ext_slave_config __user *) arg); break; case MPU_CONFIG_COMPASS: retval = slave_config(compass_adapter, mldl_cfg, mldl_cfg->compass, + &mldl_cfg->pdata->compass, (struct ext_slave_config __user *) arg); break; case MPU_CONFIG_PRESSURE: retval = slave_config(pressure_adapter, mldl_cfg, mldl_cfg->pressure, + &mldl_cfg->pdata->pressure, (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_SUSPEND: @@ -772,6 +757,11 @@ static long mpu_ioctl(struct file *file, sensors & ML_THREE_AXIS_PRESSURE); } break; + 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]; @@ -812,15 +802,14 @@ static long mpu_ioctl(struct file *file, retval = -EFAULT; } break; - case MPU_READ_MEMORY: - case MPU_WRITE_MEMORY: 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; } @@ -844,10 +833,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) @@ -868,8 +860,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, @@ -879,8 +872,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); @@ -902,9 +896,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__); } @@ -923,7 +919,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); @@ -936,6 +933,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; } @@ -954,7 +952,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, @@ -965,8 +964,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; } @@ -974,6 +974,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 @@ -1007,7 +1009,7 @@ int mpu3050_probe(struct i2c_client *client, struct i2c_adapter *accel_adapter = NULL; struct i2c_adapter *compass_adapter = NULL; struct i2c_adapter *pressure_adapter = NULL; - + printk("Ameer's changes...\n"); dev_dbg(&client->adapter->dev, "%s\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { @@ -1024,10 +1026,25 @@ 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; @@ -1056,7 +1073,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 { @@ -1143,8 +1160,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); } @@ -1264,17 +1281,16 @@ static struct i2c_driver mpu3050_driver = { static int __init mpu_init(void) { int res = i2c_add_driver(&mpu3050_driver); - pid = 0; - printk(KERN_DEBUG "%s\n", __func__); + pr_debug("%s\n", __func__); if (res) - dev_err(&this_client->adapter->dev, "%s failed\n", + 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/mpuirq.c b/drivers/misc/mpu3050/mpuirq.c index 691e5bc5b052..ce1ad409cbf4 100644 --- a/drivers/misc/mpu3050/mpuirq.c +++ b/drivers/misc/mpu3050/mpuirq.c @@ -72,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; } @@ -92,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, diff --git a/drivers/misc/mpu3050/mpuirq.h b/drivers/misc/mpu3050/mpuirq.h index 70a2d35679f0..a71c79c75e8c 100644 --- a/drivers/misc/mpu3050/mpuirq.h +++ b/drivers/misc/mpu3050/mpuirq.h @@ -22,15 +22,15 @@ #ifdef __KERNEL__ #include <linux/i2c-dev.h> +#include <linux/time.h> +#else +#include <sys/time.h> #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 index 2ee53851e125..a3c7bfec4b4b 100644 --- a/drivers/misc/mpu3050/slaveirq.c +++ b/drivers/misc/mpu3050/slaveirq.c @@ -89,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); @@ -112,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 = @@ -168,7 +171,6 @@ 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 */ data->data_ready = 1; do_gettimeofday(&irqtime); @@ -223,6 +225,8 @@ int slaveirq_init(struct i2c_adapter *slave_adapter, data->data_ready = 0; data->timeout = 0; + init_waitqueue_head(&data->slaveirq_wait); + res = request_irq(data->irq, slaveirq_handler, IRQF_TRIGGER_RISING, data->dev.name, data); @@ -241,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 index ca9c7e496dab..b4e1115f1b0a 100644 --- a/drivers/misc/mpu3050/slaveirq.h +++ b/drivers/misc/mpu3050/slaveirq.h @@ -27,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 index 94dd095306a5..41c3ac981016 100644 --- a/drivers/misc/mpu3050/timerirq.c +++ b/drivers/misc/mpu3050/timerirq.c @@ -63,9 +63,6 @@ static void timerirq_handler(unsigned long arg) struct timerirq_data *data = (struct timerirq_data *)arg; struct timeval irqtime; - /* dev_info(data->dev->this_device, - "%s, %ld\n", __func__, (unsigned long)data); */ - data->data.interruptcount++; data->data_ready = 1; @@ -75,6 +72,10 @@ static void timerirq_handler(unsigned long arg) 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) @@ -159,7 +160,9 @@ static ssize_t timerirq_read(struct file *file, int len, err; struct timerirq_data *data = file->private_data; - if (!data->data_ready) { + if (!data->data_ready && + data->timeout && + !(file->f_flags & O_NONBLOCK)) { wait_event_interruptible_timeout(data->timerirq_wait, data->data_ready, data->timeout); @@ -182,7 +185,8 @@ static ssize_t timerirq_read(struct file *file, return len; } -unsigned int timerirq_poll(struct file *file, struct poll_table_struct *poll) +static unsigned int timerirq_poll(struct file *file, + struct poll_table_struct *poll) { int mask = 0; struct timerirq_data *data = file->private_data; diff --git a/drivers/misc/mpu3050/timerirq.h b/drivers/misc/mpu3050/timerirq.h index a38b4907a4d4..ec2c1e29f080 100644 --- a/drivers/misc/mpu3050/timerirq.h +++ b/drivers/misc/mpu3050/timerirq.h @@ -20,9 +20,11 @@ #ifndef __TIMERIRQ__ #define __TIMERIRQ__ -#define TIMERIRQ_SET_TIMEOUT (5) -#define TIMERIRQ_GET_INTERRUPT_CNT (7) -#define TIMERIRQ_START (8) -#define TIMERIRQ_STOP (9) +#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 index 15b5fef07c9a..d66d9e76b9af 100644 --- a/include/linux/mpu.h +++ b/include/linux/mpu.h @@ -22,6 +22,9 @@ #ifdef __KERNEL__ #include <linux/types.h> +#include <linux/ioctl.h> +#elif defined LINUX +#include <sys/ioctl.h> #endif #ifdef M_HW @@ -35,72 +38,67 @@ #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_GET_CONFIG_ACCEL (0x28) -#define MPU_GET_CONFIG_COMPASS (0x29) -#define MPU_GET_CONFIG_PRESSURE (0x2a) +#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; }; +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; @@ -108,6 +106,7 @@ struct mpuirq_data { int data_size; void *data; }; + enum ext_slave_config_key { MPU_SLAVE_CONFIG_ODR_SUSPEND, MPU_SLAVE_CONFIG_ODR_RESUME, @@ -119,6 +118,8 @@ enum ext_slave_config_key { 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, }; @@ -157,6 +158,7 @@ enum ext_slave_id { ACCEL_ID_LIS331, ACCEL_ID_LSM303, + ACCEL_ID_LIS3DH, ACCEL_ID_KXSD9, ACCEL_ID_KXTF9, ACCEL_ID_BMA150, @@ -165,11 +167,12 @@ enum ext_slave_id { ACCEL_ID_MMA8450, ACCEL_ID_MMA845X, ACCEL_ID_MPU6000, - ACCEL_ID_LIS3DH, COMPASS_ID_AKM, COMPASS_ID_AMI30X, + COMPASS_ID_AMI306, COMPASS_ID_YAS529, + COMPASS_ID_YAS530, COMPASS_ID_HMC5883, COMPASS_ID_LSM303, COMPASS_ID_MMC314X, @@ -397,12 +400,18 @@ struct ext_slave_descr *ak8975_get_slave_descr(void); #define get_compass_slave_descr ak8975_get_slave_descr #endif -#ifdef CONFIG_MPU_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_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 @@ -427,6 +436,12 @@ struct ext_slave_descr *yas529_get_slave_descr(void); #define get_compass_slave_descr yas529_get_slave_descr #endif +#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 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 |