Kernel driver mpu ===================== Supported chips: * InvenSense IMU3050 Prefix: 'mpu3050' Datasheet: PS-MPU-3000A-00.2.4b.pdf * InvenSense IMU6000 Prefix: 'mpu6000' Datasheet: MPU-6000A-00 v1.0.pdf Author: InvenSense Description ----------- The mpu is a motion processor unit that controls the mpu3050 gyroscope, a slave accelerometer, a compass and a pressure sensor, or the mpu6000 and slave compass. This document describes how to install the driver into a Linux kernel and a small note about how to set up the file permissions in an android file system. Sysfs entries ------------- /dev/mpu /dev/mpuirq /dev/accelirq /dev/compassirq /dev/pressureirq General Remarks MPU3050 ----------------------- * Valid addresses for the MPU3050 is 0x68. * Accelerometer must be on the secondary I2C bus for MPU3050, the magnetometer must be on the primary bus and pressure sensor must be on the primary bus. General Remarks MPU6000 ----------------------- * Valid addresses for the MPU6000 is 0x68. * Magnetometer must be on the secondary I2C bus for the MPU6000. * Accelerometer slave address must be set to 0x68 * Gyro and Accel orientation matrices should be the same Programming the chip using /dev/mpu ---------------------------------- Programming of MPU3050 or MPU6000 is done by first opening the /dev/mpu file and then performing a series of IOCTLS on the handle returned. The IOCTL codes can be found in mpu.h. Typically this is done by the mllite library in user space. Adding to a Kernel ================== The mpu driver is designed to be inserted in the drivers/misc part of the kernel. Extracting the tarball from the root kernel dir will place the contents of the tarball here: /drivers/misc/inv_mpu /include/linux/mpu.h /include/linux/mpu3050.h /include/linux/mpu6000.h After this is done the drivers/misc/Kconfig must be edited to add the line: source "drivers/misc/inv_mpu/Kconfig" Similarly drivers/misc/Makefile must be edited to add the line: obj-y += inv_mpu/ Configuration can then be done as normal. NOTE: This driver depends on a kernel patch to drivers/char/char.c. This patch started to be included in most 2.6.35 based kernels. drivers: misc: pass miscdevice pointer via file private data https://patchwork.kernel.org/patch/96412/ --- drivers/char/misc.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 92ab03d..cd650ca 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -144,6 +144,7 @@ static int misc_open(struct inode * inode, struct file * file) old_fops = file->f_op; file->f_op = new_fops; if (file->f_op->open) { + file->private_data = c; err=file->f_op->open(inode,file); if (err) { fops_put(file->f_op); --- Board and Platform Data ----------------------- In order for the driver to work, board and platform data specific to the device needs to be added to the board file. A mpu_platform_data structure must be created and populated and set in the i2c_board_info_structure. For details of each structure member see mpu.h. All values below are simply an example and should be modified for your platform. #include #if defined(CONFIG_MPU_SENSORS_MPU3050) static struct mpu_platform_data mpu_data = { .int_config = 0x10, .orientation = { -1, 0, 0, 0, 1, 0, 0, 0, -1 }, /* accel */ .accel = { #ifdef CONFIG_INV_SENSORS_MODULE .get_slave_descr = NULL, #else .get_slave_descr = get_accel_slave_descr, #endif .irq = (IH_GPIO_BASE + 138), .adapt_num = 2, .bus = EXT_SLAVE_BUS_SECONDARY, #ifdef CONFIG_MPU_SENSORS_KXTF9 .address = 0x0F, #elif defined CONFIG_MPU_SENSORS_BMA150 .address = 0x38, #elif defined CONFIG_MPU_SENSORS_LIS331 || defined CONFIG_MPU_SENSORS_LIS303 \ || defined CONFIG_MPU_SENSORS_LIS3DH || defined CONFIG_MPU_SENSORS_KXSD9 .address = 0x18, #elif defined CONFIG_MPU_SENSORS_MMA845X || defined CONFIG_MPU_SENSORS_MMA8450 .address = 0x1C, #elif defined CONFIG_MPU_SENSORS_ADI346 .address = 0x53, #endif .orientation = { -1, 0, 0, 0, 1, 0, 0, 0, -1 }, }, /* compass */ .compass = { #ifdef CONFIG_INV_SENSORS_MODULE .get_slave_descr = NULL, #else .get_slave_descr = get_compass_slave_descr, #endif .irq = (IH_GPIO_BASE + 137), .adapt_num = 2, .bus = EXT_SLAVE_BUS_PRIMARY, #ifdef CONFIG_MPU_SENSORS_AK8975 .address = 0x0E, #elif defined CONFIG_MPU_SENSORS_AMI30x .address = 0x0E, #elif defined CONFIG_MPU_SENSORS_AMI306 .address = 0x0E, #elif defined CONFIG_MPU_SENSORS_YAS529 .address = 0x2E, #elif defined CONFIG_MPU_SENSORS_MMC314X .address = 0x30, #elif defined CONFIG_MPU_SENSORS_HSCDTD00XX .address = 0x0C, #endif .orientation = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }, }, }; #endif #if defined(CONFIG_MPU_SENSORS_MPU6050A2) || \ defined(CONFIG_MPU_SENSORS_MPU6050B1) static struct mpu_platform_data mpu_data = { .int_config = 0x10, .orientation = { -1, 0, 0, 0, 1, 0, 0, 0, -1 }, /* accel */ .accel = { #if defined CONFIG_INV_SENSORS_MODULE .get_slave_descr = NULL, #else .get_slave_descr = get_accel_slave_descr, #endif .irq = (IH_GPIO_BASE + 137), .adapt_num = 2, .bus = EXT_SLAVE_BUS_PRIMARY, .address = 0x68, .orientation = { -1, 0, 0, 0, 1, 0, 0, 0, -1 }, }, /* compass */ .compass = { #if defined CONFIG_INV_SENSORS_MODULE .get_slave_descr = NULL, #else .get_slave_descr = get_compass_slave_descr, #endif .irq = (IH_GPIO_BASE + 138), .adapt_num = 2, .bus = EXT_SLAVE_BUS_SECONDARY, #ifdef CONFIG_MPU_SENSORS_AK8975 .address = 0x0E, #elif defined CONFIG_MPU_SENSORS_AMI30x .address = 0x0E, #elif defined CONFIG_MPU_SENSORS_AMI306 .address = 0x0E, #elif defined CONFIG_MPU_SENSORS_YAS529 .address = 0x2E, #elif defined CONFIG_MPU_SENSORS_MMC314X .address = 0x30, #elif defined CONFIG_MPU_SENSORS_HSCDTD00XX .address = 0x0C, #endif .orientation = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }, }, }; #endif static struct i2c_board_info __initdata beagle_i2c_2_boardinfo[] = { #if defined(CONFIG_MPU_SENSORS_MPU3050) || \ defined(CONFIG_MPU_SENSORS_MPU6050A2) || \ defined(CONFIG_MPU_SENSORS_MPU6050B1) { I2C_BOARD_INFO(MPU_NAME, 0x68), .irq = (IH_GPIO_BASE + MPUIRQ_GPIO), .platform_data = &mpu_data, }, #endif }; Typically the IRQ is a GPIO input pin and needs to be configured properly. If in the above example GPIO 168 corresponds to IRQ 299, the following should be done as well: #define MPU_GPIO_IRQ 168 gpio_request(MPU_GPIO_IRQ,"MPUIRQ"); gpio_direction_input(MPU_GPIO_IRQ) 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 ======================== To set up the file permissions on an android system, the /dev/mpu and /dev/mpuirq files needs to be added to the system/core/init/devices.c file inside the perms_ structure. static struct perms_ devperms[] = { { "/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