Index: linux-2.6.35/drivers/misc/mpu3050/mlsl.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.35/drivers/misc/mpu3050/mlsl.h 2010-12-22
14:09:28.000000000 +0800
@@ -0,0 +1,103 @@
+/*
+ $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
<http://www.gnu.org/licenses/>.
+ $
+ */
+
+#ifndef __MSSL_H__
+#define __MSSL_H__
+
+#include "mltypes.h"
+#include "mpu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ------------ */
+/* - Defines. - */
+/* ------------ */
+
+/*
+ * NOTE : to properly support Yamaha compass reads,
+ * the max transfer size should be at least 9 B.
+ * Length in bytes, typically a power of 2 >= 2
+ */
+#define SERIAL_MAX_TRANSFER_SIZE 30
+
+/* ---------------------- */
+/* - Types definitions. - */
+/* ---------------------- */
+
+/* --------------------- */
+/* - Function p-types. - */
+/* --------------------- */
+
+ tMLError MLSLSerialOpen(char const *port,
+ void **sl_handle);
+ tMLError MLSLSerialReset(void *sl_handle);
+ tMLError MLSLSerialClose(void *sl_handle);
+
+ tMLError MLSLSerialWriteSingle(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned char registerAddr,
+ unsigned char data);
+
+ tMLError MLSLSerialRead(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned char registerAddr,
+ unsigned short length,
+ unsigned char *data);
+
+ tMLError MLSLSerialWrite(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short length,
+ unsigned char const *data);
+
+ tMLError MLSLSerialReadMem(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short memAddr,
+ unsigned short length,
+ unsigned char *data);
+
+ tMLError MLSLSerialWriteMem(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short memAddr,
+ unsigned short length,
+ unsigned char const *data);
+
+ tMLError MLSLSerialReadFifo(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short length,
+ unsigned char *data);
+
+ tMLError MLSLSerialWriteFifo(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short length,
+ unsigned char const *data);
+
+ tMLError MLSLWriteCal(unsigned char *cal, unsigned int len);
+ tMLError MLSLReadCal(unsigned char *cal, unsigned int len);
+ tMLError MLSLGetCalLength(unsigned int *len);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+#endif /* MLSL_H */
Index: linux-2.6.35/drivers/misc/mpu3050/mpu-i2c.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.35/drivers/misc/mpu3050/mpu-i2c.c 2010-12-22
14:09:28.000000000 +0800
@@ -0,0 +1,204 @@
+/*
+ $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
<http://www.gnu.org/licenses/>.
+ $
+ */
+
+/**
+ * @defgroup
+ * @brief
+ *
+ * @{
+ * @file mpu-i2c.c
+ * @brief
+ *
+ */
+
+#include <mlos.h>
+
+#include <linux/i2c.h>
+#include "mpu.h"
+
+int sensor_i2c_write(struct i2c_adapter *i2c_adap,
+ unsigned char address,
+ unsigned int len, unsigned char const *data)
+{
+ struct i2c_msg msgs[1];
+ int res;
+
+ if (NULL == data || NULL == i2c_adap)
+ return -EINVAL;
+
+ msgs[0].addr = address;
+ msgs[0].flags = 0; /* write */
+ msgs[0].buf = (unsigned char *) data;
+ msgs[0].len = len;
+
+ res = i2c_transfer(i2c_adap, msgs, 1);
+ if (res < 1)
+ return res;
+ else
+ return 0;
+}
+
+int sensor_i2c_write_register(struct i2c_adapter *i2c_adap,
+ unsigned char address,
+ unsigned char reg, unsigned char value)
+{
+ unsigned char data[2];
+
+ data[0] = reg;
+ 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,
+ unsigned int len, unsigned char *data)
+{
+ struct i2c_msg msgs[2];
+ int res;
+
+ if (NULL == data || NULL == i2c_adap)
+ return -EINVAL;
+
+ msgs[0].addr = address;
+ msgs[0].flags = 0; /* write */
+ msgs[0].buf = ®
+ msgs[0].len = 1;
+
+ msgs[1].addr = address;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].buf = data;
+ msgs[1].len = len;
+
+ res = i2c_transfer(i2c_adap, msgs, 2);
+ if (res < 2)
+ return res;
+ else
+ return 0;
+}
+
+int mpu_memory_read(struct i2c_adapter *i2c_adap,
+ unsigned char mpu_addr,
+ unsigned short mem_addr,
+ unsigned int len, unsigned char *data)
+{
+ unsigned char bank[2];
+ unsigned char addr[2];
+ unsigned char buf;
+
+ struct i2c_msg msgs[1];
+ int ret;
+
+ if (NULL == data || NULL == i2c_adap)
+ return -EINVAL;
+
+ bank[0] = MPUREG_BANK_SEL;
+ bank[1] = mem_addr >> 8;
+
+ addr[0] = MPUREG_MEM_START_ADDR;
+ addr[1] = mem_addr & 0xFF;
+
+ buf = MPUREG_MEM_R_W;
+
+ /* Write Message */
+ msgs[0].addr = mpu_addr;
+ msgs[0].flags = 0;
+ msgs[0].buf = bank;
+ msgs[0].len = sizeof(bank);
+ ret = i2c_transfer(i2c_adap, msgs, 1);
+
+ msgs[0].addr = mpu_addr;
+ msgs[0].flags = 0;
+ msgs[0].buf = addr;
+ msgs[0].len = sizeof(addr);
+ ret = i2c_transfer(i2c_adap, msgs, 1);
+
+ msgs[0].addr = mpu_addr;
+ msgs[0].flags = 0;
+ msgs[0].buf = &buf;
+ msgs[0].len = 1;
+ ret = i2c_transfer(i2c_adap, msgs, 1);
+
+ msgs[0].addr = mpu_addr;
+ msgs[0].flags = I2C_M_RD;
+ msgs[0].buf = data;
+ msgs[0].len = len;
+
+ ret = i2c_transfer(i2c_adap, msgs, 1);
+ if (ret != 1)
+ return ret;
+ else
+ return 0;
+}
+
+int mpu_memory_write(struct i2c_adapter *i2c_adap,
+ unsigned char mpu_addr,
+ unsigned short mem_addr,
+ unsigned int len, unsigned char const *data)
+{
+ unsigned char bank[2];
+ unsigned char addr[2];
+ unsigned char buf[513];
+
+ struct i2c_msg msgs[1];
+ int ret;
+
+ if (NULL == data || NULL == i2c_adap)
+ return -EINVAL;
+ if (len >= (sizeof(buf) - 1))
+ return -ENOMEM;
+
+ bank[0] = MPUREG_BANK_SEL;
+ bank[1] = mem_addr >> 8;
+
+ addr[0] = MPUREG_MEM_START_ADDR;
+ addr[1] = mem_addr & 0xFF;
+
+ buf[0] = MPUREG_MEM_R_W;
+
+ memcpy(buf + 1, data, len);
+
+ /* Write Message */
+ msgs[0].addr = mpu_addr;
+ msgs[0].flags = 0;
+ msgs[0].buf = bank;
+ msgs[0].len = sizeof(bank);
+ ret = i2c_transfer(i2c_adap, msgs, 1);
+
+ msgs[0].addr = mpu_addr;
+ msgs[0].flags = 0;
+ msgs[0].buf = addr;
+ msgs[0].len = sizeof(addr);
+ ret = i2c_transfer(i2c_adap, msgs, 1);
+
+ msgs[0].addr = mpu_addr;
+ msgs[0].flags = 0;
+ msgs[0].buf = (unsigned char *) buf;
+ msgs[0].len = len + 1;
+
+ ret = i2c_transfer(i2c_adap, msgs, 1);
+ if (ret != 1)
+ return ret;
+ else
+ return 0;
+}
+
+/**
+ * @}
+ */
Index: linux-2.6.35/drivers/misc/mpu3050/mldl_cfg.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.35/drivers/misc/mpu3050/mldl_cfg.h 2010-12-22
14:09:28.000000000 +0800
@@ -0,0 +1,105 @@
+/*
+ $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
<http://www.gnu.org/licenses/>.
+ $
+ */
+
+/**
+ * @addtogroup MLDL
+ *
+ * @{
+ * @file mldl_cfg.h
+ * @brief The Motion Library Driver Layer Configuration header
file.
+ */
+
+#ifndef __MLDL_CFG_H__
+#define __MLDL_CFG_H__
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#include "mlsl.h"
+#include "mpu.h"
+
+/* --------------------- */
+/* - Defines. - */
+/* --------------------- */
+
+#define SAMPLING_PERIOD(mldl_cfg) \
+ (((((mldl_cfg->lpf) == 0) || ((mldl_cfg->lpf) == 7))
\
+ ? (8000)
\
+ : (1000))
\
+ / (mldl_cfg->divider + 1))
+
+/* --------------------- */
+/* - Variables. - */
+/* --------------------- */
+
+/* Platform data for the MPU */
+struct mldl_cfg {
+ /* MPU related configuration */
+ unsigned char addr;
+ unsigned char int_config;
+ unsigned char ext_sync;
+ unsigned char full_scale;
+ unsigned char lpf;
+ unsigned char clk_src;
+ unsigned char divider;
+ unsigned char dmp_enable;
+ unsigned char fifo_enable;
+ unsigned char dmp_cfg1;
+ unsigned char dmp_cfg2;
+ unsigned char gyro_power;
+ unsigned char offset_tc[MPU_NUM_AXES];
+ unsigned char ram[MPU_MEM_NUM_RAM_BANKS][MPU_MEM_BANK_SIZE];
+
+ /* MPU Related stored status and info */
+ unsigned char silicon_revision;
+ unsigned char product_id;
+ unsigned short trim;
+
+ /* Driver/Kernel related state information */
+ int is_suspended;
+
+ /* Slave related information */
+ struct ext_slave_descr *accel;
+ struct ext_slave_descr *compass;
+
+ struct mpu3050_platform_data *pdata;
+};
+
+
+int mpu3050_open(struct mldl_cfg *mldl_cfg, void *mlsl_handle);
+int mpu3050_resume(struct mldl_cfg *mldl_cfg, void *mlsl_handle,
+ void *accel_handle,
+ void *compass_handle,
+ bool resume_accel, bool resume_compass);
+int mpu3050_suspend(struct mldl_cfg *mldl_cfg, void *mlsl_handle,
+ void *accel_handle,
+ void *compass_handle,
+ bool suspend_accel, bool suspend_compass);
+int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, void *mlsl_handle,
+ unsigned char *data);
+int mpu3050_read_compass(struct mldl_cfg *mldl_cfg, void *mlsl_handle,
+ unsigned char *data);
+
+
+#endif /* __MLDL_CFG_H__ */
+
+/**
+ *...@}
+ */
Index: linux-2.6.35/drivers/misc/mpu3050/mpuirq.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.35/drivers/misc/mpu3050/mpuirq.c 2010-12-23
11:16:17.000000000 +0800
@@ -0,0 +1,465 @@
+/*
+ $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
<http://www.gnu.org/licenses/>.
+ $
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/irq.h>
+#include <linux/signal.h>
+#include <linux/miscdevice.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/input.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include "mpu.h"
+#include "mpuirq.h"
+#include "mldl_cfg.h"
+#include "mlsl.h"
+#include "mpu-i2c.h"
+#include "accel/bma023.h"
+
+#define MPUIRQ_NAME "mpuirq"
+
+/* function which gets accel data and sends it to MPU */
+
+DECLARE_WAIT_QUEUE_HEAD(mpuirq_wait);
+DECLARE_WAIT_QUEUE_HEAD(accelirq_wait);
+
+static DEFINE_SPINLOCK(accel_lock);
+
+struct mpuirq_dev_data {
+ struct work_struct work;
+ struct i2c_client *mpu_client;
+ struct miscdevice *dev;
+ int irq;
+ int pid;
+ int accel_divider;
+ int data_ready;
+ int timeout;
+};
+
+struct accelirq_dev_data {
+ struct work_struct work;
+ struct i2c_client *mpu_client;
+ struct input_dev *accel_input;
+ int irq;
+ int data_ready;
+ int timeout;
+ int freq;
+};
+
+static struct mpuirq_dev_data mpuirq_dev_data;
+static struct accelirq_dev_data accelirq_dev_data;
+static struct mpuirq_data mpuirq_data;
+static char *interface = MPUIRQ_NAME;
+
+static void mpu_accel_data_work_fcn(struct work_struct *work);
+static void accel_data_work_fcn(struct work_struct *work);
+
+static int accel_input_open(struct input_dev *input){
+ struct mldl_cfg *mldl_cfg = (struct mldl_cfg *)
i2c_get_clientdata(accelirq_dev_data.mpu_client);
+ struct accel_config *aconfig = accel_get_config();
+ aconfig->enable_count_hg_lg = 0x02;
+ mpu3050_suspend(mldl_cfg, accelirq_dev_data.mpu_client->adapter,
+
i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num),
+
i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num),
+ 1, 1);
+ mldl_cfg->accel->resume(accelirq_dev_data.mpu_client->adapter,
+ mldl_cfg->accel,
+
&mldl_cfg->pdata->accel);
+ aconfig->enable_count_hg_lg = 0x00;
+ return 0;
+}
+
+static void accel_input_close(struct input_dev *input){
+ struct mldl_cfg *mldl_cfg = (struct mldl_cfg *)
i2c_get_clientdata(accelirq_dev_data.mpu_client);
+ mpu3050_suspend(mldl_cfg, accelirq_dev_data.mpu_client->adapter,
+
i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num),
+
i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num),
+ 1, 0);
+}
+
+static int accel_input_init(void){
+ int res = 0;
+ accelirq_dev_data.accel_input = input_allocate_device();
+ if(!accelirq_dev_data.accel_input){
+ res = -ENOMEM;
+ printk(KERN_ERR "%s: accel input device memory alloc
failed\n",__func__);
+ goto error;
+ }
+ set_bit(EV_ABS, accelirq_dev_data.accel_input->evbit);
+ accelirq_dev_data.accel_input->name = "bma023_accel";
+ accelirq_dev_data.accel_input->id.bustype = BUS_I2C;
+ accelirq_dev_data.accel_input->id.product = 0x69;
+ accelirq_dev_data.accel_input->open = accel_input_open;
+ accelirq_dev_data.accel_input->close = accel_input_close;
+// accelirq_dev_data.accel_input->phys = "accel/input0";
+ input_set_abs_params(accelirq_dev_data.accel_input, ABS_X, -255,
255, 0, 0);
+ input_set_abs_params(accelirq_dev_data.accel_input, ABS_Y, -255,
255, 0, 0);
+ input_set_abs_params(accelirq_dev_data.accel_input, ABS_Z, -255,
255, 0, 0);
+
+ res = input_register_device(accelirq_dev_data.accel_input);
+ if(res){
+ printk(KERN_ERR "%s: accel input device register
failed\n",__func__);
+ goto reg_fail;
+ }
+ return res;
+reg_fail:
+ input_unregister_device(accelirq_dev_data.accel_input);
+error:
+ return res;
+}
+
+
+static int mpuirq_open(struct inode *inode, struct file *file)
+{
+ dev_dbg(mpuirq_dev_data.dev->this_device,
+ "%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;
+}
+
+/* close function - called when the "file" /dev/mpuirq is closed in
userspace */
+static int mpuirq_release(struct inode *inode, struct file *file)
+{
+ dev_dbg(mpuirq_dev_data.dev->this_device, "mpuirq_release\n");
+ return 0;
+}
+
+/* read function called when from /dev/mpuirq is read */
+static ssize_t mpuirq_read(struct file *file,
+ char *buf, size_t count, loff_t * ppos)
+{
+ int len, err;
+ struct mpuirq_dev_data *p_mpuirq_dev_data = file->private_data;
+
+ if (!mpuirq_dev_data.data_ready) {
+ wait_event_interruptible_timeout(mpuirq_wait,
+ mpuirq_dev_data.
+ data_ready,
+
mpuirq_dev_data.timeout);
+ }
+
+ if (mpuirq_dev_data.data_ready && NULL != buf
+ && count >= sizeof(mpuirq_data)) {
+ err = copy_to_user(buf, &mpuirq_data,
sizeof(mpuirq_data));
+ } else {
+ return 0;
+ }
+ if (err != 0) {
+ dev_err(p_mpuirq_dev_data->dev->this_device,
+ "Copy to user returned %d\n", err);
+ return -EFAULT;
+ }
+ mpuirq_dev_data.data_ready = 0;
+ len = sizeof(mpuirq_data);
+ return len;
+}
+
+unsigned int mpuirq_poll(struct file *file, struct poll_table_struct
*poll)
+{
+ int mask = 0;
+ struct mpuirq_dev_data *p_mpuirq_dev_data = file->private_data;
+
+ poll_wait(file, &mpuirq_wait, poll);
+ if (mpuirq_dev_data.data_ready)
+ mask |= POLLIN | POLLRDNORM;
+ dev_dbg(p_mpuirq_dev_data->dev->this_device,
+ "%s: returning %d\n", __func__, mask);
+ return mask;
+}
+
+/* ioctl - I/O control */
+static long mpuirq_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ int data;
+
+ switch (cmd) {
+ case MPUIRQ_SET_TIMEOUT:
+ mpuirq_dev_data.timeout = arg;
+ break;
+
+ case MPUIRQ_GET_INTERRUPT_CNT:
+ data = mpuirq_data.interruptcount - 1;
+ if (mpuirq_data.interruptcount > 1)
+ mpuirq_data.interruptcount = 1;
+
+ if (copy_to_user((int *) arg, &data, sizeof(int)))
+ return -EFAULT;
+ break;
+ case MPUIRQ_GET_IRQ_TIME:
+ if (copy_to_user((int *) arg, &mpuirq_data.irqtime,
+ sizeof(mpuirq_data.irqtime)))
+ return -EFAULT;
+ mpuirq_data.irqtime = 0;
+ break;
+ case MPUIRQ_SET_FREQUENCY_DIVIDER:
+ mpuirq_dev_data.accel_divider = arg;
+ break;
+ default:
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+static void accel_data_work_fcn(struct work_struct *work){
+ signed short axis_data[3];
+ struct accelirq_dev_data *irq_dev_data =
+ (struct accelirq_dev_data *) work;
+ struct mldl_cfg *mldl_cfg = (struct mldl_cfg *)
+ i2c_get_clientdata(irq_dev_data->mpu_client);
+ struct i2c_adapter *accel_adapter;
+ accel_adapter =
i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+ if(bma023_read_accel_xyz(accel_adapter, mldl_cfg, axis_data) <
0){
+ printk("accel work: read xyz of accel failed\n");
+ return;
+ }
+ input_event(irq_dev_data->accel_input, EV_ABS, ABS_X,
axis_data[0]);
+ input_event(irq_dev_data->accel_input, EV_ABS, ABS_Y,
axis_data[1]);
+ input_event(irq_dev_data->accel_input, EV_ABS, ABS_Z,
axis_data[2]);
+ input_sync(irq_dev_data->accel_input);
+}
+static void mpu_accel_data_work_fcn(struct work_struct *work)
+{
+ struct mpuirq_dev_data *mpuirq_dev_data =
+ (struct mpuirq_dev_data *) work;
+ struct mldl_cfg *mldl_cfg =
+ (struct mldl_cfg *)
+ i2c_get_clientdata(mpuirq_dev_data->mpu_client);
+ struct i2c_adapter *accel_adapter;
+ unsigned char wbuff[16];
+ unsigned char rbuff[16];
+ int ii;
+
+ accel_adapter =
i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+ mldl_cfg->accel->read(accel_adapter,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel, rbuff);
+
+
+ /* @todo add other data formats here as well */
+ if (EXT_SLAVE_BIG_ENDIAN == mldl_cfg->accel->endian) {
+ for (ii = 0; ii < 3; ii++) {
+ wbuff[2 * ii + 1] = rbuff[2 * ii + 1];
+ wbuff[2 * ii + 2] = rbuff[2 * ii + 0];
+ }
+ } else {
+ memcpy(wbuff + 1, rbuff, mldl_cfg->accel->len);
+ }
+
+ wbuff[7] = 0;
+ wbuff[8] = 1; /*set semaphore */
+
+ mpu_memory_write(mpuirq_dev_data->mpu_client->adapter,
+ mldl_cfg->addr, 0x0108, 8, wbuff);
+}
+
+static irqreturn_t accelirq_handler(int irq, void *dev_id)
+{
+ static int accel_count;
+ static unsigned long flags;
+ accel_count++;
+ if(!(accelirq_dev_data.freq > 0))
+ return -1;
+ spin_lock_irqsave(&accel_lock, flags);
+ if(accel_count % accelirq_dev_data.freq == 0){
+ accel_count &= 0;
+ schedule_work((struct work_struct *)
(&accelirq_dev_data));
+ }
+ spin_unlock_irqrestore(&accel_lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mpuirq_handler(int irq, void *dev_id)
+{
+ static int mycount;
+ struct timeval irqtime;
+ mycount++;
+
+ mpuirq_data.interruptcount++;
+
+ /* 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));
+ }
+
+ wake_up_interruptible(&mpuirq_wait);
+ }
+
+ return IRQ_HANDLED;
+
+}
+
+/* define which file operations are supported */
+const struct file_operations mpuirq_fops = {
+ .owner = THIS_MODULE,
+ .read = mpuirq_read,
+ .poll = mpuirq_poll,
+
+#if HAVE_COMPAT_IOCTL
+ .compat_ioctl = mpuirq_ioctl,
+#endif
+#if HAVE_UNLOCKED_IOCTL
+ .unlocked_ioctl = mpuirq_ioctl,
+#endif
+ .open = mpuirq_open,
+ .release = mpuirq_release,
+};
+
+static struct miscdevice mpuirq_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = MPUIRQ_NAME,
+ .fops = &mpuirq_fops,
+};
+
+int mpuirq_init(struct i2c_client *mpu_client)
+{
+ int res;
+ struct mldl_cfg *mldl_cfg =
+ (struct mldl_cfg *) i2c_get_clientdata(mpu_client);
+
+ /* work_struct initialization */
+ INIT_WORK((struct work_struct *) &mpuirq_dev_data,
+ mpu_accel_data_work_fcn);
+ INIT_WORK((struct work_struct *) &accelirq_dev_data,
+ accel_data_work_fcn);
+
+ mpuirq_dev_data.mpu_client = mpu_client;
+ accelirq_dev_data.mpu_client = mpu_client;
+
+ dev_info(&mpu_client->adapter->dev,
+ "Module Param interface = %s\n", interface);
+
+ accelirq_dev_data.irq = 299;
+ accelirq_dev_data.data_ready = 0;
+ accelirq_dev_data.timeout = 0;
+ accelirq_dev_data.freq = 1;
+
+ if(mldl_cfg->accel){
+ if (accelirq_dev_data.irq) {
+ res = request_irq(accelirq_dev_data.irq,
+
accelirq_handler,
+
(IRQF_TRIGGER_RISING),
+ "accel_irq", &accelirq_dev_data.irq);
+ if (res) {
+ dev_err(&mpu_client->adapter->dev,
+ "accel: cannot register
IRQ %d\n", accelirq_dev_data.irq);
+ } else {
+ res = accel_input_init();
+ if(res)
+
dev_err(&mpu_client->adapter->dev,
+
"accel_input_register returned %d\n", res);
+ }
+ } else {
+ printk(KERN_ERR "accel irq: cannot regist irq
%d\n", accelirq_dev_data.irq);
+ res = 0;
+ }
+ } else {
+ printk(KERN_ERR "accel irq: No Accel\n");
+ res = 0;
+ }
+
+ mpuirq_dev_data.irq = mpu_client->irq;
+ mpuirq_dev_data.pid = 0;
+ mpuirq_dev_data.accel_divider = -1;
+ mpuirq_dev_data.data_ready = 0;
+ mpuirq_dev_data.timeout = 0;
+ mpuirq_dev_data.dev = &mpuirq_device;
+
+ if (mpuirq_dev_data.irq) {
+ unsigned long flags;
+ if (BIT_ACTL_LOW ==
+ ((mldl_cfg->pdata->int_config) & BIT_ACTL))
+ flags = IRQF_TRIGGER_FALLING;
+ else
+ flags = IRQF_TRIGGER_RISING;
+
+ res =
+ request_irq(mpuirq_dev_data.irq, mpuirq_handler,
flags,
+ interface, &mpuirq_dev_data.irq);
+ if (res) {
+ dev_err(&mpu_client->adapter->dev,
+ "myirqtest: cannot register IRQ %d\n",
+ mpuirq_dev_data.irq);
+ } else {
+ res = misc_register(&mpuirq_device);
+ if (res < 0) {
+ dev_err(&mpu_client->adapter->dev,
+ "misc_register returned %d\n",
+ res);
+ free_irq(mpuirq_dev_data.irq,
+ &mpuirq_dev_data.irq);
+ }
+ }
+ } else {
+ res = 0;
+ }
+ return res;
+}
+
+void mpuirq_exit(void)
+{
+ /* Free the IRQ first before flushing the work */
+ if (mpuirq_dev_data.irq > 0)
+ free_irq(mpuirq_dev_data.irq, &mpuirq_dev_data.irq);
+
+ if (accelirq_dev_data.irq > 0)
+ free_irq(accelirq_dev_data.irq, &accelirq_dev_data.irq);
+
+ flush_scheduled_work();
+ input_unregister_device(accelirq_dev_data.accel_input);
+
+ dev_info(mpuirq_device.this_device, "Unregistering %s\n",
+ MPUIRQ_NAME);
+ misc_deregister(&mpuirq_device);
+
+ return;
+}
+
+module_param(interface, charp, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(interface, "The Interface name");
_______________________________________________
MeeGo-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel