aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/mediatek/sensorHub
diff options
context:
space:
mode:
authorMeizu OpenSource <patchwork@meizu.com>2016-08-15 10:19:42 +0800
committerMeizu OpenSource <patchwork@meizu.com>2016-08-15 10:19:42 +0800
commitd2e1446d81725c351dc73a03b397ce043fb18452 (patch)
tree4dbc616b7f92aea39cd697a9084205ddb805e344 /drivers/misc/mediatek/sensorHub
first commit
Diffstat (limited to 'drivers/misc/mediatek/sensorHub')
-rw-r--r--drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuBus.c827
-rw-r--r--drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor.c2027
-rw-r--r--drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor.h457
-rw-r--r--drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor_factory.c474
-rwxr-xr-xdrivers/misc/mediatek/sensorHub/CwMcuSensor/Makefile9
-rwxr-xr-xdrivers/misc/mediatek/sensorHub/Makefile14
-rwxr-xr-xdrivers/misc/mediatek/sensorHub/SCP_sensorHub/Makefile4
-rw-r--r--drivers/misc/mediatek/sensorHub/SCP_sensorHub/SCP_sensorHub.c2569
-rwxr-xr-xdrivers/misc/mediatek/sensorHub/SCP_shf/Makefile3
-rw-r--r--drivers/misc/mediatek/sensorHub/SCP_shf/shf_kernel.c405
-rw-r--r--drivers/misc/mediatek/sensorHub/SCP_shf/shf_kernel.h33
-rw-r--r--drivers/misc/mediatek/sensorHub/inc/SCP_sensorHub.h185
-rw-r--r--drivers/misc/mediatek/sensorHub/inc/cust_sensorHub.h11
13 files changed, 7018 insertions, 0 deletions
diff --git a/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuBus.c b/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuBus.c
new file mode 100644
index 000000000..81237489a
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuBus.c
@@ -0,0 +1,827 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/string.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+#include <mach/mt_gpio.h>
+#include <cust_gpio_usage.h>
+#include <cust_eint.h>
+#include <mach/eint.h>
+#include <cust_cwmcu.h>
+#include <mach/mt_pm_ldo.h>
+#include <linux/spi/spi.h>
+#include <mach/mt_spi.h>
+#include <mach/mt_sleep.h>
+#include "CwMcuSensor.h"
+
+
+extern struct CWMCU_data *sensor;
+static DEFINE_MUTEX(cwmcu_bus_lock);
+
+
+#ifdef CWMCU_I2C_INTERFACE
+static u8 *CWI2CDMABuf_va = NULL;
+static u64 CWI2CDMABuf_pa = NULL;
+static struct i2c_board_info __initdata i2c_cw_boardinfo = { I2C_BOARD_INFO("CwMcuSensor", (0x3a))};
+
+static s32 i2c_dma_read(struct i2c_client *client, u8 addr, u8 *rxbuf, s32 len)
+{
+ int ret;
+ s32 retry = 0;
+ u8 buffer[2];
+
+ struct i2c_msg msg[2] =
+ {
+ {
+ .addr = (client->addr & I2C_MASK_FLAG),
+ .flags = 0,//(client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG),
+ .buf = buffer,
+ .len = 1,
+ .timing = I2C_MASTER_CLOCK
+ },
+ {
+ .addr = (client->addr & I2C_MASK_FLAG),
+ .ext_flag = (client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG),
+ .flags = I2C_M_RD,
+ .buf = CWI2CDMABuf_pa,
+ .len = len,
+ .timing = I2C_MASTER_CLOCK
+ },
+ };
+
+ buffer[0] = addr;
+
+ if (rxbuf == NULL)
+ return -1;
+
+ //GTP_DEBUG("dma i2c read: 0x%04X, %d bytes(s)", addr, len);
+ for (retry = 0; retry < 10; ++retry)
+ {
+ ret = i2c_transfer(client->adapter, &msg[0], 2);
+ if (ret < 0)
+ {
+ CW_ERROR("I2C DMA read error retry=%d", retry);
+ continue;
+ }
+ memcpy(rxbuf, CWI2CDMABuf_va, len);
+ return 0;
+ }
+ CW_ERROR("Dma I2C Read Error: 0x%04X, %d byte(s), err-code: %d", addr, len, ret);
+ return ret;
+}
+
+
+static s32 i2c_dma_write(struct i2c_client *client, u8 addr, u8 *txbuf, s32 len)
+{
+ int ret;
+ s32 retry = 0;
+ u8 *wr_buf = CWI2CDMABuf_va;
+ //CW_DEBUG("fwq3,.....%x",txbuf[0]);
+ struct i2c_msg msg =
+ {
+ .addr = (client->addr & I2C_MASK_FLAG),
+ .ext_flag = (client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG),
+ .flags = 0,
+ .buf = CWI2CDMABuf_pa,
+ .len = 1+len,
+ .timing = I2C_MASTER_CLOCK
+ };
+
+ wr_buf[0] = addr;
+
+ if (txbuf == NULL)
+ return -1;
+
+ //GTP_DEBUG("dma i2c write: 0x%04X, %d bytes(s)", addr, len);
+ memcpy(wr_buf+1, txbuf, len+1);
+ //for(retry=0;retry<len+1;retry++)
+ //{
+ // CW_DEBUG("fwq4,.....wr_buf[%d]=%x",retry,wr_buf[retry]);
+ //}
+ for (retry = 0; retry < 5; ++retry)
+ {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0)
+ {
+ CW_ERROR("I2C DMA write error retry=%d", retry);
+ continue;
+ }
+ return 0;
+ }
+ CW_ERROR("Dma I2C Write Error: 0x%04X, %d byte(s), err-code: %d", addr, len, ret);
+ return ret;
+}
+
+static s32 i2c_dma_read_serial(struct i2c_client *client, u8 *rxbuf, s32 len)
+{
+ int ret;
+ s32 retry = 0;
+ u8 buffer[2];
+
+ struct i2c_msg msg[2] =
+ {
+ {
+ .addr = (client->addr & I2C_MASK_FLAG),
+ .ext_flag = (client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG),
+ .flags = I2C_M_RD,
+ .buf = CWI2CDMABuf_pa,
+ .len = len,
+ .timing = I2C_MASTER_CLOCK
+ },
+ };
+
+ if (rxbuf == NULL)
+ return -1;
+
+ //GTP_DEBUG("dma i2c read: 0x%04X, %d bytes(s)", addr, len);
+ for (retry = 0; retry < 5; ++retry)
+ {
+ ret = i2c_transfer(client->adapter, &msg[0], 1);
+ if (ret < 0)
+ {
+ CW_ERROR("I2C DMA read error retry=%d", retry);
+ continue;
+ }
+ memcpy(rxbuf, CWI2CDMABuf_va, len);
+ return 0;
+ }
+ CW_ERROR("Dma I2C Read Error: %d byte(s), err-code: %d", len, ret);
+ return ret;
+}
+
+static s32 i2c_dma_write_serial(struct i2c_client *client, u8 *txbuf, s32 len)
+{
+ int ret;
+ s32 retry = 0;
+ u8 *wr_buf = CWI2CDMABuf_va;
+
+ struct i2c_msg msg =
+ {
+ .addr = (client->addr & I2C_MASK_FLAG),
+ .ext_flag = (client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG),
+ .flags = 0,
+ .buf = CWI2CDMABuf_pa,
+ .len = len,
+ .timing = I2C_MASTER_CLOCK
+ };
+
+ if (txbuf == NULL)
+ return -1;
+
+ //GTP_DEBUG("dma i2c write: 0x%04X, %d bytes(s)", addr, len);
+ memcpy(wr_buf, txbuf, len);
+ for (retry = 0; retry < 10; ++retry)
+ {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0)
+ {
+ CW_ERROR("I2C DMA write error retry=%d", retry);
+ continue;
+ }
+ return 0;
+ }
+ CW_ERROR("Dma I2C Write Error: %d byte(s), err-code: %d",len, ret);
+ return ret;
+}
+
+static s32 i2c_read_bytes_dma(struct i2c_client *client, u8 addr, u8 *rxbuf, s32 len)
+{
+ s32 left = len;
+ s32 read_len = 0;
+ u8 *rd_buf = rxbuf;
+ s32 ret = 0;
+
+ //GTP_DEBUG("Read bytes dma: 0x%04X, %d byte(s)", addr, len);
+ while (left > 0)
+ {
+ if (left > GTP_DMA_MAX_TRANSACTION_LENGTH)
+ {
+ read_len = GTP_DMA_MAX_TRANSACTION_LENGTH;
+ }
+ else
+ {
+ read_len = left;
+ }
+ ret = i2c_dma_read(client, addr, rd_buf, read_len);
+ if (ret < 0)
+ {
+ CW_ERROR("dma read failed");
+ return -1;
+ }
+
+ left -= read_len;
+ addr += read_len;
+ rd_buf += read_len;
+ }
+ return 0;
+}
+
+static s32 i2c_write_bytes_dma(struct i2c_client *client, u8 addr, u8 *txbuf, s32 len)
+{
+
+ s32 ret = 0;
+ s32 write_len = 0;
+ s32 left = len;
+ u8 *wr_buf = txbuf;
+ //CW_DEBUG("fwq2...%x",txbuf[0]);
+ //GTP_DEBUG("Write bytes dma: 0x%04X, %d byte(s)", addr, len);
+ while (left > 0)
+ {
+ if (left > GTP_DMA_MAX_I2C_TRANSFER_SIZE)
+ {
+ write_len = GTP_DMA_MAX_I2C_TRANSFER_SIZE;
+ }
+ else
+ {
+ write_len = left;
+ }
+ ret = i2c_dma_write(client, addr, wr_buf, write_len);
+
+ if (ret < 0)
+ {
+ CW_ERROR("dma i2c write failed!");
+ return -1;
+ }
+
+ left -= write_len;
+ addr += write_len;
+ wr_buf += write_len;
+ }
+ return 0;
+}
+
+static s32 i2c_write_bytes_dma_serial(struct i2c_client *client,u8 *txbuf, s32 len)
+{
+
+ s32 ret = 0;
+ s32 write_len = 0;
+ s32 left = len;
+ u8 *wr_buf = txbuf;
+
+ //GTP_DEBUG("Write bytes dma: 0x%04X, %d byte(s)", addr, len);
+ while (left > 0)
+ {
+ if (left > GTP_DMA_MAX_I2C_TRANSFER_SIZE)
+ {
+ write_len = GTP_DMA_MAX_I2C_TRANSFER_SIZE;
+ }
+ else
+ {
+ write_len = left;
+ }
+ ret = i2c_dma_write_serial(client, wr_buf, write_len);
+
+ if (ret < 0)
+ {
+ CW_ERROR("dma i2c write failed!");
+ return -1;
+ }
+
+ left -= write_len;
+ wr_buf += write_len;
+ }
+ return 0;
+}
+
+static s32 i2c_read_bytes_dma_serial(struct i2c_client *client, u8 *rxbuf, s32 len)
+{
+ s32 left = len;
+ s32 read_len = 0;
+ u8 *rd_buf = rxbuf;
+ s32 ret = 0;
+
+ //GTP_DEBUG("Read bytes dma: 0x%04X, %d byte(s)", addr, len);
+ while (left > 0)
+ {
+ if (left > GTP_DMA_MAX_TRANSACTION_LENGTH)
+ {
+ read_len = GTP_DMA_MAX_TRANSACTION_LENGTH;
+ }
+ else
+ {
+ read_len = left;
+ }
+ ret = i2c_dma_read_serial(client, rd_buf, read_len);
+ if (ret < 0)
+ {
+ CW_ERROR("dma read serial failed");
+ return -1;
+ }
+
+ left -= read_len;
+
+ rd_buf += read_len;
+ }
+ return 0;
+}
+
+void i2c_init(void *client)
+{
+ CWI2CDMABuf_va = (u8 *)dma_alloc_coherent(NULL, GTP_DMA_MAX_TRANSACTION_LENGTH, &CWI2CDMABuf_pa, GFP_KERNEL);
+ if(!CWI2CDMABuf_va)
+ {
+ CW_INFO("[sensorHUB] dma_alloc_coherent error");
+ }
+
+ sensor->client = (struct i2c_client *)client;
+ i2c_set_clientdata(sensor->client, sensor);
+}
+
+static int CWMCU_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ CW_ERROR("i2c_check_functionality error");
+ return -EIO;
+ }
+
+ CWMCU_probe(client);
+ pm_runtime_enable(&client->dev);
+
+ return 0;
+}
+
+static int CWMCU_i2c_remove(struct i2c_client *client)
+{
+ struct CWMCU_data *sensor = i2c_get_clientdata(client);
+ kfree(sensor);
+
+ return 0;
+}
+
+static int CWMCU_i2c_suspend(struct device *dev)
+{
+ CWMCU_suspend(&sensor->client->dev);
+
+}
+
+static int CWMCU_i2c_resume(struct device *dev)
+{
+ CWMCU_resume(&sensor->client->dev);
+}
+
+static const struct dev_pm_ops CWMCU_pm_ops = {
+ .suspend = CWMCU_i2c_suspend,
+ .resume = CWMCU_i2c_resume
+};
+
+static const struct i2c_device_id CWMCU_id[] = {
+ { CWMCU_NAME, 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, CWMCU_id);
+
+static struct i2c_driver CWMCU_i2c_driver = {
+ .driver = {
+ .name = CWMCU_NAME,
+ .owner = THIS_MODULE,
+ /*.pm = &CWMCU_pm_ops,*/
+ },
+ .probe = CWMCU_i2c_probe,
+ .remove = CWMCU_i2c_remove,
+ .id_table = CWMCU_id,
+};
+
+#elif defined(CWMCU_SPI_INTERFACE)
+#define CWMCU_SPI_OLD_PROTOCOL
+
+unsigned char* cwmcu_spi_src_buffer_all = NULL;
+static struct mt_chip_conf spi_conf;
+
+static int spi_xfer(unsigned char *txbuf,unsigned char *rxbuf, int len)
+{
+ struct spi_transfer transfer_1[2];
+ int const pkt_count = len / CWMCU_SPI_INTERFACE_MAX_PKT_LENGTH_PER_TIMES;
+ int const remainder = len % CWMCU_SPI_INTERFACE_MAX_PKT_LENGTH_PER_TIMES;
+ struct spi_message msg;
+ spi_message_init(&msg);
+
+ //CW_INFO(" len=%d, txbuf=0x%x, rxbuf=0x%x", len, txbuf, rxbuf);
+ if(len>CWMCU_SPI_INTERFACE_MAX_PKT_LENGTH_PER_TIMES){
+ transfer_1[0].tx_buf =(txbuf==NULL)?NULL: txbuf;
+ transfer_1[0].rx_buf =(rxbuf==NULL)?NULL: rxbuf;
+ transfer_1[0].len = CWMCU_SPI_INTERFACE_MAX_PKT_LENGTH_PER_TIMES * pkt_count;
+ spi_message_add_tail(&transfer_1[0], &msg);
+
+ if(0 != remainder) {
+ transfer_1[1].tx_buf =(txbuf==NULL)?NULL:txbuf+ (CWMCU_SPI_INTERFACE_MAX_PKT_LENGTH_PER_TIMES * pkt_count);
+ transfer_1[1].rx_buf =(rxbuf==NULL)?NULL:rxbuf+ (CWMCU_SPI_INTERFACE_MAX_PKT_LENGTH_PER_TIMES * pkt_count);
+ transfer_1[1].len = remainder;
+ spi_message_add_tail(&transfer_1[1], &msg);
+ }
+ }
+ else{
+ transfer_1[0].tx_buf =(txbuf==NULL)?NULL: txbuf;
+ transfer_1[0].rx_buf =(rxbuf==NULL)?NULL: rxbuf;
+ transfer_1[0].len = len;
+ spi_message_add_tail(&transfer_1[0], &msg);
+ }
+ if(spi_sync(sensor->spi, &msg))
+ return -1;
+ else
+ return 0;
+}
+
+static int spi_write_bytes_serial(unsigned char *buffer, int len)
+{
+ int ret = 0;
+ unsigned char* tx_buf=NULL, *rx_buf=NULL;
+
+ if(len > CWMCU_SPI_INTERFACE_MAX_PKT_LENGTH_PER_TIMES){
+ tx_buf = buffer;
+ rx_buf =NULL;
+ }
+ else{
+ if(cwmcu_spi_src_buffer_all==NULL)
+ return -1;
+ if(buffer != cwmcu_spi_src_buffer_all)
+ memcpy(cwmcu_spi_src_buffer_all,buffer,len);
+ tx_buf = cwmcu_spi_src_buffer_all;
+ rx_buf =NULL;
+ }
+ ret = spi_xfer(tx_buf,rx_buf, len);
+
+ return ret;
+}
+
+static int spi_read_bytes_serial(unsigned char *buffer, int len)
+{
+ int ret = 0;
+ unsigned char *tx_buf=NULL, *rx_buf=NULL;
+
+ if(len>CWMCU_SPI_INTERFACE_MAX_PKT_LENGTH_PER_TIMES){
+ tx_buf = NULL;
+ rx_buf = buffer;
+ ret = spi_xfer(tx_buf,rx_buf, len);
+ }
+ else{
+ if(cwmcu_spi_src_buffer_all == NULL)
+ return -1;
+ tx_buf = NULL;
+ rx_buf = cwmcu_spi_src_buffer_all;
+ ret = spi_xfer(tx_buf,rx_buf, len);
+ if(ret == 0)
+ memcpy(buffer,cwmcu_spi_src_buffer_all,len);
+ }
+ return ret;
+}
+
+static int spi_read_bytes(u8 reg_addr, u8 *buffer, u8 len)
+{
+ int ret = 0;
+
+ //CW_DEBUG("[SPI]R_Reg:0x%x, len=%d", reg_addr, len);
+ if(cwmcu_spi_src_buffer_all == NULL)
+ return -1;
+#ifdef CWMCU_SPI_OLD_PROTOCOL
+ cwmcu_spi_src_buffer_all[0]= reg_addr;
+
+ ret = spi_xfer(cwmcu_spi_src_buffer_all, NULL, 1);
+ if (ret < 0)
+ {
+ CW_ERROR("spi_read_bytes: write failed");
+ return ret;
+ }
+ ret = spi_read_bytes_serial(buffer, len);
+ if (ret < 0)
+ {
+ CW_ERROR("spi_read_bytes: read failed");
+ return ret;
+ }
+#else //New Protocol
+ cwmcu_spi_src_buffer_all[0]= 0x0;
+ cwmcu_spi_src_buffer_all[1]= 0xA1;
+ cwmcu_spi_src_buffer_all[2]= reg_addr;
+
+ ret = spi_xfer(cwmcu_spi_src_buffer_all, NULL, 15);
+ if (ret < 0)
+ {
+ CW_ERROR("spi_read_bytes: write failed");
+ return ret;
+ }
+
+ ret = spi_read_bytes_serial(cwmcu_spi_src_buffer_all, 15);
+ if (ret < 0)
+ {
+ CW_ERROR("spi_read_bytes: read failed");
+ return ret;
+ }
+ memcpy(buffer, &cwmcu_spi_src_buffer_all[3], len);
+#endif
+ return ret;
+}
+
+static int spi_write_bytes(u8 reg_addr, u8 *buffer, u8 len)
+{
+ int ret = 0;
+ if(cwmcu_spi_src_buffer_all == NULL)
+ return -1;
+
+ //CW_DEBUG("[SPI]W_Reg:0x%x, len=%d", reg_addr, len);
+#if 0
+ cwmcu_spi_src_buffer_all[0] = reg_addr;
+ memcpy(&cwmcu_spi_src_buffer_all[1], buffer, len);
+
+ ret = spi_write_bytes_serial(cwmcu_spi_src_buffer_all, len+1);
+ if (ret < 0)
+ {
+ CW_ERROR("spi_write_bytes: write failed");
+ return ret;
+ }:
+#elif defined(CWMCU_SPI_OLD_PROTOCOL)
+ cwmcu_spi_src_buffer_all[0] = reg_addr;
+ ret = spi_xfer(cwmcu_spi_src_buffer_all, NULL, 1);
+ if (ret < 0)
+ {
+ CW_ERROR("spi_write_bytes 1st: write failed");
+ return ret;
+ }
+ memcpy(&cwmcu_spi_src_buffer_all[0], buffer, len);
+ ret = spi_write_bytes_serial(cwmcu_spi_src_buffer_all, len);
+ if (ret < 0)
+ {
+ CW_ERROR("spi_write_bytes 2nd: write failed");
+ return ret;
+ }
+#else //New protocol
+ cwmcu_spi_src_buffer_all[0] = 0x0;
+ cwmcu_spi_src_buffer_all[1] = 0xA0;
+ cwmcu_spi_src_buffer_all[2] = reg_addr;
+ memcpy(&cwmcu_spi_src_buffer_all[3], buffer, len);
+ ret = spi_write_bytes_serial(cwmcu_spi_src_buffer_all, 15);
+ if (ret < 0)
+ {
+ CW_ERROR("spi_write_bytes: write failed");
+ return ret;
+ }
+
+#endif
+}
+
+int spi_rw_bytes_serial(u8 *wbuf, u8 *rbuf, u8 len)
+{
+ int ret;
+ unsigned char *tx_buf=NULL, *rx_buf=NULL;
+
+ tx_buf = wbuf;
+ rx_buf = cwmcu_spi_src_buffer_all;
+
+ ret = spi_xfer(tx_buf, rx_buf, len);
+ if(ret == 0)
+ memcpy(rbuf,cwmcu_spi_src_buffer_all, len);
+ else if (ret < 0)
+ {
+ CW_ERROR("spi_rw_bytes: read failed");
+ }
+
+ return ret;
+}
+
+void spi_io_enable(int enable)
+{
+#if 1
+ if (enable){
+ mt_set_gpio_mode(GPIO_SPI_CS_PIN, GPIO_SPI_CS_PIN_M_SPI_CS);
+ mt_set_gpio_mode(GPIO_SPI_SCK_PIN, GPIO_SPI_SCK_PIN_M_SPI_SCK);
+ mt_set_gpio_mode(GPIO_SPI_MISO_PIN, GPIO_SPI_MISO_PIN_M_SPI_MISO);
+ mt_set_gpio_mode(GPIO_SPI_MOSI_PIN, GPIO_SPI_MOSI_PIN_M_SPI_MOSI);
+ }
+ else{
+ //set dir pull to save power
+ mt_set_gpio_mode(GPIO_SPI_CS_PIN, GPIO_SPI_CS_PIN_M_GPIO);
+ mt_set_gpio_dir(GPIO_SPI_CS_PIN, GPIO_DIR_IN);
+ mt_set_gpio_pull_enable(GPIO_SPI_CS_PIN, GPIO_PULL_DISABLE);
+
+ mt_set_gpio_mode(GPIO_SPI_SCK_PIN, GPIO_SPI_SCK_PIN_M_GPIO);
+ mt_set_gpio_dir(GPIO_SPI_SCK_PIN, GPIO_DIR_IN);
+ mt_set_gpio_pull_enable(GPIO_SPI_SCK_PIN, GPIO_PULL_DISABLE);
+
+ mt_set_gpio_mode(GPIO_SPI_MISO_PIN, GPIO_SPI_MISO_PIN_M_GPIO);
+ mt_set_gpio_dir(GPIO_SPI_MISO_PIN, GPIO_DIR_IN);
+ mt_set_gpio_pull_enable(GPIO_SPI_MISO_PIN, GPIO_PULL_DISABLE);
+
+ mt_set_gpio_mode(GPIO_SPI_MOSI_PIN, GPIO_SPI_MOSI_PIN_M_GPIO);
+ mt_set_gpio_dir(GPIO_SPI_MOSI_PIN, GPIO_DIR_IN);
+ mt_set_gpio_pull_enable(GPIO_SPI_MOSI_PIN, GPIO_PULL_DISABLE);
+ }
+
+#endif
+}
+void spi_init(void *dev)
+{
+ struct mt_chip_conf* spi_par;
+
+ sensor->spi = dev;
+
+ spi_io_enable(1);
+
+ cwmcu_spi_src_buffer_all = kmalloc(CWMCU_SPI_INTERFACE_MAX_PKT_LENGTH_PER_TIMES,GFP_KERNEL);
+ if(cwmcu_spi_src_buffer_all== NULL){
+ CW_ERROR("error kmalloc fail cwmcu_spi_src_buffer_all");
+ }
+ //INNODev->spi->controller_data =(void*)&spi_conf;
+ spi_par =&spi_conf;
+ if(!spi_par){
+ CW_ERROR("spi config fail");
+ }
+
+ spi_par->setuptime = 15;
+ spi_par->holdtime = 15;
+ spi_par->high_time = 10; //10--6m 15--4m 20--3m 30--2m [ 60--1m 120--0.5m 300--0.2m]
+ spi_par->low_time = 10;
+ spi_par->cs_idletime = 20;
+
+ spi_par->rx_mlsb = 1;
+ spi_par->tx_mlsb = 1;
+ spi_par->tx_endian = 0;
+ spi_par->rx_endian = 0;
+
+ spi_par->cpol = 0;
+ spi_par->cpha = 0;
+ spi_par->com_mod = DMA_TRANSFER;
+
+ spi_par->pause = 0;
+ spi_par->finish_intr = 1;
+ spi_par->deassert = 0;
+
+ if(spi_setup(sensor->spi)){
+ CW_ERROR("spi_setup fail");
+ }
+
+ //TODO
+ //SPI DMA SETTING
+}
+
+int CWMCU_spi_probe(struct spi_device *spi)
+{
+ CW_INFO("CWMCU_spi_probe entry");
+
+ CWMCU_probe(spi);
+
+ pm_runtime_enable(&spi->dev);
+}
+
+int CWMCU_spi_remove(struct spi_device *spi)
+{
+ sensor->spi = NULL;
+
+ return 0;
+}
+
+int CWMCU_spi_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+ CWMCU_suspend(&spi->dev);
+ spi_io_enable(0);
+ return 0;
+}
+
+int CWMCU_spi_resume(struct spi_device *spi)
+{
+ spi_io_enable(1);
+ CWMCU_resume(&spi->dev);
+}
+
+static struct spi_board_info spi_cw_boardinfo __initdata = {
+ .modalias = CWMCU_NAME,
+ .bus_num = 0,
+ .chip_select=0,
+ .mode = SPI_MODE_3,
+};
+
+static struct spi_driver CWMCU_spi_driver = {
+ .driver = {
+ .name = CWMCU_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = CWMCU_spi_probe,
+ .remove = CWMCU_spi_remove,
+ .suspend = CWMCU_spi_suspend,
+ .resume = CWMCU_spi_resume,
+};
+
+
+#endif //bus type
+/*======================================================== */
+void CWMCU_bus_init(void *bus_dev)
+{
+#if defined(CWMCU_I2C_INTERFACE)
+ i2c_init(bus_dev);
+#elif defined(CWMCU_SPI_INTERFACE)
+ spi_init(bus_dev);
+#endif
+}
+
+int CWMCU_bus_register(void)
+{
+#if defined(CWMCU_I2C_INTERFACE)
+ i2c_register_board_info(CWMCU_I2C_NUMBER, &i2c_cw_boardinfo, 1);
+ return i2c_add_driver(&CWMCU_i2c_driver);
+#elif defined(CWMCU_SPI_INTERFACE)
+ spi_register_board_info(&spi_cw_boardinfo, 1);
+ return spi_register_driver(&CWMCU_spi_driver);
+#endif
+}
+
+void CWMCU_bus_unregister(void)
+{
+#if defined(CWMCU_I2C_INTERFACE)
+ i2c_del_driver(&CWMCU_i2c_driver);
+#elif defined(CWMCU_SPI_INTERFACE)
+
+#endif
+}
+
+int CWMCU_bus_write(struct CWMCU_data *sensor, u8 reg_addr, u8 *data, u8 len)
+{
+ int ret;
+
+ mutex_lock(&cwmcu_bus_lock);
+#if defined(CWMCU_I2C_INTERFACE)
+ ret = i2c_write_bytes_dma(sensor->client, reg_addr, data,len);
+#elif defined(CWMCU_SPI_INTERFACE)
+ ret = spi_write_bytes(reg_addr, data, len);
+#endif
+ mutex_unlock(&cwmcu_bus_lock);
+
+ return ret;
+}
+
+/* Returns the number of read bytes on success */
+int CWMCU_bus_read(struct CWMCU_data *sensor, u8 reg_addr, u8 *data, u8 len)
+{
+ int ret = 0;
+ mutex_lock(&cwmcu_bus_lock);
+
+#if defined(CWMCU_I2C_INTERFACE)
+ ret = i2c_read_bytes_dma(sensor->client, reg_addr, data, len);
+#elif defined(CWMCU_SPI_INTERFACE)
+ ret = spi_read_bytes(reg_addr, data, len);
+#endif
+ mutex_unlock(&cwmcu_bus_lock);
+
+ return ret;
+}
+
+int CWMCU_bus_write_serial(u8 *data, int len)
+{
+ int ret = 0;
+
+ mutex_lock(&cwmcu_bus_lock);
+#if defined(CWMCU_I2C_INTERFACE)
+ ret = i2c_write_bytes_dma_serial(sensor->client, data, len);
+
+ if (ret < 0) {
+ CW_ERROR("i2c write error =%d", ret);
+ goto BUS_WS_EXIT;
+ }
+#elif defined(CWMCU_SPI_INTERFACE)
+ ret = spi_write_bytes_serial(data, len);
+
+ if (ret < 0) {
+ CW_ERROR("spi write error =%d", ret);
+ goto BUS_WS_EXIT;
+ }
+#endif
+ mutex_unlock(&cwmcu_bus_lock);
+
+BUS_WS_EXIT:
+ return ret;
+}
+
+int CWMCU_bus_read_serial(u8 *data, int len)
+{
+ int ret = 0;
+
+ mutex_lock(&cwmcu_bus_lock);
+#if defined(CWMCU_I2C_INTERFACE)
+ ret = i2c_read_bytes_dma_serial(sensor->client, data, len);
+
+ if (ret < 0) {
+ CW_ERROR("i2c read error =%d", ret);
+ goto BUS_RS_EXIT;
+ }
+#elif defined(CWMCU_SPI_INTERFACE)
+ ret = spi_read_bytes_serial(data, len);
+
+ if (ret < 0) {
+ CW_ERROR("spi read error =%d", ret);
+ goto BUS_RS_EXIT;
+ }
+#endif
+ mutex_unlock(&cwmcu_bus_lock);
+
+BUS_RS_EXIT:
+ return ret;
+}
+
+
+
+
diff --git a/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor.c b/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor.c
new file mode 100644
index 000000000..9d99c46a8
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor.c
@@ -0,0 +1,2027 @@
+/*
+ * Verifiy on sensorhub F/W 102(SPI), 018(I2C)
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/string.h>
+#include <linux/dma-mapping.h>
+#include <linux/earlysuspend.h>
+#include "CwMcuSensor.h"
+#include <linux/gpio.h>
+#include <mach/mt_gpio.h>
+#include <cust_gpio_usage.h>
+#include <cust_eint.h>
+#include <mach/eint.h>
+#include <cust_cwmcu.h>
+#include <mach/mt_pm_ldo.h>
+#include <linux/wakelock.h>
+#include <linux/spi/spi.h>
+#include <mach/mt_spi.h>
+
+
+#define ACK 0x79
+#define NACK 0x1F
+
+#define DPS_MAX (1 << (16 - 1))
+
+/* Input poll interval in milliseconds */
+#define CWMCU_POLL_INTERVAL 10
+#define CWMCU_POLL_MAX 200
+#define CWMCU_POLL_MIN 10
+
+#define CWMCU_MAX_OUTPUT_ID (CW_SNAP+1)
+#define CWMCU_MAX_OUTPUT_BYTE (CWMCU_MAX_OUTPUT_ID * 7)
+#define CWMCU_MAX_DRIVER_OUTPUT_BYTE 256
+static struct wake_lock cwmcu_wakelock;
+static CWMCU_send_dummy_data(uint32_t timestamp);
+
+int cw_fw_upgrade_status = -1;
+module_param(cw_fw_upgrade_status, int, 0660);
+int cw_tilt_wakeup_flag = 1;
+module_param(cw_tilt_wakeup_flag, int, 0660);
+int cw_data_log = 0;
+module_param(cw_data_log, int, 0660);
+
+static struct early_suspend cw_early_suspend_handler = {
+ .level = EARLY_SUSPEND_LEVEL_DISABLE_FB+1,
+ .suspend = NULL,
+ .resume = NULL,
+};
+
+/* turn on gpio interrupt if defined */
+#define CWMCU_INTERRUPT
+
+struct CWMCU_data *sensor;
+
+static int CWMCU_Set_Mcu_Mode(int mode)
+{
+ switch (sensor->mcu_mode) {
+ case CW_NORMAL:
+ sensor->mcu_mode = mode;
+ break;
+ case CW_SLEEP:
+ sensor->mcu_mode = mode;
+ break;
+ case CW_NO_SLEEP:
+ sensor->mcu_mode = mode;
+ break;
+ case CW_BOOT:
+ sensor->mcu_mode = mode;
+ break;
+ default:
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static void cwmcu_powermode_switch(SWITCH_POWER_ID id, int onoff)
+{
+ if (onoff) {
+ if (sensor->power_on_list == 0) {
+ mt_set_gpio_out(GPIO_CW_MCU_WAKE_UP, onoff);
+ }
+ sensor->power_on_list |= ((uint32_t)(1) << id);
+ usleep_range(200, 250);
+ } else {
+ sensor->power_on_list &= ~(1 << id);
+ if (sensor->power_on_list == 0) {
+ mt_set_gpio_out(GPIO_CW_MCU_WAKE_UP, onoff);
+ }
+ }
+ /* CW_DEBUG("%s id = %d, onoff = %d", __func__, id, onoff); */
+}
+
+static void cwmcu_kernel_status(uint8_t status)
+{
+ sensor->kernel_status = status;
+ CWMCU_bus_write(sensor, CwRegMapW_KERNEL_STATUS, &sensor->kernel_status, 1);
+}
+
+static void cwmcu_reinit(void)
+{
+ uint8_t data[10];
+ int i =0;
+ int j =0;
+ for(i = 0;i<HANDLE_ID_END;i ++){
+ for(j = 0;j<SENSORS_ID_END;j ++){
+ if(sensor->sensors_info[i][j].en){
+ data[0] = i;
+ data[1] = j;
+ data[2] = (sensor->sensors_info[i][j].rate ==0)?200:sensor->sensors_info[i][j].rate;
+ data[3] = (uint8_t)sensor->sensors_info[i][j].timeout;
+ data[4] = (uint8_t)(sensor->sensors_info[i][j].timeout >>8);
+ if(CWMCU_bus_write(sensor, CwRegMapW_SET_ENABLE, data, 5)< 0){
+ printk("%s:%s:(flush:bus write fail)\n",LOG_TAG_KERNEL ,__FUNCTION__);
+ }
+ printk("%s:%s:(id:%d enable)\n",LOG_TAG_KERNEL ,__FUNCTION__,j);
+
+ if(CWMCU_bus_write(sensor, CwRegMapW_SET_FLUSH, data, 2)< 0){
+ printk("%s:%s:(flush:bus write fail)\n",LOG_TAG_KERNEL ,__FUNCTION__);
+ }
+ printk("%s:%s:(flush:id:%d)\n",LOG_TAG_KERNEL ,__FUNCTION__, j);
+ msleep(1);
+ }
+ }
+ }
+
+ if(sensor->initial_hw_config){
+ for(i = 0;i<HW_ID_END;i++){
+ if(sensor->hw_info[i].hw_id !=HW_ID_END){
+ data[0] = i;
+ data[1] = sensor->hw_info[i].hw_id;
+ data[2] = sensor->hw_info[i].deviceaddr;
+ data[3] = sensor->hw_info[i].rate;
+ data[4] = sensor->hw_info[i].mode;
+ data[5] = sensor->hw_info[i].position;
+ data[6] = sensor->hw_info[i].private_setting[0];
+ data[7] = sensor->hw_info[i].private_setting[1];
+ data[8] = sensor->hw_info[i].private_setting[2];
+ data[9] = sensor->hw_info[i].private_setting[3];
+ CWMCU_bus_write(sensor, CwRegMapRW_HW_SENSORS_CONFIG_START+i, data, 10);
+ printk(KERN_DEBUG "CwMcu:%s id:%d, HwId:%u, deviceaddr:%u, mode:%u, position:%u\n"
+ ,__FUNCTION__
+ , i
+ ,sensor->hw_info[i].hw_id
+ ,sensor->hw_info[i].deviceaddr
+ ,sensor->hw_info[i].mode
+ ,sensor->hw_info[i].position
+ );
+ }
+ }
+ }
+
+ cwmcu_kernel_status(KERNEL_RESUND);
+}
+
+static void cwmcu_send_event_to_hal(uint8_t event, uint8_t data0, uint8_t data1)
+{
+ uint32_t data_event = 0;
+ sensor->report_count++;
+ data_event = ((u32)sensor->report_count << 24) |((u32)event << 16) | ((u32)data1 << 8) | (u32)data0;
+ input_report_abs(sensor->input, CW_ABS_X, data_event);
+ input_sync(sensor->input);
+}
+
+static void cwmcu_read_batch_buff(struct CWMCU_data *sensor)
+{
+ uint8_t data[20];
+ uint16_t count = 0;
+ uint32_t data_event[4] = {0};
+ int i = 0;
+
+ if (CWMCU_bus_read(sensor, CwRegMapR_BatchCount, data, 2) >= 0) {
+ count = ((uint16_t)data[1] << 8) | (uint16_t)data[0];
+// printk("CwMcu:%s count %u\n",__FUNCTION__, count);
+ } else {
+ printk("CwMcu:%s check count failed~!!\n",__FUNCTION__);
+ return;
+ }
+ for (i = 0; i < count; i++) {
+ if (CWMCU_bus_read(sensor, CwRegMapR_BatchEvent, data, 9) >= 0) {
+ /* check if there are no data from queue */
+ if (data[0] != CWMCU_NODATA) {
+ sensor->report_count++;
+ if (data[0] == META_DATA) {
+ data_event[1] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[2] << 8) | (u32)data[1];
+ printk("CwMcu:%s META_DATA ,%u,%u,%u,%u,%u,%u,%u,%u,%u\n",__FUNCTION__,
+ data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7],data[8]
+ );
+ input_report_abs(sensor->input, CW_ABS_Z, data_event[1]);
+ input_sync(sensor->input);
+ } else if (data[0] == TimestampSync) {
+ data_event[1] = ((u32)data[4] << 24) | ((u32)data[3] << 16) | ((u32)data[2] << 8) | (u32)data[1];
+ printk( "CwMcu:TimestampSync :%u\n",data_event[1]);
+ input_report_abs(sensor->input, CW_ABS_TIMEBASE_WAKE_UP, data_event[1]);
+ input_sync(sensor->input);
+ } else if (data[0] == ACCURACY_UPDATE) {
+ data_event[1] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[2] << 8) | (u32)data[1];
+ printk( "CwMcu:TimestampSync :%u\n",data_event[1]);
+ input_report_abs(sensor->input, CW_ABS_ACCURACY, data_event[1]);
+ input_sync(sensor->input);
+ } else {
+ data_event[0] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[2] << 8) | (u32)data[1];
+ data_event[1] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[4] << 8) | (u32)data[3];
+ data_event[2] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[6] << 8) | (u32)data[5];
+ data_event[3] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[8] << 8) | (u32)data[7];
+
+ /* Calibration */
+ if (data[0] == ACCELERATION || data[0] == GYRO) {
+ data_event[0] += sensor->cali_data[data[0]].x;
+ data_event[1] += sensor->cali_data[data[0]].y;
+ data_event[2] += sensor->cali_data[data[0]].z;
+ }
+
+ if (cw_data_log)
+ CW_DEBUG("read_batch_buff: 0x%x,ox%x,0x%x,0x%x", data_event[0], data_event[1], data_event[2], data_event[3]);
+ /* check flush event */
+ input_report_abs(sensor->input, CW_ABS_X, data_event[0]);
+ input_report_abs(sensor->input, CW_ABS_Y, data_event[1]);
+ input_report_abs(sensor->input, CW_ABS_Z, data_event[2]);
+ input_report_abs(sensor->input, CW_ABS_TIMEDIFF_WAKE_UP, data_event[3]);
+ input_sync(sensor->input);
+ }
+ }
+ }
+ }
+ sensor->interrupt_check_count++;
+}
+static void cwmcu_read_stream_buff(struct CWMCU_data *sensor)
+{
+ uint8_t data[20];
+ uint16_t count = 0;
+ uint32_t data_event[4] = {0};
+ int i = 0;
+ static int pre_tilt = 0;
+
+ if (CWMCU_bus_read(sensor, CwRegMapR_StreamCount, data, 2) >= 0) {
+ count = ((uint16_t)data[1] << 8) | (uint16_t)data[0];
+// printk("CwMcu:%s count %u\n",__FUNCTION__, count);
+ } else {
+ printk("CwMcu:%s check count failed~!!\n",__FUNCTION__);
+ return;
+ }
+ for (i = 0; i < count; i++) {
+ if (CWMCU_bus_read(sensor, CwRegMapR_StreamEvent, data, 9) >= 0) {
+ if (data[0] != TILT) pre_tilt = 0;
+ /* check if there are no data from queue */
+ if (data[0] != CWMCU_NODATA) {
+ sensor->report_count++;
+ if (data[0] == META_DATA) {
+ data_event[1] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[2] << 8) | (u32)data[1];
+ printk("CwMcu:%s META_DATA ,%u,%u,%u,%u,%u,%u,%u,%u,%u\n",__FUNCTION__,
+ data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7],data[8]
+ );
+ input_report_abs(sensor->input, CW_ABS_Z, data_event[1]);
+ input_sync(sensor->input);
+ CWMCU_send_dummy_data(0);
+ } else if (data[0] == TimestampSync) {
+ data_event[1] = ((u32)data[4] << 24) | ((u32)data[3] << 16) | ((u32)data[2] << 8) | (u32)data[1];
+ printk( "CwMcu:TimestampSync :%u\n",data_event[1]);
+ input_report_abs(sensor->input, CW_ABS_TIMEBASE, data_event[1]);
+ input_sync(sensor->input);
+ } else if (data[0] == ACCURACY_UPDATE) {
+ data_event[1] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[2] << 8) | (u32)data[1];
+ printk( "CwMcu:AccuracySync :%u\n",data_event[1]);
+ input_report_abs(sensor->input, CW_ABS_ACCURACY, data_event[1]);
+ input_sync(sensor->input);
+ }
+ else if (data[0] == TILT) {
+ if (cw_tilt_wakeup_flag) {
+ if (data[5] == 1) {
+ pre_tilt = 1;
+
+ }else if (pre_tilt == 1 && data[5] == 0){
+ pre_tilt = 0;
+ //TODO check data_event[2] bit 0
+ input_report_key(sensor->input, KEY_POWER, 1);
+ input_sync(sensor->input);
+ input_report_key(sensor->input, KEY_POWER, 0);
+ input_sync(sensor->input);
+ }
+ input_report_abs(sensor->input, CW_ABS_X, 700);
+ input_report_abs(sensor->input, CW_ABS_Y, 650);
+ input_report_abs(sensor->input, CW_ABS_Z, 650);
+ input_sync(sensor->input);
+ /* check flush event */
+ CW_INFO("tilt wakeup(%d) %x,%x,%x,%x",pre_tilt, data_event[0], data_event[1], data_event[2], data_event[3]);
+ }
+ }
+ else {
+ data_event[0] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[2] << 8) | (u32)data[1];
+ data_event[1] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[4] << 8) | (u32)data[3];
+ data_event[2] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[6] << 8) | (u32)data[5];
+ data_event[3] = ((u32)sensor->report_count << 24) |((u32)data[0] << 16) | ((u32)data[8] << 8) | (u32)data[7];
+
+ /* Calibration */
+ data_event[0] += sensor->cali_data[data[0]].x/10;
+ data_event[1] += sensor->cali_data[data[0]].y/10;
+ data_event[2] += sensor->cali_data[data[0]].z/10;
+
+ if (cw_data_log)
+ CW_DEBUG("read_stream_buff: 0x%x,ox%x,0x%x,0x%x", data_event[0], data_event[1], data_event[2], data_event[3]);
+ /* check flush event */
+ input_report_abs(sensor->input, CW_ABS_X, data_event[0]);
+ input_report_abs(sensor->input, CW_ABS_Y, data_event[1]);
+ input_report_abs(sensor->input, CW_ABS_Z, data_event[2]);
+ input_report_abs(sensor->input, CW_ABS_TIMEDIFF, data_event[3]);
+ input_sync(sensor->input);
+ }
+ }
+ }
+ }
+ sensor->interrupt_check_count++;
+}
+
+#define QueueSystemInfoMsgSize 30
+
+static void ParserInfoFormQueue(char *data){
+ static unsigned char loge_bufftemp[QueueSystemInfoMsgSize*2];
+ static unsigned char buff_counttemp = 0;
+ int i;
+ for(i=0;i<QueueSystemInfoMsgSize;i++){
+ loge_bufftemp[buff_counttemp] = (unsigned char)data[i];
+ buff_counttemp++;
+ if(data[i] == '\n'){
+ printk("CwMcuInfo:%s",loge_bufftemp);
+ memset(loge_bufftemp,0x00,QueueSystemInfoMsgSize*2);
+ buff_counttemp = 0;
+ }
+ }
+}
+static void cwmcu_read_mcu_info(struct CWMCU_data *sensor)
+{
+ uint8_t data[40];
+ uint16_t count = 0;
+ int i = 0;
+
+ if (CWMCU_bus_read(sensor, CwRegMapR_SystemInfoMsgCount, data, 1) >= 0) {
+ count = (uint16_t)data[0];
+ } else {
+ printk("CwMcu:%s check count failed~!!\n",__FUNCTION__);
+ return;
+ }
+ for (i = 0; i < count; i++) {
+ if (CWMCU_bus_read(sensor, CwRegMapR_SystemInfoMsgEvent, data, 30) >= 0) {
+ ParserInfoFormQueue(data);
+ }
+ }
+
+}
+
+
+static void cwmcu_read_Interrupt_buff(struct CWMCU_data *sensor)
+{
+ uint8_t data[4];
+ uint16_t count = 0;
+ int i = 0;
+ if (CWMCU_bus_read(sensor, CwRegMapR_InteruptCount, data, 1) >= 0) {
+ count = (uint16_t)data[0];
+ } else {
+ printk("CwMcu:%s check count failed~!!\n",__FUNCTION__);
+ return;
+ }
+ for (i = 0; i < count; i++) {
+ if (CWMCU_bus_read(sensor, CwRegMapR_InteruptEvent, data, 4) >= 0) {
+ if(data[0] == ERROR_MSG){
+ switch ((int8_t)data[2] ) {
+ case DRIVER_ENABLE_FAIL:
+ printk("CwMcu:DRIVER_ENABLE_FAIL:ID:%u:Status:%u\n", data[1],data[3]);
+ break;
+ case DRIVER_DISABLE_FAIL:
+ printk("CwMcu:DRIVER_DISABLE_FAIL:ID:%u:Status:%u\n", data[1],data[3]);
+ break;
+ case DRIVER_GETDATA_FAIL:
+ printk("CwMcu:DRIVER_GETDATA_FAIL:ID:%u:Status:%u\n", data[1],data[3]);
+ break;
+ }
+ }else if(data[0] == CALIBRATOR_UPDATE){
+ #if 0
+ if(data[1] == CALIBRATOR_TYPE_DEFAULT){
+ printk("CwMcu:Calibrator Id:%u,Status:%u\n", data[2],data[3]);
+ if(data[3] == CALIBRATOR_STATUS_PASS){
+ cwmcu_send_event_to_hal(CALIBRATOR_UPDATE,data[2],data[3]);
+ }
+ #endif
+ }else if(data[1] == CALIBRATOR_TYPE_SELFTEST){
+ printk("CwMcu:Selftest Id:%u,Status:%u\n", data[2],data[3]);
+ }
+ }else if(data[0] == MCU_ENABLE_LIST){
+ if(data[1] == 0){
+ sensor->mcu_enable_list = (sensor->mcu_enable_list&0xFFFF0000) |(((uint32_t)data[3])<<8)|((uint32_t)data[2]);
+ }else if(data[1] == 1){
+ sensor->mcu_enable_list = (sensor->mcu_enable_list&0x0000FFFF) |(((uint32_t)data[3])<<24)|(((uint32_t)data[2])<<16);
+ }
+ printk("CwMcu:%s:(McuEnableList:%u)\n",__FUNCTION__,sensor->mcu_enable_list);
+ }else if(data[0] == MCU_HW_ENABLE_LIST){
+ if(data[1] == 0){
+ sensor->mcu_hw_enable_list = (sensor->mcu_hw_enable_list&0xFFFF0000) |(((uint32_t)data[3])<<8)|((uint32_t)data[2]);
+ }else if(data[1] == 1){
+ sensor->mcu_hw_enable_list = (sensor->mcu_hw_enable_list&0x0000FFFF) |(((uint32_t)data[3])<<24)|(((uint32_t)data[2])<<16);
+ }
+ printk("CwMcu:%s:(McuHwEnableList:%u)\n",__FUNCTION__,sensor->mcu_hw_enable_list);
+ }
+ }
+ sensor->interrupt_check_count++;
+}
+
+static void cwmcu_interrupt_trigger(struct CWMCU_data *sensor)
+{
+ uint8_t temp[2] = {0};
+
+ if (sensor->mcu_mode == CW_BOOT) {
+ printk("--CWMCU--%s sensor->mcu_mode = %d\n", __func__, sensor->mcu_mode);
+ return;
+ }
+ /* check mcu interrupt status */
+ if (CWMCU_bus_read(sensor, CwRegMapR_InterruptStatus, temp, 2) >= 0) {
+ sensor->interrupt_status = (u32)temp[1] << 8 | (u32)temp[0];
+ if (cw_data_log)
+ CW_DEBUG("==>INT:0x%x (en_list=0x%x)",sensor->interrupt_status, sensor->enabled_list);
+ } else {
+ printk("--CWMCU-- check interrupt_status failed~!!\n");
+ return;
+ }
+
+ if (sensor->interrupt_status & (1<<INTERRUPT_INIT)) {
+ cwmcu_reinit();
+ cwmcu_send_event_to_hal(MCU_REINITIAL,0,0);
+ }
+ if (sensor->interrupt_status & (1<<INTERRUPT_TIMESYNC)) {
+ cwmcu_send_event_to_hal(TimestampSync,0,0);
+ }
+ if ((sensor->interrupt_status & (1<<INTERRUPT_BATCHTIMEOUT)) || (sensor->interrupt_status & (1<<INTERRUPT_BATCHFULL)) ) {
+ cwmcu_read_batch_buff(sensor);
+ }
+ if (sensor->interrupt_status & (1<<INTERRUPT_INFO)) {
+ cwmcu_read_Interrupt_buff(sensor);
+ }
+ if (sensor->interrupt_status & (1<<INTERRUPT_DATAREADY)) {
+ cwmcu_read_stream_buff(sensor);
+ }
+ if (sensor->interrupt_status & (1<<INTERRUPT_LOGE)) {
+ cwmcu_read_mcu_info(sensor);
+ }
+}
+
+#if 0
+
+static int CWMCU_read(struct CWMCU_data *sensor)
+{
+ #ifndef CWMCU_INTERRUPT
+ cwmcu_powermode_switch(SWITCH_POWER_NORMAL, 1);
+ if(sensor->enabled_list)
+ cwmcu_read_stream_buff(sensor);
+
+ if(sensor->debug_log)
+ cwmcu_read_mcu_info(sensor);
+
+ cwmcu_interrupt_trigger(sensor);
+
+ cwmcu_powermode_switch(SWITCH_POWER_NORMAL, 0);
+ #else
+ if(sensor->debug_log){
+ cwmcu_powermode_switch(SWITCH_POWER_NORMAL, 1);
+ cwmcu_read_mcu_info(sensor);
+ cwmcu_powermode_switch(SWITCH_POWER_NORMAL, 0);
+ }
+ #endif
+ return 0;
+ }
+#else
+
+static int CWMCU_read(struct CWMCU_data *sensor)
+{
+ if (sensor->mcu_mode == CW_BOOT) {
+ return 0;
+ }
+#ifndef CWMCU_INTERRUPT
+ cwmcu_powermode_switch(SWITCH_POWER_NORMAL, 1);
+ if(sensor->kernel_status !=KERNEL_SUPEND) {
+ cwmcu_kernel_status(KERNEL_RESUND);
+ cwmcu_interrupt_trigger(sensor);
+ }
+ if(sensor->enabled_list)
+ cwmcu_read_stream_buff(sensor);
+
+ if(sensor->debug_log){
+ cwmcu_powermode_switch(SWITCH_POWER_LOG, 1);
+ cwmcu_read_mcu_info(sensor);
+ cwmcu_powermode_switch(SWITCH_POWER_LOG, 0);
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_NORMAL, 0);
+#else
+ if(sensor->debug_log){
+ cwmcu_powermode_switch(SWITCH_POWER_LOG, 1);
+ cwmcu_read_mcu_info(sensor);
+ cwmcu_powermode_switch(SWITCH_POWER_LOG, 0);
+ }
+#endif
+
+ return 0;
+}
+#endif
+/*==========sysfs node=====================*/
+
+static int active_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int enabled = 0;
+ int id = 0;
+ int handle = 0;
+ uint32_t enabled_list = 0;
+ uint32_t enabled_list_temp = 0;
+ uint8_t data[5];
+ int i = 0;
+
+ sscanf(buf, "%d %d\n", &id, &enabled);
+
+ handle = NonWakeUpHandle;
+ sensor->sensors_info[handle][id].en = enabled;
+ data[0] = handle;
+ data[1] = id;
+ if(enabled){
+ sensor->enabled_list |= 1<<id;
+ data[2] = (sensor->sensors_info[handle][id].rate ==0)?200:sensor->sensors_info[handle][id].rate;
+ data[3] = (uint8_t)sensor->sensors_info[handle][id].timeout;
+ data[4] = (uint8_t)(sensor->sensors_info[handle][id].timeout >>8);
+ }else{
+ sensor->enabled_list &= ~(1<<id);
+ sensor->sensors_info[handle][id].rate = 0;
+ sensor->sensors_info[handle][id].timeout = 0;
+ data[2] = 0;
+ data[3] = 0;
+ data[4] = 0;
+ }
+ if (sensor->mcu_mode == CW_BOOT) {
+ return count;
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_ENABLE, 1);
+ if(enabled){
+ if(CWMCU_bus_write(sensor, CwRegMapW_SET_ENABLE, data, 5)< 0){
+ printk("%s:%s:(bus Write Fail)\n",LOG_TAG_KERNEL ,__FUNCTION__);
+ }
+ }else{
+ if(CWMCU_bus_write(sensor, CwRegMapW_SET_DISABLE, data, 5)< 0){
+ printk("%s:%s:(bus Write Fail)\n",LOG_TAG_KERNEL ,__FUNCTION__);
+ }
+ }
+ msleep(5);
+
+ if (CWMCU_bus_read(sensor, CwRegMapR_EnableList, data, 4) < 0)
+ return count;
+ enabled_list = (uint32_t)data[3]<<24 |(uint32_t)data[2]<<16 |(uint32_t)data[1]<<8 |(uint32_t)data[0];
+ if(enabled_list !=sensor->enabled_list){
+ printk("%s:%s:(Enable not match AP:0x%x,MCU:0x%x)\n",LOG_TAG_KERNEL ,__FUNCTION__, sensor->enabled_list,enabled_list);
+ enabled_list_temp = sensor->enabled_list ^ enabled_list;
+ for(i=0;i<SENSORS_ID_END;i++){
+ if (enabled_list_temp & (1<<i)) {
+ data[0] = NonWakeUpHandle;
+ data[1] = i;
+ if(sensor->sensors_info[NonWakeUpHandle][i].en){
+ data[2] = (sensor->sensors_info[NonWakeUpHandle][i].rate ==0)?200:sensor->sensors_info[NonWakeUpHandle][i].rate;
+ data[3] = (uint8_t)sensor->sensors_info[NonWakeUpHandle][i].timeout;
+ data[4] = (uint8_t)(sensor->sensors_info[NonWakeUpHandle][i].timeout >>8);
+ CWMCU_bus_write(sensor, CwRegMapW_SET_ENABLE, data, 5);
+ printk("%s:%s:(id:%d enable)\n",LOG_TAG_KERNEL ,__FUNCTION__,i);
+ }else{
+ data[2] = 0;
+ data[3] = 0;
+ data[4] = 0;
+ if(CWMCU_bus_write(sensor, CwRegMapW_SET_DISABLE, data, 5)< 0){
+ printk("%s:%s:(bus Write Fail)\n",LOG_TAG_KERNEL ,__FUNCTION__);
+ }
+ }
+ msleep(5);
+ }
+ }
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_ENABLE, 0);
+ printk("%s:%s:(id:%d, en:%d)\n",LOG_TAG_KERNEL ,__FUNCTION__, id,enabled);
+ return count;
+}
+
+static int active_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ uint8_t data[5];
+ uint32_t mcu_enabled_list;
+
+ cwmcu_powermode_switch(SWITCH_POWER_NORMAL, 1);
+ CWMCU_bus_read(sensor, CwRegMapR_EnableList, data, 4);
+ cwmcu_powermode_switch(SWITCH_POWER_NORMAL, 0);
+ mcu_enabled_list = (uint32_t)data[3]<<24 |(uint32_t)data[2]<<16 |(uint32_t)data[1]<<8 |(uint32_t)data[0];
+
+ return sprintf(buf, "0x%x (mcu:0x%x)\n", sensor->enabled_list, mcu_enabled_list);
+}
+
+static int interval_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, sizeof(CWMCU_POLL_INTERVAL), "%d\n", CWMCU_POLL_INTERVAL);
+}
+
+static int interval_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ return count;
+}
+
+static int batch_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int id = 0;
+ int handle = 0;
+ int mode = -1;
+ int rate = 0;
+ int64_t timeout = 0;
+ uint8_t data[5];
+
+// if(mode ==0)
+ {
+ sscanf(buf, "%d %d %d %lld\n", &id, &mode, &rate, &timeout);
+
+ handle = NonWakeUpHandle;
+ sensor->sensors_info[handle][id].rate = rate;
+ sensor->sensors_info[handle][id].timeout = timeout;
+ data[0] = handle;
+ data[1] = id;
+ data[2] = sensor->sensors_info[handle][id].rate;
+ data[3] = (uint8_t)sensor->sensors_info[handle][id].timeout;
+ data[4] = (uint8_t)(sensor->sensors_info[handle][id].timeout >>8);
+
+ if (sensor->mcu_mode == CW_BOOT) {
+ return count;
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_BATCH, 1);
+ if (CWMCU_bus_write(sensor, CwRegMapW_SET_ENABLE, data, 5)<0){
+ printk("%s:%s:(Write Fail:id:%d, mode:%d, rate:%d, timeout:%lld)\n",LOG_TAG_KERNEL ,__FUNCTION__, id,mode, rate, timeout);
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_BATCH, 0);
+ printk("%s:%s:(id:%d, mode:%d, rate:%d, timeout:%lld)\n",LOG_TAG_KERNEL ,__FUNCTION__, id,mode, rate, timeout);
+ }
+ return count;
+}
+
+static int batch_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, sizeof(buf), "\n");
+}
+
+static int flush_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int id = 0;
+ int error_msg = 0;
+ uint8_t data[2];
+ if (sensor->mcu_mode == CW_BOOT) {
+ return count;
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_BATCH, 1);
+
+ sscanf(buf, "%d\n", &id);
+ data[0] = NonWakeUpHandle;
+ data[1] = (uint8_t)id;
+
+ printk("CwMcu: flush id = %d~!!\n", id);
+
+ error_msg = CWMCU_bus_write(sensor, CwRegMapW_SET_FLUSH, data, 2);
+
+ if (error_msg < 0)
+ printk("CwMcu: flush bus error~!!\n");
+ cwmcu_powermode_switch(SWITCH_POWER_BATCH, 0);
+
+ return count;
+}
+
+static int flush_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ CW_INFO("%s in", __func__);
+ return 0;
+}
+
+static int CWMCU_Erase_Mcu_Memory(void)
+{
+ /* page should be 1~N */
+ uint8_t send[300];
+ uint8_t received[10];
+ uint8_t XOR = 0;
+ uint8_t page;
+ uint16_t i = 0;
+ page = 128;
+
+ send[0] = 0x44;
+ send[1] = 0xBB;
+ if (CWMCU_bus_write_serial((uint8_t *)send, 2) < 0) {
+ return -EAGAIN;
+ }
+ if (CWMCU_bus_read_serial((uint8_t *)received, 1) < 0) {
+ return -EAGAIN;
+ }
+ if (received[0] != ACK) {
+ return -EAGAIN;
+ }
+
+ send[0] = (uint8_t) ((page-1)>>8);
+ send[1] = (uint8_t) (page-1);
+ send[2] = send[0] ^ send[1];
+ if (CWMCU_bus_write_serial((uint8_t *)send, 3) < 0) {
+ return -EAGAIN;
+ }
+ if (CWMCU_bus_read_serial((uint8_t *)received, 1) < 0) {
+ return -EAGAIN;
+ }
+ if (received[0] != ACK) {
+ return -EAGAIN;
+ }
+
+ for (i = 0; i < page; i++) {
+ send[2*i] = (uint8_t)(i>>8);
+ send[(2*i)+1] = (uint8_t)i;
+ XOR = XOR ^ send[2*i] ^ send[(2*i)+1];
+ }
+ send[(2*page)] = XOR;
+ if (CWMCU_bus_write_serial((uint8_t *)send, ((2*page)+1)) < 0) {
+ return -EAGAIN;
+ }
+ return 0;
+
+}
+static int CWMCU_Write_Mcu_Memory(const char *buf)
+{
+ uint8_t WriteMemoryCommand[2];
+ uint8_t data[300];
+ uint8_t received[10];
+ uint8_t XOR = 0;
+ uint16_t i = 0;
+ WriteMemoryCommand[0] = 0x31;
+ WriteMemoryCommand[1] = 0xCE;
+ if (CWMCU_bus_write_serial((uint8_t *)WriteMemoryCommand, 2) < 0) {
+ return -EAGAIN;
+ }
+ if (CWMCU_bus_read_serial((uint8_t *)received, 1) < 0) {
+ return -EAGAIN;
+ }
+ if (received[0] != ACK) {
+ return -EAGAIN;
+ }
+
+ /* Set Address + Checksum */
+ data[0] = (uint8_t) (sensor->addr >> 24);
+ data[1] = (uint8_t) (sensor->addr >> 16);
+ data[2] = (uint8_t) (sensor->addr >> 8);
+ data[3] = (uint8_t) sensor->addr;
+ data[4] = data[0] ^ data[1] ^ data[2] ^ data[3];
+ if (CWMCU_bus_write_serial((uint8_t *)data, 5) < 0) {
+ return -EAGAIN;
+ }
+ if (CWMCU_bus_read_serial((uint8_t *)received, 1) < 0) {
+ return -EAGAIN;
+ }
+ if (received[0] != ACK) {
+ return -EAGAIN;
+ }
+
+ /* send data */
+ data[0] = sensor->len - 1;
+ XOR = sensor->len - 1;
+ for (i = 0; i < sensor->len; i++) {
+ data[i+1] = buf[i];
+ XOR ^= buf[i];
+ }
+ data[sensor->len+1] = XOR;
+
+ if (CWMCU_bus_write_serial((uint8_t *)data, (sensor->len + 2)) < 0) {
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static CWMCU_send_dummy_data(uint32_t timestamp)
+{
+ uint32_t data_event[4] = {0x00100000, 0x00100000, 0x00100000, 0x00100000};
+ static int first_in = 1;
+
+ if (first_in) {
+ // for show step card
+ //data_event[2] |= timestamp;
+ input_report_abs(sensor->input, CW_ABS_X, data_event[0]);
+ input_report_abs(sensor->input, CW_ABS_Y, data_event[1]);
+ input_report_abs(sensor->input, CW_ABS_Z, data_event[2]);
+ input_report_abs(sensor->input, CW_ABS_TIMEDIFF, data_event[3]);
+ input_sync(sensor->input);
+ first_in = 0;
+ CW_DEBUG("CWMCU_send_dummy_data : send dummy pedometer data");
+}
+}
+
+static int set_firmware_update_cmd(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ u8 data[40] = {0};
+ s16 data_buff[3] = {0};
+ s16 _bData[8];
+ s16 _bData2[9];
+ s16 m_hdata[3];
+ s16 m_asa[3];
+ u8 test = 0x01;
+
+ sscanf(buf, "%d %d %d\n", &sensor->cmd, &sensor->addr, &sensor->len);
+ CW_INFO("CWMCU cmd=%d addr=%d len=%d", sensor->cmd, sensor->addr, sensor->len);
+
+ cwmcu_powermode_switch(SWITCH_POWER_FIRMWARE_COMMAND, 1);
+
+ switch (sensor->cmd) {
+ case CHANGE_TO_BOOTLOADER_MODE:
+ CW_INFO("CWMCU CHANGE_TO_BOOTLOADER_MODE");
+ wake_lock(&cwmcu_wakelock);
+ cw_fw_upgrade_status = 0;
+ sensor->mcu_mode = CW_BOOT;
+ /* boot enable : put high , reset: put low */
+ mt_set_gpio_out(GPIO_CW_MCU_RESET, 1);
+ mt_set_gpio_out(GPIO_CW_MCU_BOOT, 1);
+ msleep(500);
+ mt_set_gpio_out(GPIO_CW_MCU_RESET, 1);
+ msleep(500);
+ mt_set_gpio_out(GPIO_CW_MCU_RESET, 0);
+ msleep(500);
+ mt_set_gpio_out(GPIO_CW_MCU_RESET, 1);
+ msleep(1000);
+
+#if defined(CWMCU_I2C_INTERFACE)
+ sensor->mcu_slave_addr = sensor->client->addr;
+ sensor->client->addr = 0x72 >> 1;
+#elif defined(CWMCU_SPI_INTERFACE)
+ {
+ int count = 20;
+ u8 tbuf[3] = {0x0};
+ u8 rbuf[10] = {0x0};
+
+ tbuf[0] = 0x5A;
+ if (CWMCU_bus_write_serial(tbuf, 1) < 0)
+ {
+ CW_ERROR("F/W bootloader mode wrtie 0x5A failed");
+ }
+
+ tbuf[0] = 0x0;
+
+ while(count-- > 0) {
+ if (spi_rw_bytes_serial(tbuf, rbuf, 1) < 0) {
+ CW_ERROR("F/W bootloader mode read ACK failed");
+ continue;
+ }
+
+ if (rbuf[0] == 0x79)
+ {
+ CW_INFO("F/W bootloader ACK is 0x79");
+ tbuf[0] = 0x79;
+ CWMCU_bus_write_serial(tbuf, 1);
+ break;
+ }
+
+ CW_INFO("F/W bootloader polling ACK... ");
+ }
+ if (count <= 0)
+ CW_INFO("F/W bootloader ACK failed... %d", count);
+ }
+#endif
+ break;
+
+ case CHANGE_TO_NORMAL_MODE:
+ CW_INFO("CWMCU CHANGE_TO_NORMAL_MODE");
+
+ sensor->firmwave_update_status = 1;
+#if defined(CWMCU_I2C_INTERFACE)
+ sensor->client->addr = 0x74 >> 1;
+#endif
+ /* boot low reset high */
+ mt_set_gpio_out(GPIO_CW_MCU_BOOT, 0);
+ mt_set_gpio_out(GPIO_CW_MCU_RESET, 1);
+ msleep(500);
+ mt_set_gpio_out(GPIO_CW_MCU_RESET, 0);
+ msleep(500);
+ mt_set_gpio_out(GPIO_CW_MCU_RESET, 1);
+ msleep(1000);
+
+ //mt_set_gpio_dir(GPIO_CW_MCU_RESET, GPIO_DIR_IN);
+
+ sensor->mcu_mode = CW_NORMAL;
+ cwmcu_reinit();
+ cw_fw_upgrade_status = 1;
+ wake_unlock(&cwmcu_wakelock);
+ break;
+
+ case ERASE_MCU_MEMORY:
+ CW_INFO("CWMCU ERASE_MCU_MEMORY");
+ sensor->firmwave_update_status = 1;
+ sensor->firmwave_update_status = CWMCU_Erase_Mcu_Memory();
+ break;
+
+ case WRITE_MCU_MEMORY:
+ CW_INFO("CWMCU Set Addr=%d\tlen=%d", sensor->addr, sensor->len);
+ break;
+
+ case MCU_GO:
+ CW_INFO("CWMCU MCU_GO");
+ break;
+
+ case CHECK_FIRMWAVE_VERSION:
+ CW_INFO("READ F/W VERSION, cw_fw_upgrade_status=%d", cw_fw_upgrade_status);
+ if (CWMCU_bus_read(sensor, CwRegMapR_REPORT_CHIP_ID, data, 4) >= 0)
+ {
+ CW_INFO( "CwMcu:CHECK_FIRMWAVE_VERSION:%u,%u,%u,%u\n", data[0],data[1],data[2],data[3]);
+ }
+ break;
+
+ case SET_DEBUG_LOG:
+ sensor->debug_log = sensor->addr;
+ break;
+ case SET_SYSTEM_COMMAND:
+ data[0] = sensor->addr;
+ data[1] = sensor->len;
+ CWMCU_bus_write(sensor, CwRegMapW_SystemCommand, data, 2);
+ break;
+ case GET_SYSTEM_TIMESTAMP:
+ if (CWMCU_bus_read(sensor, CwRegMapR_REPORT_SYSTEM_TIMESTAMP, data, 4) >= 0) {
+ printk("Timestamp:%u\n",
+ (((uint32_t)data[3])<<24) |(((uint32_t)data[2])<<16) |(((uint32_t)data[1])<<8) | ((uint32_t)data[0])
+ );
+ }
+ break;
+ case GET_FUNCTION_ENTRY_POINT:
+ if (CWMCU_bus_read(sensor, CwRegMapR_FunctionEntryPoint, data, 4) >= 0) {
+ printk("GET_FUNCTION_ENTRY_POINT:%u\n",
+ (((uint32_t)data[3])<<24) |(((uint32_t)data[2])<<16) |(((uint32_t)data[1])<<8) | ((uint32_t)data[0])
+ );
+ }
+ break;
+ case GET_MCU_INFO:
+ cwmcu_read_mcu_info(sensor);
+ break;
+ case SET_TILT_WAKEUP:
+ cw_tilt_wakeup_flag = 1;
+ break;
+ case SET_HW_INITIAL_CONFIG_FLAG:
+ sensor->initial_hw_config = sensor->addr;
+ break;
+ case SET_SENSORS_POSITION:
+ data[0] = sensor->addr;
+ data[1] = sensor->len;
+ CWMCU_bus_write(sensor, CwRegMapW_HW_SENSORS_POSITION, data, 2);
+ break;
+ case SHOW_LOG_INFO:
+ printk("CwDbg:initial_hw_config%d\n",sensor->initial_hw_config);
+ printk("CwDbg:kernel_status%d\n",sensor->kernel_status);
+ printk("CwDbg:enabled_list%d\n",sensor->enabled_list);
+ printk("CwDbg:interrupt_status%d\n",sensor->interrupt_status);
+ printk("CwDbg:power_on_list%d\n",sensor->power_on_list);
+ printk("CwDbg:%d\n",sensor->power_on_list);
+ printk("CwDbg:%d\n",sensor->power_on_list);
+ break;
+ case GET_SENSORS_INDEX0:
+ case GET_SENSORS_INDEX1:
+ case GET_SENSORS_INDEX2:
+ case GET_SENSORS_INDEX3:
+ case GET_SENSORS_INDEX4:
+ case GET_SENSORS_INDEX5:
+ case GET_SENSORS_INDEX6:
+ CW_INFO( "CWMCU CHECK_ACC_DATA\n");
+ if (CWMCU_bus_read(sensor, CwRegMapR_REPORT_DATA_START +sensor->cmd - GET_SENSORS_INDEX0, data, 6) >= 0) {
+ data_buff[0] = (s16)(((u16)data[1] << 8) | (u16)data[0]);
+ data_buff[1] = (s16)(((u16)data[3] << 8) | (u16)data[2]);
+ data_buff[2] = (s16)(((u16)data[5] << 8) | (u16)data[4]);
+
+ CW_INFO( "x = %d, y = %d, z = %d\n",
+ data_buff[0], data_buff[1], data_buff[2]);
+ }
+ break;
+ default:
+ break;
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_FIRMWARE_COMMAND, 0);
+ return count;
+}
+
+static int set_firmware_update_data(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ CW_INFO("CWMCU Write Data");
+ CW_INFO("%s",buf);
+ sensor->firmwave_update_status = 1;
+ sensor->firmwave_update_status = CWMCU_Write_Mcu_Memory(buf);
+ return count;
+}
+
+static int get_firmware_update_status(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ CW_INFO("CWMCU firmwave_update_status = %d", sensor->firmwave_update_status);
+ return snprintf(buf, sizeof(buf), "%d\n", sensor->firmwave_update_status);
+}
+
+static int set_firmware_update(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+#if defined(CWMCU_I2C_INTERFACE)
+ int intsize = sizeof(int);
+ memcpy(&sensor->cw_bus_rw, buf, intsize);
+ memcpy(&sensor->cw_bus_len, &buf[4], intsize);
+ memcpy(sensor->cw_bus_data, &buf[8], sensor->cw_bus_len);
+
+ //CW_DEBUG("[set_firmware_update_i2] RW=%d, LEN=%d, DATA=0x%x,0x%x", sensor->cw_bus_rw, sensor->cw_bus_len, sensor->cw_bus_data[0], sensor->cw_bus_data[1]);
+#elif defined(CWMCU_SPI_INTERFACE)
+ int intsize = sizeof(int);
+ memcpy(&sensor->cw_bus_rw, buf, intsize);
+ memcpy(&sensor->cw_bus_len, &buf[4], intsize);
+
+ if (sensor->cw_bus_rw)
+ {
+ if (sensor->cw_bus_len == 2)
+ {
+ sensor->cw_bus_len += 1;
+ sensor->cw_bus_data[0] = 0x5A;
+ memcpy(&sensor->cw_bus_data[1], &buf[8], sensor->cw_bus_len);
+ }
+ else
+ {
+ memcpy(sensor->cw_bus_data, &buf[8], sensor->cw_bus_len);
+ }
+ }
+ else
+ {
+ sensor->cw_bus_len = 3;
+ sensor->cw_bus_data[0] = 0x00;
+ sensor->cw_bus_data[1] = 0x00;
+ sensor->cw_bus_data[2] = 0x00;
+ }
+ //CW_DEBUG("SET_FIRMWARE_UPDATE : rw=%d, len=%d, data=%x,%x,%x ", sensor->cw_bus_rw, sensor->cw_bus_len, sensor->cw_bus_data[0], sensor->cw_bus_data[1], sensor->cw_bus_data[2]);
+#endif
+ return count;
+}
+
+static int get_firmware_update(struct device *dev, struct device_attribute *attr, char *buf)
+{
+#if defined(CWMCU_I2C_INTERFACE)
+
+ int status = 0;
+ if (sensor->cw_bus_rw) {
+ if (CWMCU_bus_write_serial(sensor->cw_bus_data, sensor->cw_bus_len) < 0) {
+ status = -1;
+ }
+ memcpy(buf, &status, sizeof(int));
+ return 4;
+ } else {
+ if (CWMCU_bus_read_serial(sensor->cw_bus_data, sensor->cw_bus_len) < 0) {
+ status = -1;
+ memcpy(buf, &status, sizeof(int));
+ return 4;
+ }
+ memcpy(buf, &status, sizeof(int));
+ memcpy(&buf[4], sensor->cw_bus_data, sensor->cw_bus_len);
+ return 4+sensor->cw_bus_len;
+ }
+#elif defined(CWMCU_SPI_INTERFACE)
+
+ int status = -1;
+ if (sensor->cw_bus_rw) {
+ if (CWMCU_bus_write_serial(sensor->cw_bus_data, sensor->cw_bus_len) < 0) {
+ status = -1;
+ }
+ else
+ status = 0;
+ memcpy(buf, &status, sizeof(int));
+ return 4;
+ } else {
+ u8 rbuf[5] = {0};
+ int count = 30;
+
+ while(count-- >= 0) {
+ sensor->cw_bus_data[0] = 0;
+ if (spi_rw_bytes_serial(sensor->cw_bus_data, rbuf, 1) < 0) {
+ CW_ERROR("get_firmware_update:Read failed");
+ continue;
+ }
+ if (rbuf[0] == 0x79) {
+ //CW_INFO("get_firmware_update ACK is 0x79");
+ buf[4] = 0x79;
+ status = 0;
+
+ memcpy(buf, &status, sizeof(int));
+ rbuf[0] = 0x79;
+ CWMCU_bus_write_serial(rbuf, 1);
+ return 4+sensor->cw_bus_len;
+ }
+ //CW_DEBUG("get_firmware_update polling ACK... (0x%x)", rbuf[0]);
+ }
+
+ status = -1;
+ return 4;
+ }
+#endif
+ return 0;
+}
+
+static int mcu_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, sizeof(buf), "%d\n", sensor->mcu_mode);
+}
+
+static int mcu_model_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int mode = 0;
+ sscanf(buf, "%d\n", &mode);
+ CWMCU_Set_Mcu_Mode(mode);
+ return count;
+}
+
+/* get calibrator data */
+static int get_calibrator_data(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ uint8_t data[2] = {0};
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 1);
+ printk("--CWMCU-- CWMCU_CALIBRATOR_STATUS\n");
+ if (CWMCU_bus_read(sensor, CwRegMapR_CalibratorStatus, data, 2) >= 0) {
+ printk("--CWMCU-- calibrator status = %d\n", data[1]);
+ } else {
+ printk("--CWMCU-- bus calibrator status read fail\n");
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 0);
+ return sprintf(buf, "%d\n",data[1]);
+
+}
+
+static int set_calibrator_data(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
+{
+ uint8_t data[33] = {0};
+ int temp[33] = {0};
+
+ if (sensor->mcu_mode == CW_BOOT) {
+ return ;
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 1);
+
+ printk("--CWMCU-- buf = %s\n", buf);
+
+ sscanf(buf, "%d %d %d",&temp[0], &temp[1], &temp[2]);
+ sensor->cal_cmd = (uint8_t)temp[0];
+ sensor->cal_type = (uint8_t)temp[1];
+ sensor->cal_id = (uint8_t)temp[2];
+ printk("--CWMCU-- cmd:%d type:%d id:%d\n", sensor->cal_cmd, sensor->cal_type, sensor->cal_id);
+ if (sensor->cal_cmd == CWMCU_CALIBRATOR_INFO) {
+ printk("--CWMCU-- set calibrator info\n");
+ data[0] = sensor->cal_id;
+ data[1] = sensor->cal_type;
+ CWMCU_bus_write(sensor, CwRegMapW_CalibratorEnable, data, 2);
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 0);
+ return count;
+}
+
+/* get calibrator data */
+static int get_calibrator_data0(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int i = 0;
+ uint8_t data[33] = {0};
+
+ if (sensor->mcu_mode == CW_BOOT) {
+ return ;
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 1);
+ printk("--CWMCU-- CWMCU_ACCELERATION_CALIBRATOR read data\n");
+ if (CWMCU_bus_read(sensor, CwRegMapRW_Calibrator_Data_Acceleration , &data[3], 30) < 0) {
+ printk(KERN_ERR "--CWMCU-- bus calibrator read fail!!! [ACC]\n");
+ data[0] = 255;
+ }else{
+ for (i = 0; i < 33; i++) {
+ printk("--CWMCU-- read data[%d] = %u\n", i, data[i]);
+ }
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 0);
+ return sprintf(buf, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ data[0], data[1], data[2],
+ data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
+ data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22],
+ data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32]);
+
+}
+
+static int set_calibrator_data0(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
+{
+ int i = 0;
+ uint8_t data[33] = {0};
+ int temp[33] = {0};
+
+ if (sensor->mcu_mode == CW_BOOT) {
+ return ;
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 1);
+
+ sscanf(buf, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
+ &temp[0], &temp[1], &temp[2],
+ &temp[3], &temp[4], &temp[5], &temp[6], &temp[7], &temp[8], &temp[9], &temp[10], &temp[11], &temp[12],
+ &temp[13], &temp[14], &temp[15], &temp[16], &temp[17], &temp[18], &temp[19], &temp[20], &temp[21], &temp[22],
+ &temp[23], &temp[24], &temp[25], &temp[26], &temp[27], &temp[28], &temp[29], &temp[30], &temp[31], &temp[32]);
+
+ for (i = 0; i < 33; i++) {
+ data[i] = (uint8_t)temp[i];
+ }
+ printk("--CWMCU-- CW_ACCELERATION_CALIBRATOR write data\n");
+ if (CWMCU_bus_write(sensor, CwRegMapRW_Calibrator_Data_Acceleration , &data[3], 30) >= 0) {
+ printk("CwMcu:%s:(%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d)\n",__FUNCTION__,
+ data[0], data[1], data[2],
+ data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
+ data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22],
+ data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32]
+ );
+ }else{
+ printk("CwMcu:%s:(bus write fail)\n",__FUNCTION__);
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 0);
+ return count;
+ }
+
+
+/* get calibrator data */
+static int get_calibrator_data1(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int i = 0;
+ uint8_t data[33] = {0};
+
+ if (sensor->mcu_mode == CW_BOOT) {
+ return ;
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 1);
+ printk("--CWMCU-- CWMCU_MAGNETIC_CALIBRATOR read data\n");
+ if (CWMCU_bus_read(sensor, CwRegMapRW_Calibrator_Data_Magnetioc , &data[3], 30) < 0) {
+ printk(KERN_ERR "--CWMCU-- bus calibrator read fail!!! [MAG]\n");
+ data[0] = 255;
+ }else{
+ printk("CWMCU:%s:(%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d)\n",__FUNCTION__,
+ data[0], data[1], data[2],
+ data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
+ data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22],
+ data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32]
+ );
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 0);
+ return sprintf(buf, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ data[0], data[1], data[2],
+ data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
+ data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22],
+ data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32]);
+}
+
+static int set_calibrator_data1(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
+{
+ int i = 0;
+ uint8_t data[33] = {0};
+ int temp[33] = {0};
+
+ if (sensor->mcu_mode == CW_BOOT) {
+ return ;
+ }
+
+ //TODO
+ return;
+
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 1);
+
+ sscanf(buf, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
+ &temp[0], &temp[1], &temp[2],
+ &temp[3], &temp[4], &temp[5], &temp[6], &temp[7], &temp[8], &temp[9], &temp[10], &temp[11], &temp[12],
+ &temp[13], &temp[14], &temp[15], &temp[16], &temp[17], &temp[18], &temp[19], &temp[20], &temp[21], &temp[22],
+ &temp[23], &temp[24], &temp[25], &temp[26], &temp[27], &temp[28], &temp[29], &temp[30], &temp[31], &temp[32]);
+
+ for (i = 0; i < 33; i++) {
+ data[i] = (uint8_t)temp[i];
+ }
+ printk("--CWMCU-- CWMCU_MAGNETIC_CALIBRATOR write data\n");
+ if (CWMCU_bus_write(sensor, CwRegMapRW_Calibrator_Data_Magnetioc , &data[3], 30) >= 0) {
+ printk("CwMcu:%s:(%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d)\n",__FUNCTION__,
+ data[0], data[1], data[2],
+ data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
+ data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22],
+ data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32]
+ );
+ }else{
+ printk("CwMcu:%s:(bus write fail)\n",__FUNCTION__);
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 0);
+ return count;
+}
+
+/* get calibrator data */
+
+static int get_calibrator_data2(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ uint8_t data[33] = {0};
+
+ if (sensor->mcu_mode == CW_BOOT) {
+ return ;
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 1);
+ if (CWMCU_bus_read(sensor, CwRegMapRW_Calibrator_Data_Gyro , &data[3], 30) < 0) {
+ printk("CwMcu:%s:(bus read fail)\n",__FUNCTION__);
+ data[0] = 255;
+ }else{
+ printk("CwMcu:%s:(%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d)\n",__FUNCTION__,
+ data[0], data[1], data[2],
+ data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
+ data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22],
+ data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32]
+ );
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 0);
+ return sprintf(buf, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ data[0], data[1], data[2],
+ data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
+ data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22],
+ data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32]);
+
+}
+
+static int set_calibrator_data2(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
+{
+ int i = 0;
+ uint8_t data[33] = {0};
+ int temp[33] = {0};
+
+ if (sensor->mcu_mode == CW_BOOT) {
+ return ;
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 1);
+
+ sscanf(buf, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
+ &temp[0], &temp[1], &temp[2],
+ &temp[3], &temp[4], &temp[5], &temp[6], &temp[7], &temp[8], &temp[9], &temp[10], &temp[11], &temp[12],
+ &temp[13], &temp[14], &temp[15], &temp[16], &temp[17], &temp[18], &temp[19], &temp[20], &temp[21], &temp[22],
+ &temp[23], &temp[24], &temp[25], &temp[26], &temp[27], &temp[28], &temp[29], &temp[30], &temp[31], &temp[32]);
+
+ for (i = 0; i < 33; i++) {
+ data[i] = (uint8_t)temp[i];
+ }
+ if (CWMCU_bus_write(sensor, CwRegMapRW_Calibrator_Data_Gyro , &data[3], 30) >= 0) {
+ printk("CwMcu:%s:(%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d)\n",__FUNCTION__,
+ data[0], data[1], data[2],
+ data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
+ data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22],
+ data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32]
+ );
+ }else{
+ printk("CwMcu:%s:(bus write fail)\n",__FUNCTION__);
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 0);
+ return count;
+}
+
+
+
+/* get calibrator data */
+static int get_calibrator_data3(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static int set_calibrator_data3(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
+{
+ return 0;
+}
+
+/* get calibrator data */
+static int get_calibrator_data4(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static int set_calibrator_data4(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
+{
+ return 0;
+}
+/* get calibrator data */
+static int get_calibrator_data5(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static int set_calibrator_data5(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
+{
+ return 0;
+}
+
+/* get calibrator data */
+static int get_calibrator_data6(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static int set_calibrator_data6(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
+{
+ return 0;
+}
+
+static int version_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ uint8_t data[4];
+ int16_t version = -1;
+ printk("--CWMCU-- %s\n", __func__);
+ cwmcu_powermode_switch(SWITCH_POWER_ENABLE, 1);
+ if (CWMCU_bus_read(sensor, CwRegMapR_REPORT_CHIP_ID, data, 4) >= 0) {
+ printk(KERN_DEBUG "CHECK_FIRMWAVE_VERSION : M:%u,D:%u,V:%u,SV:%u\n", data[3], data[2], data[1], data[0]);
+ version = (int16_t)( ((uint16_t)data[1])<<8 | (uint16_t)data[0]);
+ }else{
+ printk(KERN_DEBUG "CHECK_FIRMWAVE_VERSION Fail\n");
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_ENABLE, 0);
+ return snprintf(buf, sizeof(buf), "%d\n", version);
+}
+
+static int timestamp_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ uint8_t data[20];
+ uint32_t timestamp = 0, timebase = 0, timebasew = 0;
+ cwmcu_powermode_switch(SWITCH_POWER_TIME, 1);
+ if (CWMCU_bus_read(sensor, CwRegMapR_REPORT_SYSTEM_TIMESTAMP, data, 12) >= 0) {
+ timestamp = ((uint32_t)data[3])<<24 | ((uint32_t)data[2])<<16 | ((uint32_t)data[1])<<8 | ((uint32_t)data[0]);
+ timebase = ((uint32_t)data[7])<<24 | ((uint32_t)data[6])<<16 | ((uint32_t)data[5])<<8 | ((uint32_t)data[4]);
+ timebasew = ((uint32_t)data[11])<<24 | ((uint32_t)data[10])<<16 | ((uint32_t)data[9])<<8 | ((uint32_t)data[8]);
+ CW_INFO("%s:( Time:%d,Base:%d,Basew:%d)\n",__FUNCTION__, timestamp,timebase,timebasew);
+ buf[12] = 0;
+ memcpy(buf, data, 12);
+ }else{
+ buf[12] = 255;
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_TIME, 0);
+ return 13;
+}
+
+
+static DEVICE_ATTR(enable, 0660, active_show, active_set);
+static DEVICE_ATTR(delay_ms, 0660, interval_show, interval_set);
+/* static DEVICE_ATTR(poll, 0660, poll_show, NULL); */
+static DEVICE_ATTR(batch, 0660, batch_show, batch_set);
+static DEVICE_ATTR(flush, 0660, flush_show, flush_set);
+static DEVICE_ATTR(mcu_mode, 0660, mcu_mode_show, mcu_model_set);
+static DEVICE_ATTR(calibrator_cmd, 0660, get_calibrator_data, set_calibrator_data);
+static DEVICE_ATTR(calibrator_cmd0, 0660, get_calibrator_data0, set_calibrator_data0);
+static DEVICE_ATTR(calibrator_cmd1, 0660, get_calibrator_data1, set_calibrator_data1);
+static DEVICE_ATTR(calibrator_cmd2, 0660, get_calibrator_data2, set_calibrator_data2);
+static DEVICE_ATTR(calibrator_cmd3, 0660, get_calibrator_data3, set_calibrator_data3);
+static DEVICE_ATTR(calibrator_cmd4, 0660, get_calibrator_data4, set_calibrator_data4);
+static DEVICE_ATTR(calibrator_cmd5, 0660, get_calibrator_data5, set_calibrator_data5);
+static DEVICE_ATTR(calibrator_cmd6, 0660, get_calibrator_data6, set_calibrator_data6);
+static DEVICE_ATTR(firmware_update_i2c, 0660, get_firmware_update, set_firmware_update);
+static DEVICE_ATTR(firmware_update_cmd, 0660, NULL, set_firmware_update_cmd);
+static DEVICE_ATTR(firmware_update_data, 0660, NULL, set_firmware_update_data);
+static DEVICE_ATTR(firmware_update_status, 0660, get_firmware_update_status, NULL);
+static DEVICE_ATTR(version, 0660, version_show, NULL);
+static DEVICE_ATTR(timestamp, 0660, timestamp_show, NULL);
+
+
+static struct attribute *sysfs_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_delay_ms.attr,
+ /* &dev_attr_poll.attr, */
+ &dev_attr_batch.attr,
+ &dev_attr_flush.attr,
+ &dev_attr_calibrator_cmd.attr,
+ &dev_attr_calibrator_cmd0.attr,
+ &dev_attr_calibrator_cmd1.attr,
+ &dev_attr_calibrator_cmd2.attr,
+ &dev_attr_calibrator_cmd3.attr,
+ &dev_attr_calibrator_cmd4.attr,
+ &dev_attr_calibrator_cmd5.attr,
+ &dev_attr_calibrator_cmd6.attr,
+ &dev_attr_mcu_mode.attr,
+ &dev_attr_firmware_update_i2c.attr,
+ &dev_attr_firmware_update_cmd.attr,
+ &dev_attr_firmware_update_data.attr,
+ &dev_attr_firmware_update_status.attr,
+ &dev_attr_version.attr,
+ &dev_attr_timestamp.attr,
+ NULL
+};
+
+static struct attribute_group sysfs_attribute_group = {
+ .attrs = sysfs_attributes
+};
+/*=======factory mode=========*/
+void factory_active_sensor(int sensor_id, int enabled)
+{
+ int error_msg = 0;
+ uint8_t data[5];
+ int handle = NonWakeUpHandle;
+ static u32 fac_enabled_list = 0;
+
+#if 0
+ if (sensor_id == HEARTBEAT)
+ {
+ if (enabled)
+ {
+ hwPowerOn(MT6323_POWER_LDO_VGP3, VOL_1800, "sensorhub");
+ hwPowerOn(MT6323_POWER_LDO_VGP1, VOL_3300, "sensorhub");
+ }
+ else
+ {
+ hwPowerDown(MT6323_POWER_LDO_VGP3, "sensorhub");
+ hwPowerDown(MT6323_POWER_LDO_VGP1, "sensorhub");
+ }
+ }
+#endif
+ printk("factory_active_sensor ==> entry %d, %d, %d\n", sensor->mcu_mode, sensor_id, enabled);
+ if (sensor->mcu_mode == CW_BOOT) {
+ return ;
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_ENABLE, 1);
+ if(enabled){
+ mt_eint_mask(CUST_EINT_SENSORHUB_NUM);
+ fac_enabled_list |= 1<<sensor_id;
+ sensor->enabled_list |= 1<<sensor_id;
+ data[0] = NonWakeUpHandle;
+ data[1] = sensor_id;
+ data[2] = 40;
+ data[3] = 0;
+ data[4] = 0;
+ error_msg = CWMCU_bus_write(sensor, CwRegMapW_SET_ENABLE, data, 5);
+ if (error_msg < 0)
+ CW_ERROR("CwMcu: active bus error (%d)~!!\n", sensor_id);
+ }else{
+ fac_enabled_list &= ~(1<<sensor_id);
+ sensor->enabled_list &= ~(1<<sensor_id);
+ sensor->sensors_info[handle][sensor_id].rate = 0;
+ sensor->sensors_info[handle][sensor_id].timeout = 0;
+ data[0] = NonWakeUpHandle;
+ data[1] = sensor_id;
+ data[2] = 0;
+ data[3] = 0;
+ data[4] = 0;
+ error_msg = CWMCU_bus_write(sensor, CwRegMapW_SET_DISABLE, data, 5);
+ if (error_msg < 0)
+ CW_ERROR("CwMcu: de-active bus error (%d)~!!\n", sensor_id);
+ if (!fac_enabled_list)
+ mt_eint_unmask(CUST_EINT_SENSORHUB_NUM);
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_ENABLE, 0);
+ printk("CwMcu:%s id:%d, en:%d\n",__FUNCTION__, sensor_id, enabled);
+
+
+}
+
+int factory_data_read(int sensor_id, int data_event[])
+{
+ int id_check = 0;
+ int ret = 0;;
+ uint8_t data[9] = {0};
+ int retry = 0;
+
+ CW_DEBUG("factory_data_read ==> entry %d, %d\n", sensor->mcu_mode, sensor_id);
+
+ if (sensor->mcu_mode == CW_BOOT) {
+ /* it will not get data if status is bootloader mode */
+ return -1;
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 1);
+
+ if (CWMCU_bus_read(sensor, CwRegMapR_REPORT_DATA_START+sensor_id, data, 6) >= 0)
+ {
+
+ data_event[0] = (s16)(data[1] << 8 | data[0] + sensor->cali_data[sensor_id].x/10);
+ data_event[1] = (s16)(data[3] << 8 | data[2] + sensor->cali_data[sensor_id].y/10);
+ data_event[2] = (s16)(data[5] << 8 | data[4] + sensor->cali_data[sensor_id].z/10);
+ CW_DEBUG("factory_data_read: sensor(%d) -> x = %d, y = %d, z = %d"
+ , sensor_id , data_event[0], data_event[1], data_event[2]);
+ }
+ else
+ {
+ CW_ERROR("factory read error 0x%x~!!!", sensor_id);
+ ret = -1;
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_CALIB, 0);
+ return ret;
+}
+
+void factory_get_calibrator_data(int sensor_id, SENSOR_DATA *cali_data)
+{
+ cali_data->x = sensor->cali_data[sensor_id].x;
+ cali_data->y = sensor->cali_data[sensor_id].y;
+ cali_data->z = sensor->cali_data[sensor_id].z;
+ CW_DEBUG("[factory_get_calibrator_data]cali[%d]=(%d,%d,%d\)", sensor_id, cali_data->x, cali_data->y, cali_data->z);
+ }
+
+void factory_clear_calibrator_data(int sensor_id)
+{
+ sensor->cali_data[sensor_id].x = 0;
+ sensor->cali_data[sensor_id].y = 0;
+ sensor->cali_data[sensor_id].z = 0;
+ }
+
+int factory_set_calibrator_data(int sensor_id, SENSOR_DATA *cali_data)
+{
+ if (!cali_data){
+ CW_ERROR("[%s] no sensor data", __FUNCTION__);
+ return -1;
+ }
+
+ if (sensor_id == ACCELERATION)
+ {
+ // Pre-process accel data, correct reversed orientation on facotry calibration.
+ if (cali_data->z > 10*1000){
+ #define LIBHWM_GRAVITY_EARTH (9806)
+ int abs_orig_caliz, new_caliz;
+ CW_DEBUG("[factory_set_calibrator_data] original calibrator is (%d,%d,%d)", cali_data->x, cali_data->y, cali_data->z);
+ abs_orig_caliz = cali_data->z - LIBHWM_GRAVITY_EARTH;
+ cali_data->z = abs_orig_caliz - LIBHWM_GRAVITY_EARTH;
+ }
+ }
+
+ sensor->cali_data[sensor_id].x += cali_data->x;
+ sensor->cali_data[sensor_id].y += cali_data->y;
+ sensor->cali_data[sensor_id].z += cali_data->z;
+
+ CW_DEBUG("[factory_set_calibrator_data] final calibrator id=%d(%d,%d,%d)", sensor_id, cali_data->x, cali_data->y, cali_data->z);
+
+ return 0;
+ }
+
+/*=======input device==========*/
+
+static void CWMCU_init_input_device(struct CWMCU_data *sensor, struct input_dev *idev)
+{
+ idev->name = CWMCU_NAME;
+#if defined(CWMCU_I2C_INTERFACE)
+ idev->id.bustype = BUS_I2C;
+ idev->dev.parent = &sensor->client->dev;
+#elif defined(CWMCU_SPI_INTERFACE)
+ idev->id.bustype = BUS_SPI;
+ idev->dev.parent = &sensor->spi->dev;
+#endif
+ idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_ABS);
+ set_bit(EV_KEY, idev->evbit);
+
+ /* send mouse event */
+ set_bit(BTN_MOUSE, idev->keybit);
+ set_bit(EV_REL, idev->evbit);
+ set_bit(REL_X, idev->relbit);
+ set_bit(REL_Y, idev->relbit);
+ set_bit(EV_MSC, idev->evbit);
+ set_bit(MSC_SCAN, idev->mscbit);
+ set_bit(BTN_LEFT, idev->keybit);
+ set_bit(BTN_RIGHT, idev->keybit);
+
+ input_set_capability(idev, EV_KEY, 116);
+ input_set_capability(idev, EV_KEY, 102);
+ input_set_capability(idev, EV_KEY, KEY_POWER);
+
+ /*
+ input_set_capability(idev, EV_KEY, 88);
+ */
+ set_bit(EV_ABS, idev->evbit);
+ input_set_abs_params(idev, CW_ABS_X, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, CW_ABS_Y, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, CW_ABS_Z, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, CW_ABS_X1, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, CW_ABS_Y1, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, CW_ABS_Z1, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, CW_ABS_TIMEDIFF, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, CW_ABS_TIMEDIFF_WAKE_UP, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, CW_ABS_ACCURACY, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, CW_ABS_TIMEBASE, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, CW_ABS_TIMEBASE_WAKE_UP, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, REL_X, -DPS_MAX, DPS_MAX, 0, 0);
+ input_set_abs_params(idev, REL_Y, -DPS_MAX, DPS_MAX, 0, 0);
+
+}
+
+/*=======polling device=========*/
+static void CWMCU_poll(struct input_polled_dev *dev)
+{
+ CWMCU_read(dev->private);
+}
+
+static int CWMCU_open(struct CWMCU_data *sensor)
+{
+ int error;
+#if defined(CWMCU_I2C_INTERFACE)
+ error = pm_runtime_get_sync(&sensor->client->dev);
+#elif defined(CWMCU_SPI_INTERFACE)
+ error = pm_runtime_get_sync(&sensor->spi->dev);
+#endif
+
+ if (error && error != -ENOSYS)
+ return error;
+ return 0;
+}
+
+static void CWMCU_close(struct CWMCU_data *sensor)
+{
+#if defined(CWMCU_I2C_INTERFACE)
+ pm_runtime_put_sync(&sensor->client->dev);
+#elif defined(CWMCU_SPI_INTERFACE)
+ pm_runtime_put_sync(&sensor->spi->dev);
+#endif
+}
+
+static void CWMCU_poll_open(struct input_polled_dev *ipoll_dev)
+{
+ struct CWMCU_data *sensor = ipoll_dev->private;
+ CWMCU_open(sensor);
+}
+
+static void CWMCU_poll_close(struct input_polled_dev *ipoll_dev)
+{
+ struct CWMCU_data *sensor = ipoll_dev->private;
+ CWMCU_close(sensor);
+}
+
+static int CWMCU_register_input_device(struct CWMCU_data *sensor)
+{
+#if 0 //input Poll device
+ int error = -1;
+
+ struct input_polled_dev *ipoll_dev;
+
+ /* poll device */
+ ipoll_dev = input_allocate_polled_device();
+ if (!ipoll_dev)
+ return -ENOMEM;
+
+ ipoll_dev->private = sensor;
+ ipoll_dev->open = CWMCU_poll_open;
+ ipoll_dev->close = CWMCU_poll_close;
+ ipoll_dev->poll = CWMCU_poll;
+ ipoll_dev->poll_interval = CWMCU_POLL_INTERVAL;
+ ipoll_dev->poll_interval_min = CWMCU_POLL_MIN;
+ ipoll_dev->poll_interval_max = CWMCU_POLL_MAX;
+
+ CWMCU_init_input_device(sensor, ipoll_dev->input);
+
+ error = input_register_polled_device(ipoll_dev);
+ if (error) {
+ input_free_polled_device(ipoll_dev);
+ return error;
+ }
+
+ sensor->input_polled = ipoll_dev;
+ sensor->input = ipoll_dev->input;
+#else
+ sensor->input = input_allocate_device();
+ if(!sensor->input)
+ CW_ERROR("alloc input_dev error!");
+
+ CWMCU_init_input_device(sensor, sensor->input);
+ if (input_register_device(sensor->input))
+ CW_ERROR("input_register_device failed.(cwmcu)\n");
+
+#endif
+ return 0;
+}
+
+static void cwmcu_resume_work(struct work_struct *work)
+{
+ char cmd[10];
+
+ cwmcu_powermode_switch(SWITCH_POWER_PROBE, 1);
+ cwmcu_kernel_status(KERNEL_RESUND);
+
+ if (cw_tilt_wakeup_flag) {
+ //de-activate tilt wakeup
+ sprintf(cmd, "%d %d\n", TILT, 0);
+ active_set(NULL, NULL, cmd, sizeof(cmd));
+ CW_INFO("resume => disable tilt");
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_PROBE, 0);
+
+ CW_DEBUG("%s:end", __FUNCTION__);
+}
+
+void CWMCU_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int CWMCU_early_suspend(struct early_suspend *h)
+{
+ char cmd[10];
+
+ if (cw_tilt_wakeup_flag) {
+ //activate tilt wakeup
+ sprintf(cmd, "%d %d\n", TILT, 1);
+ active_set(NULL, NULL, cmd, sizeof(cmd));
+ CW_INFO("suspend => enable tilt");
+ }
+
+ cwmcu_powermode_switch(SWITCH_POWER_PROBE, 1);
+ cwmcu_kernel_status(KERNEL_SUPEND);
+ cwmcu_powermode_switch(SWITCH_POWER_PROBE, 0);
+
+ sensor->cw_suspend_flag= 1;
+ return 0;
+}
+
+void CWMCU_resume(struct device *dev)
+{
+ return 0;
+}
+
+static int CWMCU_late_resume(struct early_suspend *h)
+{
+ schedule_work(&sensor->resume_work);
+ return 0;
+}
+
+#ifdef CWMCU_INTERRUPT
+static void CWMCU_interrupt_thread(void)
+{
+ //mt_eint_mask(CUST_EINT_SENSORHUB_NUM);
+
+ if (sensor->mcu_mode == CW_BOOT) {
+ //CW_INFO("%s sensor->mcu_mode = %d", __func__, sensor->mcu_mode);
+ mt_eint_unmask(CUST_EINT_SENSORHUB_NUM);
+ return;
+ }
+ schedule_work(&sensor->work);
+
+ //mt_eint_unmask(CUST_EINT_SENSORHUB_NUM);
+ return;
+}
+
+static void cwmcu_work_report(struct work_struct *work)
+{
+ if (sensor->mcu_mode == CW_BOOT) {
+ printk("CwMcu:%s sensor->mcu_mode = %d\n", __func__, sensor->mcu_mode);
+ mt_eint_unmask(CUST_EINT_SENSORHUB_NUM);
+ return;
+ }
+ cwmcu_powermode_switch(SWITCH_POWER_INTERRUPT, 1);
+ cwmcu_interrupt_trigger(sensor);
+ cwmcu_powermode_switch(SWITCH_POWER_INTERRUPT, 0);
+ //printk("CwMcu:%s\n", __func__);
+ mt_eint_unmask(CUST_EINT_SENSORHUB_NUM);
+}
+
+#endif
+
+static void cwmcu_hw_config_init(struct CWMCU_data *sensor)
+{
+ int i = 0;
+ SensorsInit_T accel_hw_info = ACCEL_HW_INFO;
+ SensorsInit_T gyro_hw_info = GYRO_HW_INFO;
+
+ sensor->initial_hw_config = 0;
+ sensor->enabled_list = 0;
+ sensor->interrupt_status = 0;
+ sensor->power_on_list = 0;
+ sensor->cal_cmd = 0;
+ sensor->cal_type = 0;
+ sensor->cal_id = 0;
+ sensor->mcu_enable_list = 0;
+ sensor->mcu_hw_enable_list = 0;
+ for(i = 0;i<DRIVER_ID_END;i++){
+ sensor->hw_info[i].hw_id=HW_ID_END;
+ }
+#if 0
+ i = ACCELERATION;
+ sensor->hw_info[i].hw_id = BMI055;
+ sensor->hw_info[i].deviceaddr = 0x30;
+ sensor->hw_info[i].rate = 20;
+ sensor->hw_info[i].mode = 7;
+ sensor->hw_info[i].position = 6;
+ sensor->hw_info[i].private_setting[0] = 2;
+ sensor->hw_info[i].private_setting[1] = 4;
+ sensor->hw_info[i].private_setting[2] = 1;
+ sensor->hw_info[i].private_setting[3] = 0x0B;
+
+ i = GYRO;
+ sensor->hw_info[i].hw_id = BMI055;
+ sensor->hw_info[i].deviceaddr = 0xD0;
+ sensor->hw_info[i].rate = 20;
+ sensor->hw_info[i].mode = 8;
+ sensor->hw_info[i].position = 6;
+ sensor->hw_info[i].private_setting[0] = 0;
+ sensor->hw_info[i].private_setting[1] = 0;
+ sensor->hw_info[i].private_setting[2] = 0;
+ sensor->hw_info[i].private_setting[3] = 0;
+#else
+ sensor->hw_info[ACCELERATION] = accel_hw_info;
+ sensor->hw_info[GYRO] = gyro_hw_info;
+#endif
+}
+
+int CWMCU_probe(void *bus_dev)
+{
+ int error;
+ int i = 0;
+
+ CW_INFO("%s", __func__);
+
+ //VGP1
+ //hwPowerOn(MT6323_POWER_LDO_VGP3, VOL_1800, "sensorhub");
+ //hwPowerOn(MT6323_POWER_LDO_VGP1, VOL_3300, "sensorhub");
+
+
+ //initialize
+ mt_set_gpio_mode(GPIO_CW_MCU_BOOT, GPIO_SENSORHUB_HOST_BOOT_ROM_M_GPIO);
+ mt_set_gpio_dir(GPIO_CW_MCU_BOOT, GPIO_DIR_OUT);
+ mt_set_gpio_mode(GPIO_CW_MCU_RESET, GPIO_SENSORHUB_HOST_RESET_M_GPIO);
+ mt_set_gpio_dir(GPIO_CW_MCU_RESET, GPIO_DIR_OUT);
+ mt_set_gpio_mode(GPIO_CW_MCU_WAKE_UP, GPIO_SENSORHUB_WAKE_UP_M_GPIO);
+ mt_set_gpio_dir(GPIO_CW_MCU_WAKE_UP, GPIO_DIR_OUT);
+
+ /* mcu reset */
+ mt_set_gpio_out(GPIO_CW_MCU_RESET, 1);
+ mt_set_gpio_out(GPIO_CW_MCU_BOOT, 1);
+ msleep(100);
+ mt_set_gpio_out(GPIO_CW_MCU_BOOT, 0);
+ mt_set_gpio_out(GPIO_CW_MCU_RESET, 1);
+ msleep(100);
+ mt_set_gpio_out(GPIO_CW_MCU_RESET, 0);
+ msleep(100);
+ mt_set_gpio_out(GPIO_CW_MCU_RESET, 1);
+ msleep(100);
+
+ wake_lock_init(&cwmcu_wakelock, WAKE_LOCK_SUSPEND, "cwmcu suspend wakelock");
+
+ //mt_set_gpio_dir(GPIO_CW_MCU_RESET, GPIO_DIR_IN);
+
+ sensor = kzalloc(sizeof(struct CWMCU_data), GFP_KERNEL);
+ if (!sensor) {
+ CW_INFO("kzalloc error");
+ return -ENOMEM;
+ }
+
+
+ CWMCU_bus_init(bus_dev);
+
+ error = CWMCU_register_input_device(sensor);
+ if (error) {
+ CW_ERROR("CWMCU_register_input_device error");
+ goto err_free_mem;
+ }
+
+ error = sysfs_create_group(&sensor->input->dev.kobj,
+ &sysfs_attribute_group);
+ if (error)
+ goto exit_free_input;
+
+ cwmcu_hw_config_init(sensor);
+
+ cwmcu_powermode_switch(SWITCH_POWER_PROBE, 1);
+ cwmcu_kernel_status(KERNEL_PROBE);
+ cwmcu_powermode_switch(SWITCH_POWER_PROBE, 0);
+#ifdef CWMCU_INTERRUPT
+
+ CW_INFO("--CWMCU--sensor->irq =%d~!!", CUST_EINT_SENSORHUB_NUM);
+
+ if (CUST_EINT_SENSORHUB_NUM > 0) {
+ mt_set_gpio_mode(GPIO_SENSORHUB_EINT_PIN, GPIO_SENSORHUB_EINT_PIN_M_EINT);
+ mt_set_gpio_dir(GPIO_SENSORHUB_EINT_PIN, GPIO_DIR_IN);
+ mt_set_gpio_pull_enable(GPIO_SENSORHUB_EINT_PIN, GPIO_PULL_ENABLE);
+ mt_set_gpio_pull_select(GPIO_SENSORHUB_EINT_PIN, 1);
+
+ //mt_eint_set_sens(GPIO_SENSORHUB_EINT, MT_EDGE_SENSITIVE);
+ //mt_eint_set_hw_debounce(GPIO_SENSORHUB_EINT, CUST_EINT_SENSORHUB_DEBOUNCE_CN);
+ mt_eint_registration(CUST_EINT_SENSORHUB_NUM, EINTF_TRIGGER_FALLING, CWMCU_interrupt_thread, 0);
+
+ mt_eint_mask(CUST_EINT_SENSORHUB_NUM);
+ INIT_WORK(&sensor->work, cwmcu_work_report);
+ mt_eint_unmask(CUST_EINT_SENSORHUB_NUM);
+ }
+#endif
+
+ INIT_WORK(&sensor->resume_work, cwmcu_resume_work);
+ //factory
+ init_factory_node();
+ for(i = 0; i<SENSORS_ID_END; i++)
+ factory_clear_calibrator_data(i);
+
+
+ sensor->mcu_mode = CW_NORMAL;
+
+ CW_INFO("CWMCU_probe success!");
+
+ return 0;
+
+exit_free_input:
+ input_free_device(sensor->input);
+err_free_mem:
+exit_destroy_mutex:
+ free_irq(CUST_EINT_SENSORHUB_NUM, sensor);
+ kfree(sensor);
+ return error;
+}
+
+static int __init CWMCU_init(void){
+
+ int ret = 0;
+ CW_INFO("CWMCU_init");
+
+ cw_early_suspend_handler.suspend = CWMCU_early_suspend;
+ cw_early_suspend_handler.resume = CWMCU_late_resume;
+ register_early_suspend(&cw_early_suspend_handler);
+
+ ret = CWMCU_bus_register();
+ if (ret <0) {
+ CW_ERROR("CWMCU_init bus register error");
+ }
+ return ret;
+}
+
+static void __exit CWMCU_exit(void){
+ //unregister_early_suspend(&cw_early_suspend_handler);
+ CWMCU_bus_unregister();
+}
+
+module_init(CWMCU_init);
+module_exit(CWMCU_exit);
+
+MODULE_DESCRIPTION("CWMCU Bus Driver");
+MODULE_AUTHOR("CyWee Group Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor.h b/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor.h
new file mode 100644
index 000000000..edb9a51d2
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor.h
@@ -0,0 +1,457 @@
+/* CWMCU.h - header file for CyWee digital 3-axis gyroscope
+ *
+ * Copyright (C) 2010 CyWee Group Ltd.
+ * Author: Joe Wei <joewei@cywee.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+#ifndef __CWMCUSENSOR_H__
+#define __CWMCUSENSOR_H__
+#include <linux/ioctl.h>
+#include <linux/sensors_io.h>
+
+#define CWMCU_NAME "CwMcuSensor"
+#define LOG_TAG_KERNEL "CwMcuKernel"
+#define LOG_TAG_MCU "CwMcu"
+
+typedef enum {
+ NonWakeUpHandle= 0,
+ WakeUpHandle=1,
+ HANDLE_ID_END
+} HANDLE_ID;
+
+typedef enum {
+ ACCELERATION =0
+ ,MAGNETIC
+ ,GYRO
+ ,LIGHT
+ ,PROXIMITY
+ ,PRESSURE
+ ,HEARTBEAT
+ ,ORIENTATION
+ ,ROTATIONVECTOR
+ ,LINEARACCELERATION
+ ,GRAVITY
+ ,MAGNETIC_UNCALIBRATED
+ ,GYROSCOPE_UNCALIBRATED
+ ,GAME_ROTATION_VECTOR
+ ,GEOMAGNETIC_ROTATION_VECTOR
+ ,STEP_DETECTOR
+ ,STEP_COUNTER
+ ,SIGNIFICANT_MOTION
+ ,TILT
+ ,SENSORS_ID_END
+} SENSORS_ID;
+
+#define DRIVER_ID_END HEARTBEAT + 1
+
+typedef enum {
+ TimestampSync = SENSORS_ID_END+1
+ ,FLASH_DATA
+ ,META_DATA
+ ,MAGNETIC_UNCALIBRATED_BIAS
+ ,GYRO_UNCALIBRATED_BIAS
+ ,ERROR_MSG
+ ,BATCH_TIMEOUT
+ ,BATCH_FULL
+ ,ACCURACY_UPDATE
+ ,CALIBRATOR_UPDATE
+ ,MCU_REINITIAL
+ ,MCU_ENABLE_LIST
+ ,MCU_HW_ENABLE_LIST
+}MCU_TO_CPU_EVENT_TYPE;
+
+typedef enum {
+ L3GD20 = 1, //gyro
+ LSM303DLHC = 2, //acc + mag
+ LSM330 = 3, //acc + gyro
+ LPS331AP = 4, //pressure
+ BMP280 = 5, //pressure
+ AKM8963 = 6, //mag
+ YAS53x = 7, //mag
+ BMI055 = 8, //acc + gyro
+ AGD = 9, //acc + gyro
+ AMI = 10, //mag
+ LSM303D = 11, //acc + mag
+ CM36283 = 12,
+ APDS9960 = 13,
+ LSM6DS0 = 14, //acc + gyro
+ AKM09911 = 15, //mag
+ BMX055 = 16, //acc + gyro + mag
+ BMA250E = 17, //acc
+ BMI160 = 18, //acc + gyro
+ CUSTOMDRIVER = 19, //custom driver
+ PAH8001 = 20, //HEARTBEAT
+ CM36671 = 21, //Proximity
+ HW_ID_END,
+} HW_ID;
+
+enum ABS_status {
+ CW_ABS_X = 0x01,
+ CW_ABS_Y,
+ CW_ABS_Z,
+ CW_ABS_X1,
+ CW_ABS_Y1,
+ CW_ABS_Z1,
+ CW_ABS_TIMEDIFF,
+ CW_ABS_TIMEDIFF_WAKE_UP,
+ CW_ABS_ACCURACY,
+ CW_ABS_TIMEBASE,
+ CW_ABS_TIMEBASE_WAKE_UP
+};
+
+enum MCU_mode {
+ CW_NORMAL = 0x00,
+ CW_SLEEP,
+ CW_NO_SLEEP,
+ CW_BOOT
+};
+
+/* power manager status */
+typedef enum {
+ SWITCH_POWER_ENABLE = 0,
+ SWITCH_POWER_DELAY,
+ SWITCH_POWER_BATCH,
+ SWITCH_POWER_NORMAL,
+ SWITCH_POWER_CALIB,
+ SWITCH_POWER_INTERRUPT,
+ SWITCH_POWER_PROBE,
+ SWITCH_POWER_LOG,
+ SWITCH_POWER_FIRMWARE_COMMAND,
+ SWITCH_POWER_TIME
+} SWITCH_POWER_ID;
+
+typedef enum {
+ DRIVER_ENABLE_FAIL = -7,
+ DRIVER_DISABLE_FAIL = -6,
+ DRIVER_GETDATA_FAIL = -5,
+ I2C_FAIL = -4,
+ DRIVER_NO_USE = -3,
+ SENSORS_NO_INITIAL = -2,
+ FAIL = -1,
+ NO_ERROR = 0,
+ NO_DATA = 1
+} ERR_MSG;
+
+/* interrupt status */
+typedef enum {
+ INTERRUPT_NON = 0,
+ INTERRUPT_INIT = 1,
+ INTERRUPT_GESTURE = 2,
+ INTERRUPT_BATCHTIMEOUT = 3,
+ INTERRUPT_BATCHFULL = 4,
+ INTERRUPT_INFO = 5,
+ INTERRUPT_DATAREADY = 6,
+ INTERRUPT_TIMESYNC = 7,
+ INTERRUPT_LOGE = 8
+} INTERRUPT_STATUS_LIST;
+
+typedef enum {
+ KERNEL_NON = 0
+ ,KERNEL_PROBE
+ ,KERNEL_SUPEND
+ ,KERNEL_RESUND
+} KERNEL_STATUS;
+
+typedef enum {
+ CALIBRATOR_TYPE_NON = 0,
+ CALIBRATOR_TYPE_DEFAULT = 1,
+ CALIBRATOR_TYPE_SELFTEST = 2
+} CALIBRATOR_TYPE;
+
+typedef enum {
+ CALIBRATOR_STATUS_OUT_OF_RANGE= -2,
+ CALIBRATOR_STATUS_FAIL= -1,
+ CALIBRATOR_STATUS_NON = 0,
+ CALIBRATOR_STATUS_INPROCESS = 1,
+ CALIBRATOR_STATUS_PASS = 2,
+} CALIBRATOR_STATUS;
+
+/* calibrator command */
+typedef enum {
+ CWMCU_ACCELERATION_CALIBRATOR = 0,
+ CWMCU_MAGNETIC_CALIBRATOR,
+ CWMCU_GYRO_CALIBRATOR,
+ CWMCU_LIGHT_CALIBRATOR,
+ CWMCU_PROXIMITY_CALIBRATOR,
+ CWMCU_PRESSURE_CALIBRATOR,
+ CWMCU_CALIBRATOR_STATUS = 6,
+ CWMCU_CALIBRATOR_INFO = 7
+} CALIBRATOR_CMD;
+
+/* firmware update command */
+typedef enum {
+ CHANGE_TO_BOOTLOADER_MODE = 1,
+ ERASE_MCU_MEMORY,
+ WRITE_MCU_MEMORY,
+ MCU_GO,
+ CHANGE_TO_NORMAL_MODE = 5,
+ CHECK_FIRMWAVE_VERSION,
+ SET_DEBUG_LOG,
+ SET_SYSTEM_COMMAND,
+ GET_SYSTEM_TIMESTAMP,
+ GET_FUNCTION_ENTRY_POINT = 10,
+ GET_MCU_INFO,
+ SET_HW_INITIAL_CONFIG_FLAG,
+ SET_SENSORS_POSITION,
+ SHOW_LOG_INFO,
+ SET_TILT_WAKEUP,
+ GET_SENSORS_INDEX0 = 20,
+ GET_SENSORS_INDEX1,
+ GET_SENSORS_INDEX2,
+ GET_SENSORS_INDEX3,
+ GET_SENSORS_INDEX4,
+ GET_SENSORS_INDEX5,
+ GET_SENSORS_INDEX6,
+} FIRMWARE_CMD;
+
+typedef enum {
+ NonSystemComand= 0
+ ,WatchDogReset=1
+ ,SystemNoSleep=2
+ ,ShowMcuInfo=3
+ ,SystemShowLoge=4
+ ,SystemCommandIndexEnd
+} SYSTEM_COMMAND_INDEX;
+
+typedef enum {
+ //5Byte: 0:handle;1:id;2:Rate;[3:4]:timeout ms;
+ CwRegMapW_SET_ENABLE=0x01,
+ //5Byte: 0:handle;1:id;2:Rate;[3:4]:timeout ms;
+ CwRegMapW_SET_DISABLE=0x02,
+ //2Byte: 0:handle;1:id;
+ CwRegMapW_SET_FLUSH=0x04,
+ //2Byte(uint16_t)
+ //4Byte: enable list;
+ CwRegMapR_EnableList=0x05,
+ CwRegMapR_InterruptStatus=0x0F,
+ /**
+ * 10byte
+ * byte 0: sensors id
+ * byte 1: HwId
+ * byte 2: deviceaddr
+ * byte 3: rate
+ * byte 4: mode
+ * byte 5: position
+ * byte 6: private_setting[0]
+ * byte 7: private_setting[1]
+ * byte 8: private_setting[2]
+ * byte 9: private_setting[3]
+ */
+ CwRegMapRW_HW_SENSORS_CONFIG_START = 0x10 +ACCELERATION,
+ CwRegMapRW_HW_SENSORS_CONFIG_END = 0x10 +DRIVER_ID_END,
+ /**
+ * 2byte
+ * byte 0: sensors id
+ * byte 1: position
+ */
+ CwRegMapW_HW_SENSORS_POSITION = 0x1F,
+ /**
+ * 2byte
+ * count
+ * byte 0: count L
+ * byte 1: count H
+ *
+ * 9byte
+ * event
+ * byte 0: sensors id
+ * byte 1: sensors X L
+ * byte 2: sensors X H
+ * byte 3: sensors Y L
+ * byte 4: sensors Y H
+ * byte 5: sensors Z L
+ * byte 6: sensors Z H
+ * byte 7: timestamp L
+ * byte 8: timestamp H
+ */
+
+ CwRegMapR_StreamCount=0x20,
+ CwRegMapR_StreamEvent=0x21,
+ CwRegMapR_BatchCount=0x22,
+ CwRegMapR_BatchEvent=0x23,
+
+ /**
+ * 1byte
+ * count
+ *
+ * 4byte
+ * byte 0: Type
+ * byte 1: id
+ * byte 2: error message (int8_t)
+ * byte 3: error status (int8_t)
+ */
+ CwRegMapR_InteruptCount=0x24,
+ CwRegMapR_InteruptEvent=0x25,
+
+ /**
+ * 2byte
+ * count
+ *
+ * 30byte
+ * Log
+ */
+ CwRegMapR_SystemInfoMsgCount = 0x26,
+ CwRegMapR_SystemInfoMsgEvent = 0x27,
+
+ /**
+ * 2byte
+ * byte 0: Sensors Id
+ * byte 1: Sensors Type
+ *
+ * wbyte
+ * Calibrator Status
+ * byte 0: Sensors Id
+ * byte 1: Sensors Status
+ */
+ CwRegMapW_CalibratorEnable = 0x40,
+ CwRegMapR_CalibratorStatus = 0x41,
+
+ CwRegMapRW_Calibrator_Data_Acceleration =0x43,
+ CwRegMapRW_Calibrator_Data_Magnetioc =0x44,
+ CwRegMapRW_Calibrator_Data_Gyro =0x45,
+ CwRegMapRW_Calibrator_Data_Light =0x46,
+ CwRegMapRW_Calibrator_Data_Proximity =0x47,
+ CwRegMapRW_Calibrator_Data_Pressure =0x48,
+
+ /**
+ * 1byte
+ */
+ CwRegMapW_SystemCommand = 0x5A,
+ CwRegMapW_KERNEL_STATUS = 0x5B,
+
+ /**
+ * 6byte
+ * data
+ */
+ CwRegMapR_REPORT_DATA_START = 0x60 +ACCELERATION, //ACCELERATION
+ CwRegMapR_REPORT_DATA_END = 0x60 +SENSORS_ID_END, //ACCELERATION
+
+
+ /**
+ * 4byte
+ * data[0] = BuildSubVersion;
+ * data[1] = BuildVersion;
+ * data[2] = BuildDay;
+ * data[3] = BuildMonth;
+ * data
+ */
+ CwRegMapR_REPORT_CHIP_ID = 0x80,
+ CwRegMapR_REPORT_SYSTEM_TIMESTAMP = 0x81,
+
+ /** * 64byte * data */
+ CwRegMapR_REPORT_MAG_LOG = 0x8A,
+
+ CwRegMapW_TIMESTAMP_SYNC = 0xA0,
+ CwRegMapR_FunctionEntryPoint = 0xA1,
+ CW_MAX_REG
+} CwRegisterMapIndex;
+/* check data of queue if queue is empty */
+
+struct CWMCU_SENSORS_INFO{
+ uint8_t en;
+ uint8_t mode;
+ uint8_t rate;
+ uint16_t timeout;
+};
+
+typedef struct {
+ uint8_t hw_id;
+ uint8_t deviceaddr;
+ uint8_t rate;
+ uint8_t mode; //default: MODE_BYPASS
+ uint8_t position;
+ uint8_t private_setting[4]; //private_setting[2] = INTERRUPT_SETTING
+ }SensorsInit_T;
+
+
+struct CWMCU_data {
+ struct i2c_client *client;
+ struct spi_device *spi;
+ struct regulator *vdd;
+ struct regulator *vcc_i2c;
+ struct input_polled_dev *input_polled;
+ struct input_dev *input;
+ struct workqueue_struct *driver_wq;
+ struct work_struct work;
+ struct work_struct resume_work;
+ struct CWMCU_SENSORS_INFO sensors_info[HANDLE_ID_END][SENSORS_ID_END];
+ SensorsInit_T hw_info[DRIVER_ID_END];
+ uint8_t initial_hw_config;
+
+ int mcu_mode;
+ uint8_t kernel_status;
+
+ /* enable & batch list */
+ uint32_t enabled_list;
+ uint32_t interrupt_status;
+
+ /* Mcu site enable list*/
+ uint32_t mcu_enable_list;
+ uint32_t mcu_hw_enable_list;
+
+ /* power status */
+ volatile uint32_t power_on_list;
+ int interrupt_check_count;
+
+ /* Calibrator status */
+ uint8_t cal_cmd;
+ uint8_t cal_type;
+ uint8_t cal_id;
+
+ /* gpio */
+ int irq_gpio;
+ int wakeup_gpio;
+
+ uint32_t debug_log;
+
+ int cmd;
+ uint32_t addr;
+ int len;
+ int mcu_slave_addr;
+ int firmwave_update_status;
+ int cw_bus_rw; /* r = 0 , w = 1 */
+ int cw_bus_len;
+ uint8_t cw_bus_data[300];
+ uint8_t report_count;
+ int cw_suspend_flag;
+
+ /*calibration*/
+ SENSOR_DATA cali_data[SENSORS_ID_END];
+};
+#define CWMCU_NODATA 0xff
+
+#define DPS_MAX (1 << (16 - 1))
+#ifdef __KERNEL__
+
+#endif /* __KERNEL */
+
+#define CW_INFO(fmt,arg...) printk("-CWMCU_INF- "fmt"\n",##arg)
+#define CW_ERROR(fmt,arg...) printk("-CWMCU_ERR- "fmt"\n",##arg)
+#define CW_DEBUG(fmt,arg...) printk("-CWMCU_DBG- "fmt"\n",##arg)
+
+extern int CWMCU_bus_register(void);
+extern void CWMCU_bus_unregister(void);
+extern int CWMCU_bus_write_serial(u8 *data, int len);
+extern int CWMCU_bus_read_serial(u8 *data, int len);
+extern int CWMCU_bus_read(struct CWMCU_data *sensor, u8 reg_addr, u8 *data, u8 len);
+extern int CWMCU_bus_write(struct CWMCU_data *sensor, u8 reg_addr, u8 *data, u8 len);
+extern void CWMCU_bus_init(void *bus_dev);
+extern int CWMCU_probe(void *bus_dev);
+extern void CWMCU_suspend(struct device *dev);
+extern void CWMCU_resume(struct device *dev);
+extern void factory_active_sensor(int sensor_id, int enabled);
+extern int factory_data_read(int sensor_id, int data_event[]);
+extern int factory_set_calibrator_data(int sensor_id, SENSOR_DATA *cali_data);
+extern void factory_clear_calibrator_data(int sensor_id);
+extern void factory_get_calibrator_data(int sensor_id, SENSOR_DATA *cali_data);
+extern void init_factory_node();
+extern int spi_rw_bytes_serial(u8 *wbuf, u8 *rbuf, u8 len);
+#endif /* __CWMCUSENSOR_H__ */
diff --git a/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor_factory.c b/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor_factory.c
new file mode 100644
index 000000000..4e7cf21c4
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor_factory.c
@@ -0,0 +1,474 @@
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/earlysuspend.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <asm/atomic.h>
+#include <mach/mt_typedefs.h>
+#include <mach/mt_gpio.h>
+#include <mach/mt_pm_ldo.h>
+#include <linux/sensors_io.h>
+#include "CwMcuSensor.h"
+#include <cust_cwmcu.h>
+
+#define SAVE_PATH_ACC "/data/system/cw_calibrator_acc.ini"
+#define SAVE_PATH_MAG "/data/system/cw_calibrator_mag.ini"
+#define SAVE_PATH_GYR "/data/system/cw_calibrator_gyr.ini"
+#define SAVE_PATH_LIGHT "/data/system/cw_calibrator_light.ini"
+#define SAVE_PATH_PROXIMITY "/data/system/cw_calibrator_proximity.ini"
+
+//===============================================================
+// gsensor
+static int cw_accel_open(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(ACCELERATION, 1);
+ return nonseekable_open(inode, file);
+}
+
+static int cw_accel_release(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(ACCELERATION, 0);
+ file->private_data = NULL;
+ return 0;
+}
+//========================
+// gyroscope
+static int cw_gyro_open(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(GYRO, 1);
+ return nonseekable_open(inode, file);
+}
+
+static int cw_gyro_release(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(GYRO, 0);
+ file->private_data = NULL;
+ return 0;
+}
+//========================
+// msensor
+static int cw_mag_open(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(MAGNETIC, 1);
+ return nonseekable_open(inode, file);
+}
+
+static int cw_mag_release(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(MAGNETIC, 0);
+ file->private_data = NULL;
+ return 0;
+}
+
+//========================
+// alsps
+static int cw_alsps_open(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(LIGHT, 1);
+ factory_active_sensor(PROXIMITY, 1);
+ return nonseekable_open(inode, file);
+}
+
+static int cw_alsps_release(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(LIGHT, 0);
+ factory_active_sensor(PROXIMITY, 0);;
+ file->private_data = NULL;
+ return 0;
+}
+
+//========================
+// barometer
+static int cw_barometer_open(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(PRESSURE, 1);
+ return nonseekable_open(inode, file);
+}
+
+static int cw_barometer_release(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(PRESSURE, 0);;
+ file->private_data = NULL;
+ return 0;
+}
+//========================
+// heart rate monitor
+static int cw_hrm_open(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(HEARTBEAT, 1);
+ return nonseekable_open(inode, file);
+}
+
+static int cw_hrm_release(struct inode *inode, struct file *file)
+{
+ factory_active_sensor(HEARTBEAT, 0);;
+ file->private_data = NULL;
+ return 0;
+}
+
+//========================
+static long cw_factory_ioctl(struct file *file, unsigned int cmd,unsigned long arg)
+{
+ int data_event[3] = {0};
+ char strbuf[256];
+ void __user *data;
+ int err = 0;
+ SENSOR_DATA sensor_data = {0};
+
+ //CW_DEBUG("[FACTORY]factory ioctl, cmd=0x%8x", cmd);
+ if(_IOC_DIR(cmd) & _IOC_READ)
+ {
+ err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
+ }
+ else if(_IOC_DIR(cmd) & _IOC_WRITE)
+ {
+ err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
+ }
+
+ if(err)
+ {
+ CW_ERROR("[FACTORY]access error: %08X, (%2d, %2d)\n", cmd, _IOC_DIR(cmd), _IOC_SIZE(cmd));
+ return -EFAULT;
+ }
+
+ data = (void __user *) arg;
+ if(data == NULL)
+ {
+ return -EINVAL;
+ }
+
+ switch(cmd)
+ {
+ //GSENSOR
+ case GSENSOR_IOCTL_READ_SENSORDATA:
+ CW_DEBUG("cw_factory_ioctl: GSENSOR_IOCTL_READ_SENSORDATA");
+ if (factory_data_read(ACCELERATION, data_event) < 0)
+ {
+ CW_ERROR("[FACTORY] accel read data failed");
+ }
+ CW_DEBUG("[FACTORY] accel data[]={%d %d %d}", data_event[0]*10, data_event[1]*10, data_event[2]*10);
+ sprintf(strbuf, "%4x %4x %4x", data_event[0]*10, data_event[1]*10, data_event[2]*10);
+ if(copy_to_user(data, strbuf, strlen(strbuf)+1))
+ {
+ err = -EFAULT;
+ break;
+ }
+ break;
+ case GSENSOR_IOCTL_CLR_CALI:
+ CW_INFO("[FACTORY] clear calibration data");
+ factory_clear_calibrator_data(ACCELERATION);
+ break;
+ case GSENSOR_IOCTL_SET_CALI:
+ CW_INFO("[FACTORY] GSENSOR_IOCTL_SET_CALI");
+ if (copy_from_user(&sensor_data, data, sizeof(sensor_data)))
+ {
+ CW_INFO("[FACTORY] ACCEL calibration data failed");
+ err = -EFAULT;
+ break;
+ }
+
+ CW_INFO("GSENSOR_IOCTL_SET_CALI data : (%d, %d, %d)!\n", sensor_data.x, sensor_data.y, sensor_data.z);
+
+ factory_set_calibrator_data(ACCELERATION, &sensor_data);
+ break;
+ case GSENSOR_IOCTL_GET_CALI:
+ CW_INFO("[FACTORY] GSENSOR_IOCTL_GET_CALI");
+ factory_get_calibrator_data(ACCELERATION, &sensor_data);
+
+ copy_to_user(data, &sensor_data, sizeof(sensor_data));
+ break;
+
+ //GYROSCOPE
+ case GYROSCOPE_IOCTL_READ_SENSORDATA:
+ CW_DEBUG("cw_factory_ioctl: GYROSCOPE_IOCTL_READ_SENSORDATA");
+ if (factory_data_read(GYRO, data_event) < 0)
+ {
+ CW_ERROR("[FACTORY] gyro read data failed");
+ }
+ CW_DEBUG("[FACTORY] gyro data[]={%d %d %d}", data_event[0]*10, data_event[1]*10, data_event[2]*10);
+ sprintf(strbuf, "%4x %4x %4x", data_event[0]*10, data_event[1]*10, data_event[2]*10);
+ if(copy_to_user(data, strbuf, strlen(strbuf)+1))
+ {
+ err = -EFAULT;
+ break;
+ }
+ break;
+ case GYROSCOPE_IOCTL_CLR_CALI:
+ CW_INFO("[FACTORY] clear calibration data");
+ factory_clear_calibrator_data(GYRO);
+ break;
+ case GYROSCOPE_IOCTL_SET_CALI:
+ CW_INFO("[FACTORY] GYROSCOPE_IOCTL_SET_CALI");
+ if (copy_from_user(&sensor_data, data, sizeof(sensor_data)))
+ {
+ CW_INFO("[FACTORY] Gyro calibration data failed");
+ err = -EFAULT;
+ break;
+ }
+
+ CW_INFO("GYROSCOPE_IOCTL_SET_CALI data : (%d, %d, %d)!\n", sensor_data.x, sensor_data.y, sensor_data.z);
+
+ factory_set_calibrator_data(GYRO, &sensor_data);
+ break;
+
+ case GYROSCOPE_IOCTL_GET_CALI:
+ CW_INFO("[FACTORY] GYROSCOPE_IOCTL_GET_CALI");
+ factory_get_calibrator_data(GYRO, &sensor_data);
+
+ copy_to_user(data, &sensor_data, sizeof(sensor_data));
+ break;
+
+ //MSENSOR
+ case MSENSOR_IOCTL_READ_FACTORY_SENSORDATA :
+ CW_DEBUG("cw_factory_ioctl: MSENSOR_IOCTL_READ_FACTORY_SENSORDATA");
+ break;
+ case MSENSOR_IOCTL_READ_SENSORDATA:
+ CW_DEBUG("cw_factory_ioctl: MSENSOR_IOCTL_READ_SENSORDATA");
+ if (factory_data_read(MAGNETIC, data_event) < 0)
+ {
+ CW_ERROR("[FACTORY] msensor read data failed");
+ }
+ CW_DEBUG("[FACTORY] CW_MAGNETIC data[]={%d %d %d}", data_event[0], data_event[1], data_event[2]);
+ sprintf(strbuf, "%4x %4x %4x", data_event[0]/100, data_event[1]/100, data_event[2]/100);
+ if(copy_to_user(data, strbuf, strlen(strbuf)+1))
+ {
+ err = -EFAULT;
+ break;
+ }
+ break;
+
+ //ALSPS
+ case ALSPS_SET_PS_MODE:
+ case ALSPS_SET_ALS_MODE:
+ case ALSPS_GET_ALS_RAW_DATA:
+ break;
+ case ALSPS_GET_PS_RAW_DATA:
+ CW_DEBUG("cw_factory_ioctl: ALSPS_GET_PS_RAW_DATA");
+ if (factory_data_read(PROXIMITY, data_event) < 0)
+ {
+ CW_ERROR("[FACTORY] PS read data failed");
+ }
+ CW_DEBUG("[FACTORY] CW_PROXIMITY data[]={%d %d %d}", data_event[0], data_event[1], data_event[2]);
+ if(copy_to_user(data, &data_event[0], sizeof(int)))
+ {
+ err = -EFAULT;
+ break;
+ }
+ break;
+ case ALSPS_GET_PS_THRESHOLD_HIGH:
+ CW_DEBUG("cw_factory_ioctl: ALSPS_GET_PS_THRESHOLD_HIGH");
+ data_event[0] = PS_HIGH_THRESHOLD;
+ if(copy_to_user(data, &data_event[0], sizeof(int)))
+ {
+ err = -EFAULT;
+ break;
+ }
+ break;
+ case ALSPS_GET_PS_THRESHOLD_LOW:
+ CW_DEBUG("cw_factory_ioctl: ALSPS_GET_PS_THRESHOLD_LOW");
+ data_event[0] = PS_LOW_THRESHOLD;
+ if(copy_to_user(data, &data_event[0], sizeof(int)))
+ {
+ err = -EFAULT;
+ break;
+ }
+ break;
+ case ALSPS_GET_PS_TEST_RESULT:
+ CW_DEBUG("cw_factory_ioctl: ALSPS_GET_PS_TEST_RESULT");
+ factory_data_read(PROXIMITY, data_event);
+ data_event[0] = (data_event[0] > PS_HIGH_THRESHOLD) ? 0 : 1;
+ if(copy_to_user(data, &data_event[0], sizeof(int)))
+ {
+ err = -EFAULT;
+ break;
+ }
+ break;
+ //BAROMETER
+ case BAROMETER_GET_TEMP_DATA:
+ CW_DEBUG("cw_factory_ioctl: BAROMETER_GET_TEMP_DATA");
+ break;
+ case BAROMETER_GET_PRESS_DATA:
+ CW_DEBUG("cw_factory_ioctl: BAROMETER_GET_PRESS_DATA");
+ if (factory_data_read(PRESSURE, data_event) < 0)
+ {
+ CW_ERROR("[FACTORY] PS read data failed");
+ }
+ data_event[0] *= 10;
+ CW_DEBUG("[FACTORY] CW_PROXIMITY data[]={%d %d %d}", data_event[0]*10, data_event[1], data_event[2]);
+ if(copy_to_user(data, &data_event[0], sizeof(int)))
+ {
+ err = -EFAULT;
+ break;
+ }
+ break;
+
+ //HEARTRATE
+ case HRM_READ_SENSOR_DATA:
+ CW_DEBUG("cw_factory_ioctl: HRM_READ_SENSOR_DATA");
+ if (factory_data_read(HEARTBEAT, data_event) < 0)
+ {
+ CW_ERROR("[FACTORY] HRM read data failed");
+ }
+
+ CW_DEBUG("[FACTORY] CW_HEARTRATE_MONITOR data[]={%d %d %d}", data_event[0], data_event[1], data_event[2]);
+ sprintf(strbuf, "%d %d %d", data_event[0], data_event[1], data_event[2]);
+ if(copy_to_user(data, strbuf, strlen(strbuf)+1))
+ {
+ err = -EFAULT;
+ break;
+ }
+ break;
+
+ default:
+ CW_INFO("[FACTORY]unknown IOCTL: 0x%08x\n", cmd);
+ break;
+
+ }
+
+ return err;
+}
+
+//========================
+//accelerometer
+static struct file_operations cw_accel_fops = {
+ .owner = THIS_MODULE,
+ .open = cw_accel_open,
+ .release = cw_accel_release,
+ .unlocked_ioctl = cw_factory_ioctl,
+};
+
+static struct miscdevice cw_accel_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "gsensor",
+ .fops = &cw_accel_fops,
+};
+//========================
+//gyroscope
+static struct file_operations cw_gyro_fops = {
+ .owner = THIS_MODULE,
+ .open = cw_gyro_open,
+ .release = cw_gyro_release,
+ .unlocked_ioctl = cw_factory_ioctl,
+};
+
+static struct miscdevice cw_gyro_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "gyroscope",
+ .fops = &cw_gyro_fops,
+};
+//========================
+//msensor
+static struct file_operations cw_mag_fops = {
+ .owner = THIS_MODULE,
+ .open = cw_mag_open,
+ .release = cw_mag_release,
+ .unlocked_ioctl = cw_factory_ioctl,
+};
+
+static struct miscdevice cw_mag_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msensor",
+ .fops = &cw_mag_fops,
+};
+//========================
+//ALSPS
+static struct file_operations cw_alsps_fops = {
+ .owner = THIS_MODULE,
+ .open = cw_alsps_open,
+ .release = cw_alsps_release,
+ .unlocked_ioctl = cw_factory_ioctl,
+};
+
+static struct miscdevice cw_alsps_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "als_ps",
+ .fops = &cw_alsps_fops,
+};
+//========================
+//Barometer
+static struct file_operations cw_barometer_fops = {
+ .owner = THIS_MODULE,
+ .open = cw_barometer_open,
+ .release = cw_barometer_release,
+ .unlocked_ioctl = cw_factory_ioctl,
+};
+
+static struct miscdevice cw_barometer_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "barometer",
+ .fops = &cw_barometer_fops,
+};
+//========================
+//Heart Rate Monitor
+static struct file_operations cw_hrm_fops = {
+ .owner = THIS_MODULE,
+ .open = cw_hrm_open,
+ .release = cw_hrm_release,
+ .unlocked_ioctl = cw_factory_ioctl,
+};
+
+static struct miscdevice cw_hrm_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "hrm",
+ .fops = &cw_hrm_fops,
+};
+
+//===============================================================
+void init_factory_node(void)
+{
+ int err;
+
+ //accel
+ err = misc_register(&cw_accel_device);
+ if (0 != err)
+ {
+ CW_ERROR("[FACTORY]init accel factory device node error");
+ }
+
+ //gyroscope
+ err = misc_register(&cw_gyro_device);
+ if (0 != err)
+ {
+ CW_ERROR("[FACTORY]init gyroscope factory device node error");
+ }
+
+ //msensor
+ err = misc_register(&cw_mag_device);
+ if (0 != err)
+ {
+ CW_ERROR("[FACTORY]init msensor factory device node error");
+ }
+
+ //alsps
+ err = misc_register(&cw_alsps_device);
+ if (0 != err)
+ {
+ CW_ERROR("[FACTORY]init alsps factory device node error");
+ }
+
+ //barometer
+ err = misc_register(&cw_barometer_device);
+ if (0 != err)
+ {
+ CW_ERROR("[FACTORY]init barometer factory device node error");
+ }
+
+ //heart rate monitor
+ err = misc_register(&cw_hrm_device);
+ if (0 != err)
+ {
+ CW_ERROR("[FACTORY]init hrm factory device node error");
+ }
+
+ CW_INFO("init factory node done!!");
+}
+
+
diff --git a/drivers/misc/mediatek/sensorHub/CwMcuSensor/Makefile b/drivers/misc/mediatek/sensorHub/CwMcuSensor/Makefile
new file mode 100755
index 000000000..688aa4a26
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/CwMcuSensor/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the input misc drivers.
+#
+
+# Each configuration option enables a list of files.
+include $(srctree)/drivers/misc/mediatek/Makefile.custom
+ccflags-y += -I$(MTK_PROJECT_PATH_ROOT)/sensorhub/cwmcusensor
+
+obj-y += CwMcuSensor.o CwMcuSensor_factory.o CwMcuBus.o
diff --git a/drivers/misc/mediatek/sensorHub/Makefile b/drivers/misc/mediatek/sensorHub/Makefile
new file mode 100755
index 000000000..060b79169
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/Makefile
@@ -0,0 +1,14 @@
+include $(srctree)/drivers/misc/mediatek/Makefile.custom
+
+# In case the platform does NOT support this type of sensors
+
+### Workaround ###
+ifneq ($(CONFIG_ARCH_MT2601),y)
+obj-y += SCP_sensorHub/
+obj-y += SCP_shf/
+else
+obj-y += CwMcuSensor/
+endif
+ifeq ($(CONFIG_CUSTOM_KERNEL_SENSORHUB),"OTHER_VENDOR")
+obj-y += other_vendor/
+endif
diff --git a/drivers/misc/mediatek/sensorHub/SCP_sensorHub/Makefile b/drivers/misc/mediatek/sensorHub/SCP_sensorHub/Makefile
new file mode 100755
index 000000000..72f53b053
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/SCP_sensorHub/Makefile
@@ -0,0 +1,4 @@
+include $(srctree)/drivers/misc/mediatek/Makefile.custom
+
+obj-y := SCP_sensorHub.o
+
diff --git a/drivers/misc/mediatek/sensorHub/SCP_sensorHub/SCP_sensorHub.c b/drivers/misc/mediatek/sensorHub/SCP_sensorHub/SCP_sensorHub.c
new file mode 100644
index 000000000..945182f8e
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/SCP_sensorHub/SCP_sensorHub.c
@@ -0,0 +1,2569 @@
+/* SCP sensor hub driver
+ *
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+
+ * (C) Copyright 2011 Bosch Sensortec GmbH
+ * All Rights Reserved
+ */
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/earlysuspend.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <asm/atomic.h>
+
+//#include <mach/mt_devs.h>
+#include <mach/mt_typedefs.h>
+#include <mach/mt_gpio.h>
+#include <mach/mt_pm_ldo.h>
+
+#include "step_counter.h"
+#include "pedometer.h"
+#include "activity.h"
+#include "in_pocket.h"
+#include "face_down.h"
+#include "pick_up.h"
+#include "shake.h"
+#include "heart_rate.h"
+#include "tilt_detector.h"
+#include "wake_gesture.h"
+#include "glance_gesture.h"
+#include <linux/batch.h>
+#include <mach/md32_ipi.h>
+#include <mach/md32_helper.h>
+#include <linux/time.h>
+
+#define POWER_NONE_MACRO MT65XX_POWER_NONE
+
+#include <cust_sensorHub.h>
+#include <linux/hwmsensor.h>
+#include <linux/hwmsen_dev.h>
+#include <linux/sensors_io.h>
+#include "SCP_sensorHub.h"
+#include "cust_sensorHub.h"
+#include <linux/hwmsen_helper.h>
+#include <mach/mt_clkmgr.h>
+/*----------------------------------------------------------------------------*/
+//#define DEBUG 1
+//#define SENSORHUB_UT
+/*----------------------------------------------------------------------------*/
+//#define CONFIG_SCP_sensorHub_LOWPASS /*apply low pass filter on output*/
+#define SW_CALIBRATION
+/*----------------------------------------------------------------------------*/
+#define SCP_sensorHub_AXIS_X 0
+#define SCP_sensorHub_AXIS_Y 1
+#define SCP_sensorHub_AXIS_Z 2
+#define SCP_sensorHub_AXES_NUM 3
+#define SCP_sensorHub_DATA_LEN 6
+#define SCP_sensorHub_DEV_NAME "SCP_sensorHub"
+
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_probe(void);
+static int SCP_sensorHub_remove(void);
+//static int SCP_sensorHub_suspend(struct platform_device *dev, pm_message_t state);
+//static int SCP_sensorHub_resume(struct platform_device *dev);
+
+static int SCP_sensorHub_local_init(void);
+#ifdef CONFIG_CUSTOM_KERNEL_STEP_COUNTER
+static void SCP_sd_work(struct work_struct *work);
+static void SCP_sig_work(struct work_struct *work);
+static struct wake_lock sig_lock;
+static int SCP_sensorHub_step_counter_init(void);
+static int SCP_sensorHub_step_counter_uninit(void);
+static void notify_ap_timeout(unsigned long);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_STEP_COUNTER
+
+#ifdef CONFIG_CUSTOM_KERNEL_IN_POCKET_SENSOR
+static void SCP_inpk_work(struct work_struct *work);
+static int SCP_sensorHub_in_pocket_init(void);
+static int SCP_sensorHub_in_pocket_uninit(void);
+#endif //CONFIG_CUSTOM_KERNEL_IN_POCKET_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_PEDOMETER
+//static void SCP_pdr_work(struct work_struct *work);
+static int SCP_sensorHub_pedometer_init(void);
+static int SCP_sensorHub_pedometer_uninit(void);
+#endif //CONFIG_CUSTOM_KERNEL_PEDOMETER
+#ifdef CONFIG_CUSTOM_KERNEL_ACTIVITY_SENSOR
+//static void SCP_act_work(struct work_struct *work);
+static int SCP_sensorHub_activity_init(void);
+static int SCP_sensorHub_activity_uninit(void);
+#endif //CONFIG_CUSTOM_KERNEL_ACTIVITY_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_SHAKE_SENSOR
+static void SCP_shk_work(struct work_struct *work);
+static int SCP_sensorHub_shake_init(void);
+static int SCP_sensorHub_shake_uninit(void);
+#endif //CONFIG_CUSTOM_KERNEL_SHAKE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_PICK_UP_SENSOR
+static void SCP_pkup_work(struct work_struct *work);
+static int SCP_sensorHub_pick_up_init(void);
+static int SCP_sensorHub_pick_up_uninit(void);
+#endif //CONFIG_CUSTOM_KERNEL_PICK_UP_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_FACE_DOWN_SENSOR
+static void SCP_fdn_work(struct work_struct *work);
+static int SCP_sensorHub_face_down_init(void);
+static int SCP_sensorHub_face_down_uninit(void);
+#endif //CONFIG_CUSTOM_KERNEL_FACE_DOWN_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_HEART_RATE_SENSOR
+//static void SCP_fdn_work(struct work_struct *work);
+static int SCP_sensorHub_heart_rate_init(void);
+static int SCP_sensorHub_heart_rate_uninit(void);
+#endif //CONFIG_CUSTOM_KERNEL_HEART_RATE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_TILT_DETECTOR_SENSOR
+static void SCP_tilt_work(struct work_struct *work);
+static int SCP_sensorHub_tilt_detector_init(void);
+static int SCP_sensorHub_tilt_detector_uninit(void);
+#endif //CONFIG_CUSTOM_KERNEL_TILT_DETECTOR_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_WAKE_GESTURE_SENSOR
+static void SCP_wag_work(struct work_struct *work);
+static int SCP_sensorHub_wake_gesture_init(void);
+static int SCP_sensorHub_wake_gesture_uninit(void);
+#endif //CONFIG_CUSTOM_KERNEL_WAKE_GESTURE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_GLANCE_GESTURE_SENSOR
+static void SCP_glg_work(struct work_struct *work);
+static int SCP_sensorHub_glance_gesture_init(void);
+static int SCP_sensorHub_glance_gesture_uninit(void);
+#endif //CONFIG_CUSTOM_KERNEL_GLANCE_GESTURE_SENSOR
+
+/*----------------------------------------------------------------------------*/
+typedef enum {
+ SCP_TRC_FUN = 0x01,
+ SCP_TRC_IPI = 0x02,
+ SCP_TRC_BATCH = 0x04,
+ SCP_TRC_BATCH_DETAIL = 0x08,
+} SCP_TRC;
+/*----------------------------------------------------------------------------*/
+SCP_sensorHub_handler sensor_handler[ID_SENSOR_MAX_HANDLE+1];
+/*----------------------------------------------------------------------------*/
+#define C_MAX_FIR_LENGTH (32)
+//#define USE_EARLY_SUSPEND
+static DEFINE_MUTEX(SCP_sensorHub_op_mutex);
+static DEFINE_MUTEX(SCP_sensorHub_req_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(SCP_sensorHub_req_wq);
+
+static int SCP_sensorHub_init_flag =-1; // 0<==>OK -1 <==> fail
+
+static struct batch_init_info SCP_sensorHub_init_info = {
+ .name = "SCP_sensorHub",
+ .init = SCP_sensorHub_local_init,
+ .uninit = SCP_sensorHub_remove,
+ .platform_diver_addr = NULL,
+};
+
+#ifdef CONFIG_CUSTOM_KERNEL_STEP_COUNTER
+static struct step_c_init_info SCP_step_counter_init_info = {
+ .name = "SCP_step_counter",
+ .init = SCP_sensorHub_step_counter_init,
+ .uninit = SCP_sensorHub_step_counter_uninit,
+};
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_STEP_COUNTER
+
+
+#ifdef CONFIG_CUSTOM_KERNEL_IN_POCKET_SENSOR
+static struct inpk_init_info SCP_in_pocket_init_info = {
+ .name = "SCP_in_pocket",
+ .init = SCP_sensorHub_in_pocket_init,
+ .uninit = SCP_sensorHub_in_pocket_uninit,
+};
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_IN_POCKET_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_PEDOMETER
+static struct pdr_init_info SCP_pedometer_init_info = {
+ .name = "SCP_pedometer",
+ .init = SCP_sensorHub_pedometer_init,
+ .uninit = SCP_sensorHub_pedometer_uninit,
+};
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_PEDOMETER
+#ifdef CONFIG_CUSTOM_KERNEL_ACTIVITY_SENSOR
+static struct act_init_info SCP_activity_init_info = {
+ .name = "SCP_activity",
+ .init = SCP_sensorHub_activity_init,
+ .uninit = SCP_sensorHub_activity_uninit,
+};
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_ACTIVITY_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_SHAKE_SENSOR
+static struct shk_init_info SCP_shake_init_info = {
+ .name = "SCP_shake",
+ .init = SCP_sensorHub_shake_init,
+ .uninit = SCP_sensorHub_shake_uninit,
+};
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_SHAKE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_PICK_UP_SENSOR
+static struct pkup_init_info SCP_pick_up_init_info = {
+ .name = "SCP_pick_up",
+ .init = SCP_sensorHub_pick_up_init,
+ .uninit = SCP_sensorHub_pick_up_uninit,
+};
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_PICK_UP_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_FACE_DOWN_SENSOR
+static struct fdn_init_info SCP_face_down_init_info = {
+ .name = "SCP_face_down",
+ .init = SCP_sensorHub_face_down_init,
+ .uninit = SCP_sensorHub_face_down_uninit,
+};
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_FACE_DOWN_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_HEART_RATE_SENSOR
+static struct hrm_init_info SCP_heart_rate_init_info = {
+ .name = "SCP_heart_rate",
+ .init = SCP_sensorHub_heart_rate_init,
+ .uninit = SCP_sensorHub_heart_rate_uninit,
+};
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_HEART_RATE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_TILT_DETECTOR_SENSOR
+static struct tilt_init_info SCP_tilt_detector_init_info = {
+ .name = "SCP_tilt_detector",
+ .init = SCP_sensorHub_tilt_detector_init,
+ .uninit = SCP_sensorHub_tilt_detector_uninit,
+};
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_TILT_DETECTOR_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_WAKE_GESTURE_SENSOR
+static struct wag_init_info SCP_wake_gesture_init_info = {
+ .name = "SCP_wake_gesture",
+ .init = SCP_sensorHub_wake_gesture_init,
+ .uninit = SCP_sensorHub_wake_gesture_uninit,
+};
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_WAKE_GESTURE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_GLANCE_GESTURE_SENSOR
+static struct glg_init_info SCP_glance_gesture_init_info = {
+ .name = "SCP_glance_gesture",
+ .init = SCP_sensorHub_glance_gesture_init,
+ .uninit = SCP_sensorHub_glance_gesture_uninit,
+};
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_GLANCE_GESTURE_SENSOR
+
+
+
+/*----------------------------------------------------------------------------*/
+struct data_filter {
+ s16 raw[C_MAX_FIR_LENGTH][SCP_sensorHub_AXES_NUM];
+ int sum[SCP_sensorHub_AXES_NUM];
+ int num;
+ int idx;
+};
+/*----------------------------------------------------------------------------*/
+struct SCP_sensorHub_data {
+ struct sensorHub_hw *hw;
+ struct work_struct ipi_work;
+ struct work_struct fifo_full_work;
+ struct work_struct sd_work; //step detect work
+ struct work_struct sig_work; //significant motion work
+ //struct work_struct pdr_work; //pedometer work
+ //struct work_struct act_work; //activity work
+ struct work_struct inpk_work;//in pocket work
+ struct work_struct pkup_work;//pick up work
+ struct work_struct fdn_work; //face down work
+ struct work_struct shk_work; //shake work
+ struct work_struct tilt_work; //tilt detector work
+ struct work_struct wag_work; //wake gesture work
+ struct work_struct glg_work; //glance gesture work
+ struct timer_list timer;
+ struct timer_list notify_timer;
+
+ /*misc*/
+ atomic_t trace;
+ atomic_t suspend;
+ atomic_t filter;
+ s16 cali_sw[SCP_sensorHub_AXES_NUM+1];
+ atomic_t wait_rsp;
+ atomic_t ipi_handler_running;
+ atomic_t disable_fifo_full_notify;
+
+ /*data*/
+ s8 offset[SCP_sensorHub_AXES_NUM+1]; /*+1: for 4-byte alignment*/
+ s16 data[SCP_sensorHub_AXES_NUM+1];
+ volatile struct sensorFIFO * volatile SCP_sensorFIFO;
+ dma_addr_t mapping;
+
+#if defined(CONFIG_SCP_sensorHub_LOWPASS)
+ atomic_t firlen;
+ atomic_t fir_en;
+ struct data_filter fir;
+#endif
+ /*early suspend*/
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(USE_EARLY_SUSPEND)
+ struct early_suspend early_drv;
+#endif
+};
+
+static struct device SCP_sensorHub_dev = {
+ .init_name = "SCPdmadev",
+ .coherent_dma_mask = ~0, // dma_alloc_coherent(): allow any address
+ .dma_mask = &SCP_sensorHub_dev.coherent_dma_mask, // other APIs: use the same mask as coherent
+};
+/*----------------------------------------------------------------------------*/
+static struct SCP_sensorHub_data *obj_data = NULL;
+static SCP_SENSOR_HUB_DATA_P userData = NULL;
+static uint *userDataLen = NULL;
+/*----------------------------------------------------------------------------*/
+#define SCP_TAG "[sensorHub] "
+#define SCP_FUN(f) printk(KERN_ERR SCP_TAG"%s\n", __FUNCTION__)
+#define SCP_ERR(fmt, args...) printk(KERN_ERR SCP_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args)
+#define SCP_LOG(fmt, args...) printk(KERN_ERR SCP_TAG fmt, ##args)
+/*--------------------SCP_sensorHub power control function----------------------------------*/
+static void SCP_sensorHub_power(struct sensorHub_hw *hw, unsigned int on)
+{
+}
+/*----------------------------------------------------------------------------*/
+//md32 may lock hw semaphore about 6.x ms to push data to dram.
+static int SCP_sensorHub_get_md32_semaphore()
+{
+ int64_t start_nt, cur_nt;
+ struct timespec time;
+ int err;
+
+ time.tv_sec = 0;
+ time.tv_nsec = 0;
+ get_monotonic_boottime(&time);
+ start_nt = time.tv_sec*1000000000LL+time.tv_nsec;
+
+ do{
+ if ((err = get_md32_semaphore(SEMAPHORE_SENSOR)) < 0)
+ {
+ time.tv_sec = 0;
+ time.tv_nsec = 0;
+ get_monotonic_boottime(&time);
+ cur_nt = time.tv_sec*1000000000LL+time.tv_nsec;
+ SCP_ERR("get_md32_semaphore fail : %d, %lld, %lld\n", err, start_nt, cur_nt);
+ }
+ else
+ {
+ return err;
+ }
+ }while((cur_nt-start_nt) < 20000000); //try 10 ms to get hw semaphore
+
+ SCP_ERR("get_md32_semaphore timeout : %d, %lld, %lld\n", err, start_nt, cur_nt);
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_init_client(void) //call by init done workqueue
+{
+ struct SCP_sensorHub_data *obj = obj_data;
+ SCP_SENSOR_HUB_DATA data;
+ unsigned int len = 0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ //enable_clock(MT_CG_INFRA_APDMA, "sensorHub");
+ //SCP_ERR("obj=%lld\n", obj);
+
+ obj->mapping = dma_map_single(&SCP_sensorHub_dev, (void *)obj->SCP_sensorFIFO, obj->SCP_sensorFIFO->FIFOSize, DMA_BIDIRECTIONAL);//(virt_to_phys(obj->SCP_sensorFIFO));
+ SCP_ERR("obj->mapping = %p\n", (void*)obj->mapping);
+ dma_sync_single_for_device(&SCP_sensorHub_dev, obj->mapping, obj->SCP_sensorFIFO->FIFOSize, DMA_TO_DEVICE);
+
+ data.set_config_req.sensorType = 0;
+ data.set_config_req.action = SENSOR_HUB_SET_CONFIG;
+ data.set_config_req.bufferBase = (int)(obj->mapping & 0xFFFFFFFF);
+ SCP_ERR("data.set_config_req.bufferBase = %d\n", data.set_config_req.bufferBase);
+// SCP_ERR("obj->SCP_sensorFIFO = %p, wp = %p, rp = %p, size = %d\n", obj->SCP_sensorFIFO,
+// obj->SCP_sensorFIFO->wp, obj->SCP_sensorFIFO->rp, obj->SCP_sensorFIFO->FIFOSize);
+ data.set_config_req.bufferSize = obj->SCP_sensorFIFO->FIFOSize;
+ len = sizeof(data.set_config_req);
+
+ SCP_sensorHub_req_send(&data, &len, 1);
+
+ SCP_ERR("SCP_sensorHub_init_client done\n");
+
+ return SCP_SENSOR_HUB_SUCCESS;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_ReadChipInfo(char *buf, int bufsize)
+{
+ if((NULL == buf)||(bufsize<=30))
+ {
+ return -1;
+ }
+
+ sprintf(buf, "SCP_sensorHub Chip");
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_ReadSensorData(int handle, hwm_sensor_data *sensorData)
+{
+ struct SCP_sensorHub_data *obj = obj_data;
+ char *pStart, *pEnd, *pNext;
+ struct SCP_sensorData curData;
+ char *rp, *wp;
+ int offset;
+ int fifo_usage;
+ int err;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ if(NULL == sensorData)
+ {
+ return -1;
+ }
+
+ if ((err = SCP_sensorHub_get_md32_semaphore()) < 0)
+ {
+ SCP_ERR("SCP_sensorHub_get_md32_semaphore fail : %d\n", err);
+ return -2;
+ }
+
+ dma_sync_single_for_cpu(&SCP_sensorHub_dev, obj->mapping, obj->SCP_sensorFIFO->FIFOSize, DMA_FROM_DEVICE);
+ pStart = (char *)obj->SCP_sensorFIFO + offsetof(struct sensorFIFO, data);
+ pEnd = (char *)pStart + obj->SCP_sensorFIFO->FIFOSize;
+ rp = pStart + (int)obj->SCP_sensorFIFO->rp;
+ wp = pStart + (int)obj->SCP_sensorFIFO->wp;
+
+ if (rp < pStart || pEnd <= rp)
+ {
+ SCP_ERR("FIFO rp invalid : %p, %p, %p\n", pStart, pEnd, rp);
+ if ((err = release_md32_semaphore(SEMAPHORE_SENSOR)) < 0)
+ {
+ SCP_ERR("release_md32_semaphore fail : %d\n", err);
+ return -3;
+ }
+ return -4;
+ }
+
+ if (wp < pStart || pEnd <= wp)
+ {
+ SCP_ERR("FIFO wp invalid : %p, %p, %p\n", pStart, pEnd, wp);
+ if ((err = release_md32_semaphore(SEMAPHORE_SENSOR)) < 0)
+ {
+ SCP_ERR("release_md32_semaphore fail : %d\n", err);
+ return -3;
+ }
+ return -5;
+ }
+
+ if (rp == wp)
+ {
+ SCP_ERR("FIFO empty\n");
+ if ((err = release_md32_semaphore(SEMAPHORE_SENSOR)) < 0)
+ {
+ SCP_ERR("release_md32_semaphore fail : %d\n", err);
+ return -3;
+ }
+ return -6;
+ }
+ else
+ {
+ pNext = rp + offsetof(struct SCP_sensorData, data) + ((struct SCP_sensorData*)rp)->dataLength;
+ pNext = (char *)((((unsigned long)pNext + 3) >> 2 ) << 2);
+
+ if (SCP_TRC_BATCH_DETAIL & atomic_read(&(obj_data->trace)))
+ SCP_LOG("dataLength = %d, pNext = %p, rp = %p, wp = %p\n", ((struct SCP_sensorData*)rp)->dataLength, pNext, rp, wp);
+
+ if (((struct SCP_sensorData*)rp)->dataLength != 6 && ((struct SCP_sensorData*)rp)->dataLength != 8)
+ SCP_ERR("Wrong dataLength = %d\n", ((struct SCP_sensorData*)rp)->dataLength);
+
+ if (pNext < pEnd)
+ {
+ memcpy((char *)&curData, rp, pNext - rp);
+ rp = pNext;
+ }
+ else
+ {
+ memcpy(&curData, rp, pEnd - rp);
+ offset = (int)(pEnd - rp); //fix build error, error: invalid operands to binary + (have 'char *' and 'char *')
+ memcpy((char *)&curData + offset, pStart, pNext - pEnd);
+ offset = (int)(pNext - pEnd); //fix build error, error: invalid operands to binary + (have 'char *' and 'char *')
+ rp = pStart + offset;
+ }
+
+ obj->SCP_sensorFIFO->rp = (int)(rp - pStart);
+ dma_sync_single_for_device(&SCP_sensorHub_dev, obj->mapping, obj->SCP_sensorFIFO->FIFOSize, DMA_TO_DEVICE); //write back to device asap.
+ if ((err = release_md32_semaphore(SEMAPHORE_SENSOR)) < 0) //allow scp to access dram
+ {
+ SCP_ERR("release_md32_semaphore fail : %d\n", err);
+ }
+
+ sensorData->sensor = curData.sensorType;
+ sensorData->value_divide = 1000; //need to check
+ sensorData->status = SENSOR_STATUS_ACCURACY_MEDIUM;
+ sensorData->values[0] = curData.data[0];
+ sensorData->values[1] = curData.data[1];
+ sensorData->values[2] = curData.data[2];
+
+ if (rp <= wp)
+ {
+ fifo_usage = (int)(wp-rp);
+ }
+ else
+ {
+ fifo_usage = obj->SCP_sensorFIFO->FIFOSize - (int)(rp-wp);
+ }
+
+ fifo_usage = (fifo_usage * 100) / obj->SCP_sensorFIFO->FIFOSize;
+
+ if (SCP_TRC_BATCH_DETAIL & atomic_read(&(obj_data->trace)))
+ SCP_LOG("rp = %p, wp = %p, fifo_usage = %d%%\n", rp, wp, fifo_usage);
+
+ if (fifo_usage < 50)
+ atomic_set(&obj->disable_fifo_full_notify,0);
+ }
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static ssize_t show_chipinfo_value(struct device_driver *ddri, char *buf)
+{
+ char strbuf[SCP_SENSOR_HUB_TEMP_BUFSIZE];
+
+ SCP_sensorHub_ReadChipInfo(strbuf, SCP_SENSOR_HUB_TEMP_BUFSIZE);
+ return snprintf(buf, PAGE_SIZE, "%s\n", strbuf);
+}
+/*----------------------------------------------------------------------------*/
+static ssize_t show_trace_value(struct device_driver *ddri, char *buf)
+{
+ ssize_t res;
+ struct SCP_sensorHub_data *obj = obj_data;
+ if (obj == NULL)
+ {
+ SCP_ERR("SCP_sensorHub_data obj is null!!\n");
+ return 0;
+ }
+
+ res = snprintf(buf, PAGE_SIZE, "0x%04X\n", atomic_read(&obj->trace));
+ return res;
+}
+/*----------------------------------------------------------------------------*/
+static ssize_t store_trace_value(struct device_driver *ddri, const char *buf, size_t count)
+{
+ struct SCP_sensorHub_data *obj = obj_data;
+ int trace;
+ if (obj == NULL)
+ {
+ SCP_ERR("SCP_sensorHub_data obj is null!!\n");
+ return 0;
+ }
+
+ if(1 == sscanf(buf, "0x%x", &trace))
+ {
+ atomic_set(&obj->trace, trace);
+ }
+ else
+ {
+ SCP_ERR("invalid content: '%s', length = %d\n", buf, (int)count);
+ }
+
+ return count;
+}
+/*----------------------------------------------------------------------------*/
+static DRIVER_ATTR(chipinfo, S_IWUSR | S_IRUGO, show_chipinfo_value, NULL);
+static DRIVER_ATTR(trace, S_IWUSR | S_IRUGO, show_trace_value, store_trace_value);
+/*----------------------------------------------------------------------------*/
+static struct driver_attribute *SCP_sensorHub_attr_list[] = {
+ &driver_attr_chipinfo, /*chip information*/
+ &driver_attr_trace, /*trace log*/
+};
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_create_attr(struct device_driver *driver)
+{
+ int idx, err = 0;
+ int num = (int)(sizeof(SCP_sensorHub_attr_list)/sizeof(SCP_sensorHub_attr_list[0]));
+ if (driver == NULL)
+ {
+ return -EINVAL;
+ }
+
+ for(idx = 0; idx < num; idx++)
+ {
+ if((err = driver_create_file(driver, SCP_sensorHub_attr_list[idx])))
+ {
+ SCP_ERR("driver_create_file (%s) = %d\n", SCP_sensorHub_attr_list[idx]->attr.name, err);
+ break;
+ }
+ }
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_delete_attr(struct device_driver *driver)
+{
+ int idx ,err = 0;
+ int num = (int)(sizeof(SCP_sensorHub_attr_list)/sizeof(SCP_sensorHub_attr_list[0]));
+
+ if(driver == NULL)
+ {
+ return -EINVAL;
+ }
+
+
+ for(idx = 0; idx < num; idx++)
+ {
+ driver_remove_file(driver, SCP_sensorHub_attr_list[idx]);
+ }
+
+
+ return err;
+}
+/******************************************************************************
+ * Function Configuration
+******************************************************************************/
+static int SCP_sensorHub_open(struct inode *inode, struct file *file)
+{
+ file->private_data = obj_data;
+
+ if(file->private_data == NULL)
+ {
+ SCP_ERR("null pointer!!\n");
+ return -EINVAL;
+ }
+ return nonseekable_open(inode, file);
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_release(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static long SCP_sensorHub_unlocked_ioctl(struct file *file, unsigned int cmd,unsigned long arg)
+{
+ char strbuf[SCP_SENSOR_HUB_TEMP_BUFSIZE];
+ void __user *data;
+ long err = 0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ if(_IOC_DIR(cmd) & _IOC_READ)
+ {
+ err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
+ }
+ else if(_IOC_DIR(cmd) & _IOC_WRITE)
+ {
+ err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
+ }
+
+ if(err)
+ {
+ SCP_ERR("access error: %08X, (%2d, %2d)\n", cmd, _IOC_DIR(cmd), _IOC_SIZE(cmd));
+ return -EFAULT;
+ }
+
+ switch(cmd)
+ {
+ case GSENSOR_IOCTL_INIT:
+ SCP_sensorHub_init_client();
+ break;
+
+ case GSENSOR_IOCTL_READ_CHIPINFO:
+ data = (void __user *) arg;
+ if(data == NULL)
+ {
+ err = -EINVAL;
+ break;
+ }
+
+ SCP_sensorHub_ReadChipInfo(strbuf, SCP_SENSOR_HUB_TEMP_BUFSIZE);
+ if(copy_to_user(data, strbuf, strlen(strbuf)+1))
+ {
+ err = -EFAULT;
+ break;
+ }
+ break;
+
+ case GSENSOR_IOCTL_READ_SENSORDATA:
+ err = -EINVAL;
+ break;
+
+ case GSENSOR_IOCTL_READ_GAIN:
+ err = -EINVAL;
+ break;
+
+ case GSENSOR_IOCTL_READ_RAW_DATA:
+ err = -EFAULT;
+ break;
+
+ case GSENSOR_IOCTL_SET_CALI:
+ err = -EINVAL;
+ break;
+
+ case GSENSOR_IOCTL_CLR_CALI:
+ err = -EINVAL;
+ break;
+
+ case GSENSOR_IOCTL_GET_CALI:
+ err = -EINVAL;
+ break;
+
+
+ default:
+ SCP_ERR("unknown IOCTL: 0x%08x\n", cmd);
+ err = -ENOIOCTLCMD;
+ break;
+
+ }
+
+ return err;
+}
+
+
+/*----------------------------------------------------------------------------*/
+static struct file_operations SCP_sensorHub_fops = {
+ //.owner = THIS_MODULE,
+ .open = SCP_sensorHub_open,
+ .release = SCP_sensorHub_release,
+ .unlocked_ioctl = SCP_sensorHub_unlocked_ioctl,
+};
+/*----------------------------------------------------------------------------*/
+static struct miscdevice SCP_sensorHub_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "SCP_sensorHub",
+ .fops = &SCP_sensorHub_fops,
+};
+/*----------------------------------------------------------------------------*/
+#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(USE_EARLY_SUSPEND)
+/*----------------------------------------------------------------------------*/
+#if 0
+static int SCP_sensorHub_suspend(struct platform_device *dev, pm_message_t state)
+{
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_resume(struct platform_device *dev)
+{
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+#endif
+#else //#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(USE_EARLY_SUSPEND)
+/*----------------------------------------------------------------------------*/
+static void SCP_sensorHub_early_suspend(struct early_suspend *h)
+{
+}
+/*----------------------------------------------------------------------------*/
+static void SCP_sensorHub_late_resume(struct early_suspend *h)
+{
+}
+/*----------------------------------------------------------------------------*/
+#endif //#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(USE_EARLY_SUSPEND)
+/*----------------------------------------------------------------------------*/
+int SCP_sensorHub_req_send(SCP_SENSOR_HUB_DATA_P data, uint *len, unsigned int wait)
+{
+ ipi_status status;
+ int err = 0;
+
+ if (SCP_TRC_IPI & atomic_read(&(obj_data->trace)))
+ SCP_ERR("len = %d, type = %d, action = %d\n", *len, data->req.sensorType, data->req.action);
+
+ if (*len > 48)
+ {
+ SCP_ERR("!!\n");
+ return -1;
+ }
+
+ if (in_interrupt())
+ {
+ SCP_ERR("Can't do %s in interrupt context!!\n", __FUNCTION__);
+ return -1;
+ }
+
+ if (ID_SENSOR_MAX_HANDLE < data->rsp.sensorType)
+ {
+ SCP_ERR("SCP_sensorHub_IPI_handler invalid sensor type %d\n", data->rsp.sensorType);
+ return -1;
+ }
+ else
+ {
+ mutex_lock(&SCP_sensorHub_req_mutex);
+
+ userData = data;
+ userDataLen = len;
+
+ switch(data->req.action)
+ {
+ case SENSOR_HUB_ACTIVATE:
+ break;
+ case SENSOR_HUB_SET_DELAY:
+ break;
+ case SENSOR_HUB_GET_DATA:
+ break;
+ case SENSOR_HUB_BATCH:
+ break;
+ case SENSOR_HUB_SET_CONFIG:
+ break;
+ case SENSOR_HUB_SET_CUST:
+ break;
+ default:
+ break;
+ }
+
+ if (1 == wait)
+ {
+ if(atomic_read(&(obj_data->wait_rsp)) == 1)
+ {
+ SCP_ERR("SCP_sensorHub_req_send reentry\n");
+ }
+ atomic_set(&(obj_data->wait_rsp), 1);
+ }
+
+ do
+ {
+ status = md32_ipi_send(IPI_SENSOR, data, *len, wait);
+ if (ERROR == status)
+ {
+ SCP_ERR("md32_ipi_send ERROR\n");
+ mutex_unlock(&SCP_sensorHub_req_mutex);
+ return -1;
+ }
+ }
+ while (BUSY == status);
+ if (SCP_TRC_IPI & atomic_read(&(obj_data->trace)))
+ SCP_ERR("md32_ipi_send DONE\n");
+ mod_timer(&obj_data->timer, jiffies + 3*HZ);
+ wait_event_interruptible(SCP_sensorHub_req_wq, (atomic_read(&(obj_data->wait_rsp)) == 0));
+ del_timer_sync(&obj_data->timer);
+ err = userData->rsp.errCode;
+ mutex_unlock(&SCP_sensorHub_req_mutex);
+ }
+
+ if (SCP_TRC_IPI & atomic_read(&(obj_data->trace)))
+ SCP_ERR("SCP_sensorHub_req_send end\n");
+
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+int SCP_sensorHub_rsp_registration(int sensor, SCP_sensorHub_handler handler)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ if (ID_SENSOR_MAX_HANDLE < sensor)
+ {
+ SCP_ERR("SCP_sensorHub_rsp_registration invalid sensor %d\n", sensor);
+ }
+
+ if (NULL == handler)
+ {
+ SCP_ERR("SCP_sensorHub_rsp_registration null handler\n");
+ }
+
+ sensor_handler[sensor] = handler;
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static void SCP_ipi_work(struct work_struct *work)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ SCP_sensorHub_init_client();
+}
+/*----------------------------------------------------------------------------*/
+static void SCP_fifo_full_work(struct work_struct *work)
+{
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ batch_notify(TYPE_BATCHFULL);
+}
+/*----------------------------------------------------------------------------*/
+static void SCP_sensorHub_req_send_timeout(unsigned long data)
+{
+ if(atomic_read(&(obj_data->wait_rsp)) == 1)
+ {
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ if (NULL != userData && NULL != userDataLen)
+ {
+ userData->rsp.errCode = -1;
+ *userDataLen = sizeof(userData->rsp);
+ }
+
+ atomic_set(&(obj_data->wait_rsp), 0);
+ wake_up(&SCP_sensorHub_req_wq);
+ }
+}
+/*----------------------------------------------------------------------------*/
+static void SCP_sensorHub_IPI_handler(int id, void *data, unsigned int len)
+{
+ struct SCP_sensorHub_data *obj = obj_data;
+ SCP_SENSOR_HUB_DATA_P rsp = (SCP_SENSOR_HUB_DATA_P)data;
+ bool wake_up_req = false;
+ bool do_registed_handler = false;
+ static int first_init_done = 0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ if (SCP_TRC_IPI & atomic_read(&(obj_data->trace)))
+ SCP_ERR("len = %d, type = %d, action = %d, errCode = %d\n", len, rsp->rsp.sensorType, rsp->rsp.action, rsp->rsp.errCode);
+
+ if (len > 48)
+ {
+ SCP_ERR("SCP_sensorHub_IPI_handler len=%d error\n", len);
+ return;
+ }
+ else
+ {
+ switch(rsp->rsp.action)
+ {
+ case SENSOR_HUB_ACTIVATE:
+ case SENSOR_HUB_SET_DELAY:
+ case SENSOR_HUB_GET_DATA:
+ case SENSOR_HUB_BATCH:
+ case SENSOR_HUB_SET_CONFIG:
+ case SENSOR_HUB_SET_CUST:
+ wake_up_req = true;
+ break;
+ case SENSOR_HUB_NOTIFY:
+ switch(rsp->notify_rsp.event)
+ {
+ case SCP_INIT_DONE:
+ if (0 == first_init_done)
+ {
+ schedule_work(&obj->ipi_work);
+ first_init_done = 1;
+ }
+ do_registed_handler = true;
+ break;
+ case SCP_FIFO_FULL:
+ if (atomic_read(&obj->disable_fifo_full_notify)==0)
+ {
+ atomic_set(&obj->disable_fifo_full_notify,1);
+ schedule_work(&obj->fifo_full_work);
+ }
+ else
+ {
+ SCP_ERR("SCP_FIFO_FULL disabled\n");
+ }
+ break;
+ case SCP_NOTIFY:
+ do_registed_handler = true;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ SCP_ERR("SCP_sensorHub_IPI_handler unknow action=%d error\n", rsp->rsp.action);
+ return;
+ }
+
+ if (ID_SENSOR_MAX_HANDLE < rsp->rsp.sensorType)
+ {
+ SCP_ERR("SCP_sensorHub_IPI_handler invalid sensor type %d\n", rsp->rsp.sensorType);
+ return;
+ }
+ else if (true == do_registed_handler)
+ {
+ if (NULL != sensor_handler[rsp->rsp.sensorType])
+ {
+ sensor_handler[rsp->rsp.sensorType](data, len);
+ }
+ }
+
+ if(atomic_read(&(obj_data->wait_rsp)) == 1 && true == wake_up_req)
+ {
+ if (NULL == userData || NULL == userDataLen)
+ {
+ SCP_ERR("SCP_sensorHub_IPI_handler null pointer\n");
+ }
+ else
+ {
+ if (userData->req.sensorType != rsp->rsp.sensorType)
+ SCP_ERR("SCP_sensorHub_IPI_handler sensor type %d != %d\n", userData->req.sensorType, rsp->rsp.sensorType);
+ if (userData->req.action != rsp->rsp.action)
+ SCP_ERR("SCP_sensorHub_IPI_handler action %d != %d\n", userData->req.action, rsp->rsp.action);
+ memcpy(userData, rsp, len);
+ *userDataLen = len;
+ }
+ atomic_set(&(obj_data->wait_rsp), 0);
+ wake_up(&SCP_sensorHub_req_wq);
+ }
+ }
+}
+/*----------------------------------------------------------------------------*/
+int SCP_sensorHub_enable_hw_batch(int handle, int enable, int flag, long long samplingPeriodNs,long long maxBatchReportLatencyNs)
+{
+ SCP_SENSOR_HUB_DATA req;
+ int len;
+ int err = 0;
+
+ if (samplingPeriodNs==0)
+ return 0;
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ do_div(maxBatchReportLatencyNs,1000000);
+ do_div(samplingPeriodNs,1000000);
+ req.batch_req.sensorType = handle;
+ req.batch_req.action = SENSOR_HUB_BATCH;
+ req.batch_req.flag = flag;
+ req.batch_req.period_ms = (unsigned int)samplingPeriodNs;
+ req.batch_req.timeout_ms = (enable==0)?0:(unsigned int)maxBatchReportLatencyNs;
+ if (SCP_TRC_BATCH & atomic_read(&(obj_data->trace)))
+ {
+ SCP_ERR("handle = %d, flag = %d, period_ms = %d, timeout_ms = %d!\n", req.batch_req.sensorType, req.batch_req.flag,
+ req.batch_req.period_ms, req.batch_req.timeout_ms);
+ }
+ len = sizeof(req.batch_req);
+ err = SCP_sensorHub_req_send(&req, &len, 1);
+ if (err)
+ {
+ SCP_ERR("SCP_sensorHub_req_send fail!\n");
+ }
+
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_flush(int handle)
+{
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_get_data(int handle, hwm_sensor_data *sensorData)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensorHub_ReadSensorData(handle, sensorData);
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_get_fifo_status(int *dataLen, int *status, char *reserved, struct batch_timestamp_info *p_batch_timestampe_info)
+{
+ struct SCP_sensorHub_data *obj = obj_data;
+ int err = 0;
+ SCP_SENSOR_HUB_DATA data;
+ char *pStart, *pEnd, *pNext;
+ unsigned int len = 0;
+ char *rp, *wp;
+ struct batch_timestamp_info *pt = p_batch_timestampe_info;
+ int i, offset;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+ for (i=0;i<=MAX_ANDROID_SENSOR_NUM;i++)
+ {
+ pt[i].total_count = 0;
+ }
+
+ *dataLen = 0;
+ *status = 1;
+
+ data.get_data_req.sensorType = 0;
+ data.get_data_req.action = SENSOR_HUB_GET_DATA;
+ len = sizeof(data.get_data_req);
+
+ if (0 != (err = SCP_sensorHub_req_send(&data, &len, 1)))
+ {
+ SCP_ERR("SCP_sensorHub_req_send error: ret value=%d\n", err);
+ return -1;
+ }
+ else
+ {
+ //To prevent get fifo status during scp wrapper around dram fifo.
+ if ((err = SCP_sensorHub_get_md32_semaphore()) < 0)
+ {
+ SCP_ERR("SCP_sensorHub_get_md32_semaphore fail : %d\n", err);
+ return -2;
+ }
+ dma_sync_single_for_cpu(&SCP_sensorHub_dev, obj->mapping, obj->SCP_sensorFIFO->FIFOSize, DMA_FROM_DEVICE);
+ //No data need to sync. back to device, release semaphore immediately.
+ if ((err = release_md32_semaphore(SEMAPHORE_SENSOR)) < 0)
+ {
+ SCP_ERR("release_md32_semaphore fail : %d\n", err);
+ return -3;
+ }
+
+ pStart = (char *)obj->SCP_sensorFIFO + offsetof(struct sensorFIFO, data);
+ pEnd = (char *)pStart + obj->SCP_sensorFIFO->FIFOSize;
+ rp = pStart + (int)obj->SCP_sensorFIFO->rp;
+ wp = pStart + (int)obj->SCP_sensorFIFO->wp;
+
+ if (SCP_TRC_BATCH & atomic_read(&(obj_data->trace)))
+ {
+ SCP_ERR("FIFO pStart = %p, rp = %p, wp = %p, pEnd = %p\n", pStart, rp, wp, pEnd);
+ }
+
+ if (rp < pStart || pEnd <= rp)
+ {
+ SCP_ERR("FIFO rp invalid : %p, %p, %p\n", pStart, pEnd, rp);
+ return -4;
+ }
+
+ if (wp < pStart || pEnd < wp)
+ {
+ SCP_ERR("FIFO wp invalid : %p, %p, %p\n", pStart, pEnd, wp);
+ return -5;
+ }
+
+ if (rp == wp)
+ {
+ SCP_ERR("FIFO empty\n");
+ return -6;
+ }
+
+ while(rp != wp)
+ {
+ pNext = rp + offsetof(struct SCP_sensorData, data) + ((struct SCP_sensorData*)rp)->dataLength;
+ pNext = (char *)((((unsigned long)pNext + 3) >> 2 ) << 2);
+ if (SCP_TRC_BATCH_DETAIL & atomic_read(&(obj_data->trace)))
+ SCP_LOG("rp = %p, dataLength = %d, pNext = %p\n", rp, ((struct SCP_sensorData*)rp)->dataLength, pNext);
+
+ if (((struct SCP_sensorData*)rp)->dataLength != 6 && ((struct SCP_sensorData*)rp)->dataLength != 8)
+ {
+ SCP_ERR("Wrong dataLength = %d, sensorType = %d\n", ((struct SCP_sensorData*)rp)->dataLength, ((struct SCP_sensorData*)rp)->sensorType);
+ return -7;
+ }
+
+ pt[((struct SCP_sensorData*)rp)->sensorType].total_count++;
+
+ if (pNext < pEnd)
+ {
+ rp = pNext;
+ }
+ else
+ {
+ offset = (int)(pNext - pEnd); //fix build error, error: invalid operands to binary + (have 'char *' and 'char *')
+ rp = pStart + offset;
+ }
+ (*dataLen)++;
+ }
+
+ //No data changed, sync. to device is not necessary.
+ //dma_sync_single_for_device(&SCP_sensorHub_dev, obj->mapping, obj->SCP_sensorFIFO->FIFOSize, DMA_TO_DEVICE);
+ }
+
+ if (SCP_TRC_BATCH & atomic_read(&(obj_data->trace)))
+ SCP_ERR("dataLen = %d, status = %d\n", *dataLen, *status);
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_probe(/*struct platform_device *pdev*/)
+{
+ struct SCP_sensorHub_data *obj;
+ int err = 0;
+ struct batch_control_path ctl={0};
+ struct batch_data_path data={0};
+
+ SCP_FUN();
+
+ if(!(obj = kzalloc(sizeof(*obj), GFP_KERNEL)))
+ {
+ SCP_ERR("Allocate SCP_sensorHub_data fail\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ memset(obj, 0, sizeof(struct SCP_sensorHub_data));
+
+ if(!(obj->SCP_sensorFIFO = kzalloc(SCP_SENSOR_HUB_FIFO_SIZE, GFP_KERNEL)))
+ {
+ SCP_ERR("Allocate SCP_sensorFIFO fail\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ obj->SCP_sensorFIFO->wp = 0;//(struct SCP_sensorData *)((char *)obj->SCP_sensorFIFO + offsetof(struct sensorFIFO, data));
+ obj->SCP_sensorFIFO->rp = 0;//(struct SCP_sensorData *)((char *)obj->SCP_sensorFIFO + offsetof(struct sensorFIFO, data));
+ obj->SCP_sensorFIFO->FIFOSize = SCP_SENSOR_HUB_FIFO_SIZE - offsetof(struct sensorFIFO, data);
+ obj->hw = get_cust_sensorHub_hw();
+
+ SCP_ERR("obj->SCP_sensorFIFO = %p, wp = %d, rp = %d, size = %d\n", obj->SCP_sensorFIFO,
+ obj->SCP_sensorFIFO->wp, obj->SCP_sensorFIFO->rp, obj->SCP_sensorFIFO->FIFOSize);
+
+ obj_data = obj;
+
+ atomic_set(&obj->trace, 0);
+ atomic_set(&obj->suspend, 0);
+ atomic_set(&obj->wait_rsp, 0);
+ atomic_set(&obj->ipi_handler_running, 0);
+ atomic_set(&obj->disable_fifo_full_notify, 0);
+ INIT_WORK(&obj->ipi_work, SCP_ipi_work);
+ INIT_WORK(&obj->fifo_full_work, SCP_fifo_full_work);
+#ifdef CONFIG_CUSTOM_KERNEL_STEP_COUNTER
+ INIT_WORK(&obj->sd_work, SCP_sd_work);
+ INIT_WORK(&obj->sig_work, SCP_sig_work);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_STEP_COUNTER
+#ifdef CONFIG_CUSTOM_KERNEL_IN_POCKET_SENSOR
+ INIT_WORK(&obj->inpk_work,SCP_inpk_work);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_IN_POCKET_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_PEDOMETER
+// INIT_WORK(&obj->pdr_work, SCP_pdr_work);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_PEDOMETER
+#ifdef CONFIG_CUSTOM_KERNEL_ACTIVITY_SENSOR
+// INIT_WORK(&obj->act_work, SCP_act_work);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_ACTIVITY_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_SHAKE_SENSOR
+ INIT_WORK(&obj->shk_work, SCP_shk_work);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_SHAKE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_PICK_UP_SENSOR
+ INIT_WORK(&obj->pkup_work,SCP_pkup_work);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_PICK_UP_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_FACE_DOWN_SENSOR
+ INIT_WORK(&obj->fdn_work, SCP_fdn_work);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_FACE_DOWN_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_HEART_RATE_SENSOR
+// INIT_WORK(&obj->hrm_work, SCP_hrm_work);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_HEART_RATE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_TILT_DETECTOR_SENSOR
+ INIT_WORK(&obj->tilt_work, SCP_tilt_work);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_TILT_DETECTOR_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_WAKE_GESTURE_SENSOR
+ INIT_WORK(&obj->wag_work, SCP_wag_work);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_WAKE_GESTURE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_GLANCE_GESTURE_SENSOR
+ INIT_WORK(&obj->glg_work, SCP_glg_work);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_GLANCE_GESTURE_SENSOR
+
+
+ init_waitqueue_head(&SCP_sensorHub_req_wq);
+ init_timer(&obj->timer);
+ obj->timer.expires = 3*HZ;
+ obj->timer.function = SCP_sensorHub_req_send_timeout;
+ obj->timer.data = (unsigned long)obj;
+
+ init_timer(&obj->notify_timer);
+ obj->notify_timer.expires = HZ/5; //200 ms
+ obj->notify_timer.function = notify_ap_timeout;
+ obj->notify_timer.data = (unsigned long)obj;
+
+ md32_ipi_registration(IPI_SENSOR, SCP_sensorHub_IPI_handler, "SCP_sensorHub");
+
+ if((err = misc_register(&SCP_sensorHub_device)))
+ {
+ SCP_ERR("SCP_sensorHub_device register failed\n");
+ goto exit_misc_device_register_failed;
+ }
+
+ if((err = SCP_sensorHub_create_attr(&(SCP_sensorHub_init_info.platform_diver_addr->driver))))
+ {
+ SCP_ERR("create attribute err = %d\n", err);
+ goto exit_create_attr_failed;
+ }
+
+ ctl.enable_hw_batch = SCP_sensorHub_enable_hw_batch;
+ ctl.flush = SCP_sensorHub_flush;
+ err = batch_register_control_path(MAX_ANDROID_SENSOR_NUM, &ctl);
+ if(err)
+ {
+ SCP_ERR("register SCP sensor hub control path err\n");
+ goto exit_kfree;
+ }
+
+ data.get_data = SCP_sensorHub_get_data;
+ data.get_fifo_status = SCP_sensorHub_get_fifo_status;
+ data.is_batch_supported = 1;
+ err = batch_register_data_path(MAX_ANDROID_SENSOR_NUM, &data);
+ if(err)
+ {
+ SCP_ERR("register SCP sensor hub control data path err\n");
+ goto exit_kfree;
+ }
+
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(USE_EARLY_SUSPEND)
+ obj->early_drv.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1,
+ obj->early_drv.suspend = SCP_sensorHub_early_suspend,
+ obj->early_drv.resume = SCP_sensorHub_late_resume,
+ register_early_suspend(&obj->early_drv);
+#endif
+
+ SCP_sensorHub_init_flag = 0;
+ printk("%s: OK new\n", __func__);
+
+ return 0;
+
+ exit_create_attr_failed:
+ misc_deregister(&SCP_sensorHub_device);
+ exit_misc_device_register_failed:
+ exit_kfree:
+ kfree(obj);
+ exit:
+ SCP_ERR("%s: err = %d\n", __func__, err);
+ SCP_sensorHub_init_flag = -1;
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_remove()
+{
+ struct sensorHub_hw *hw = get_cust_sensorHub_hw();
+ int err = 0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+ SCP_sensorHub_power(hw, 0);
+
+ if((err = SCP_sensorHub_delete_attr(&(SCP_sensorHub_init_info.platform_diver_addr->driver))))
+ {
+ SCP_ERR("SCP_sensorHub_delete_attr fail: %d\n", err);
+ }
+
+ if((err = misc_deregister(&SCP_sensorHub_device)))
+ {
+ SCP_ERR("misc_deregister fail: %d\n", err);
+ }
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensor_enable(int sensorType, int en)
+{
+ SCP_SENSOR_HUB_DATA req;
+ int len;
+ int err = 0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ req.activate_req.sensorType = sensorType;
+ req.activate_req.action = SENSOR_HUB_ACTIVATE;
+ req.activate_req.enable = en;
+ len = sizeof(req.activate_req);
+ err = SCP_sensorHub_req_send(&req, &len, 1);
+ if (err)
+ {
+ SCP_ERR("SCP_sensorHub_req_send fail!\n");
+ }
+
+ return err;
+}
+static int SCP_sensor_set_delay(int sensorType, int delay)
+{
+ SCP_SENSOR_HUB_DATA req;
+ int len;
+ int err = 0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ req.set_delay_req.sensorType = sensorType;
+ req.set_delay_req.action = SENSOR_HUB_SET_DELAY;
+ req.set_delay_req.delay = delay;
+ len = sizeof(req.set_delay_req);
+ err = SCP_sensorHub_req_send(&req, &len, 1);
+ if (err)
+ {
+ SCP_ERR("SCP_sensorHub_req_send fail!\n");
+ }
+
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensor_get_data16(int sensorType, void *value, int *status)
+{
+ SCP_SENSOR_HUB_DATA req;
+ int len;
+ int err = 0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ req.get_data_req.sensorType = sensorType;
+ req.get_data_req.action = SENSOR_HUB_GET_DATA;
+ len = sizeof(req.get_data_req);
+ err = SCP_sensorHub_req_send(&req, &len, 1);
+ if (err)
+ {
+ SCP_ERR("SCP_sensorHub_req_send fail!\n");
+ }
+
+ switch (sensorType)
+ {
+ case ID_ACTIVITY://there are 6 values in activity
+ *(u16*)value = *req.get_data_rsp.int16_Data;
+ *((u16*)value+1) = *(req.get_data_rsp.int16_Data+1);
+ *((u16*)value+2) = *(req.get_data_rsp.int16_Data+2);
+ *((u16*)value+3) = *(req.get_data_rsp.int16_Data+3);
+ *((u16*)value+4) = *(req.get_data_rsp.int16_Data+4);
+ *((u16*)value+5) = *(req.get_data_rsp.int16_Data+5);
+ SCP_LOG("ID_ACTIVITY , value=%d value1=%d value2=%d value3=%d value4=%d value5=%d\n",
+ *((u16*)value), *((u16*)value+1), *((u16*)value+2), *((u16*)value+3), *((u16*)value+4), *((u16*)value+5));
+ break;
+ case ID_IN_POCKET:
+ *((u16*)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_PICK_UP_GESTURE:
+ *((u16*)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_FACE_DOWN:
+ *((u16*)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_SHAKE:
+ *((u16*)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_TILT_DETECTOR:
+ *((u16*)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_WAKE_GESTURE:
+ *((u16*)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_GLANCE_GESTURE:
+ *((u16*)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ default:
+ err = -1;
+ break;
+ }
+ SCP_LOG("sensorType = %d, value = %d\n", sensorType, *((u16 *)value));
+ return err;
+}
+
+static int SCP_sensor_get_data32(int sensorType, void *value, int *status)
+{
+ SCP_SENSOR_HUB_DATA req;
+ int len;
+ int err = 0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ req.get_data_req.sensorType = sensorType;
+ req.get_data_req.action = SENSOR_HUB_GET_DATA;
+ len = sizeof(req.get_data_req);
+ err = SCP_sensorHub_req_send(&req, &len, 1);
+ if (err)
+ {
+ SCP_ERR("SCP_sensorHub_req_send fail!\n");
+ }
+
+ switch (sensorType)
+ {
+ case ID_STEP_COUNTER:
+ *((u32*)value) = *(req.get_data_rsp.int32_Data);
+ break;
+ case ID_STEP_DETECTOR:
+ *((u32*)value) = *(req.get_data_rsp.int32_Data);
+ break;
+ case ID_SIGNIFICANT_MOTION:
+ *((u32*)value) = *(req.get_data_rsp.int32_Data);
+ break;
+ case ID_PEDOMETER://there are 4 values in pedometer
+ *(u32*)value = *req.get_data_rsp.int32_Data;
+ *((u32*)value+1) = *(req.get_data_rsp.int32_Data+1);
+ *((u32*)value+2) = *(req.get_data_rsp.int32_Data+2);
+ *((u32*)value+3) = *(req.get_data_rsp.int32_Data+3);
+ SCP_LOG("ID_PEDOMETER, value=%d value1=%d value2=%d value3=%d\n",
+ *((u32*)value), *((u32*)value+1), *((u32*)value+2), *((u32*)value+3));
+ break;
+ case ID_HEART_RATE://there are 4 values in pedometer
+ *(u32*)value = *req.get_data_rsp.int32_Data;
+ *((u32*)value+1) = *(req.get_data_rsp.int32_Data+1);
+ SCP_LOG("ID_HEART_RATE, value=%d value1=%d \n",
+ *((u32*)value), *((u32*)value+1));
+ break;
+ default:
+ err = -1;
+ break;
+ }
+ SCP_LOG("sensorType = %d, value = %d\n", sensorType, *((u32 *)value));
+ return err;
+}
+
+static int SCP_sensor_get_data(int sensorType, void *value, int *status)
+{
+ SCP_SENSOR_HUB_DATA req;
+ int len;
+ int err = 0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ req.get_data_req.sensorType = sensorType;
+ req.get_data_req.action = SENSOR_HUB_GET_DATA;
+ len = sizeof(req.get_data_req);
+ err = SCP_sensorHub_req_send(&req, &len, 1);
+ if (err)
+ {
+ SCP_ERR("SCP_sensorHub_req_send fail!\n");
+ }
+
+ switch (sensorType)
+ {
+ case ID_STEP_COUNTER:
+ *((u64 *)value) = *(req.get_data_rsp.int32_Data);
+ break;
+ case ID_STEP_DETECTOR:
+ *((u64 *)value) = *(req.get_data_rsp.int32_Data);
+ break;
+ case ID_SIGNIFICANT_MOTION:
+ *((u64 *)value) = *(req.get_data_rsp.int32_Data);
+ break;
+ case ID_HEART_RATE://there are 2 values in heart rate
+ *(u64 *)value = *req.get_data_rsp.int32_Data;
+ *((u64 *)value+1) = *(req.get_data_rsp.int32_Data+1);
+ SCP_LOG("ID_PEDOMETER, value=%lld value1=%lld\n",
+ *((u64 *)value), *((u64 *)value+1));
+ break;
+ case ID_PEDOMETER://there are 4 values in pedometer
+ *(u64 *)value = *req.get_data_rsp.int32_Data;
+ *((u64 *)value+1) = *(req.get_data_rsp.int32_Data+1);
+ *((u64 *)value+2) = *(req.get_data_rsp.int32_Data+2);
+ *((u64 *)value+3) = *(req.get_data_rsp.int32_Data+3);
+ SCP_LOG("ID_PEDOMETER, value=%lld value1=%lld value2=%lld value3=%lld\n",
+ *((u64 *)value), *((u64 *)value+1), *((u64 *)value+2), *((u64 *)value+3));
+ break;
+ case ID_ACTIVITY://there are 6 values in activity
+ *(u64 *)value = *req.get_data_rsp.int16_Data;
+ *((u64 *)value+1) = *(req.get_data_rsp.int16_Data+1);
+ *((u64 *)value+2) = *(req.get_data_rsp.int16_Data+2);
+ *((u64 *)value+3) = *(req.get_data_rsp.int16_Data+3);
+ *((u64 *)value+4) = *(req.get_data_rsp.int16_Data+4);
+ *((u64 *)value+5) = *(req.get_data_rsp.int16_Data+5);
+ *(u64 *)value &= 0xFFFF;
+ *((u64 *)value+1) &= 0xFFFF;
+ *((u64 *)value+2) &= 0xFFFF;
+ *((u64 *)value+3) &= 0xFFFF;
+ *((u64 *)value+4) &= 0xFFFF;
+ *((u64 *)value+5) &= 0xFFFF;
+ SCP_LOG("ID_ACTIVITY 16, Data=%d Data1=%d Data2=%d Data3=%d Data4=%d Data5=%d\n",
+ *req.get_data_rsp.int16_Data, *(req.get_data_rsp.int16_Data+1), *(req.get_data_rsp.int16_Data+2),
+ *(req.get_data_rsp.int16_Data+3), *(req.get_data_rsp.int16_Data+4), *(req.get_data_rsp.int16_Data+5));
+ SCP_LOG("ID_ACTIVITY 64, value=%lld value1=%lld value2=%lld value3=%lld value4=%lld value5=%lld\n",
+ *((u64 *)value), *((u64 *)value+1), *((u64 *)value+2), *((u64 *)value+3), *((u64 *)value+4), *((u64 *)value+5));
+ break;
+ case ID_IN_POCKET:
+ *((u64 *)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_PICK_UP_GESTURE:
+ *((u64 *)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_FACE_DOWN:
+ *((u64 *)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_SHAKE:
+ *((u64 *)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_TILT_DETECTOR:
+ *((u64 *)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_WAKE_GESTURE:
+ *((u64 *)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ case ID_GLANCE_GESTURE:
+ *((u64 *)value) = *(req.get_data_rsp.int16_Data);
+ break;
+ default:
+ err = -1;
+ break;
+ }
+
+ SCP_LOG("sensorType = %d, value = %lld\n", sensorType, *((u64 *)value));
+
+ return err;
+}
+static int SCP_sensorHub_notify_handler(void* data, uint len)
+{
+ SCP_SENSOR_HUB_DATA_P rsp = (SCP_SENSOR_HUB_DATA_P)data;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ if (SCP_TRC_IPI == atomic_read(&(obj_data->trace)))
+ SCP_LOG("len = %d, type = %d, action = %d, errCode = %d\n", len, rsp->rsp.sensorType, rsp->rsp.action, rsp->rsp.errCode);
+
+ if(!obj_data)
+ {
+ return -1;
+ }
+
+ switch(rsp->rsp.action)
+ {
+ case SENSOR_HUB_NOTIFY:
+ SCP_LOG("SENSOR_HUB_NOTIFY sensorId = %d\n", rsp->notify_rsp.sensorType);
+ switch(rsp->notify_rsp.event)
+ {
+ case SCP_NOTIFY:
+ if (ID_STEP_DETECTOR == rsp->notify_rsp.sensorType)
+ {
+ schedule_work(&(obj_data->sd_work));
+ }
+ else if (ID_SIGNIFICANT_MOTION == rsp->notify_rsp.sensorType)
+ {
+ wake_lock(&sig_lock);
+ schedule_work(&(obj_data->sig_work));
+ }
+ else if (ID_IN_POCKET == rsp->notify_rsp.sensorType)
+ {
+ schedule_work(&(obj_data->inpk_work));
+ }
+ else if (ID_PICK_UP_GESTURE == rsp->notify_rsp.sensorType)
+ {
+ schedule_work(&(obj_data->pkup_work));
+ }
+ else if (ID_FACE_DOWN == rsp->notify_rsp.sensorType)
+ {
+ schedule_work(&(obj_data->fdn_work));
+ }
+ else if (ID_SHAKE == rsp->notify_rsp.sensorType)
+ {
+ schedule_work(&(obj_data->shk_work));
+ }
+ else if (ID_TILT_DETECTOR == rsp->notify_rsp.sensorType)
+ {
+ schedule_work(&(obj_data->tilt_work));
+ }
+ else if (ID_WAKE_GESTURE == rsp->notify_rsp.sensorType)
+ {
+ schedule_work(&(obj_data->wag_work));
+ }
+ else if (ID_GLANCE_GESTURE == rsp->notify_rsp.sensorType)
+ {
+ schedule_work(&(obj_data->glg_work));
+ }
+ else
+ {
+ SCP_ERR("Unknow notify");
+ }
+ break;
+ default:
+ SCP_ERR("Error sensor hub notify");
+ break;
+ }
+ break;
+ default:
+ SCP_ERR("Error sensor hub action");
+ break;
+ }
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+#ifdef CONFIG_CUSTOM_KERNEL_HEART_RATE_SENSOR
+//static void SCP_hrm_work(struct work_struct *work)
+//{
+// if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+// SCP_FUN();
+//
+// hrm_notify();
+//}
+//static int hrm_enable(int en)
+//{
+// if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+// SCP_FUN();
+//
+// return SCP_sensor_enable(ID_HEART_RATE, en);
+//}
+static int hrm_get_data(u32 *value, int *status)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data32(ID_HEART_RATE, value, status);
+}
+static int hrm_open_report_data(int open)//open data rerport to HAL
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int hrm_enable_nodata(int en)//only enable not report event to HAL
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_HEART_RATE, en);
+}
+static int hrm_set_delay(u64 delay)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_set_delay(ID_HEART_RATE, delay);
+}
+static int SCP_sensorHub_heart_rate_init()
+{
+ struct hrm_control_path ctl={0};
+ struct hrm_data_path data={0};
+ int err=0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ ctl.open_report_data= hrm_open_report_data;
+ ctl.enable_nodata = hrm_enable_nodata;
+ ctl.set_delay = hrm_set_delay;
+ ctl.is_report_input_direct = false;
+ ctl.is_support_batch = true;
+ err = hrm_register_control_path(&ctl);
+ if(err)
+ {
+ printk("register heart_rate control path err\n");
+ return -1;
+ }
+
+ data.get_data = hrm_get_data;
+ //data.vender_div = 1;
+ err = hrm_register_data_path(&data);
+ if(err)
+ {
+ printk("register heart_rate data path err\n");
+ return -1;
+ }
+ return 0;
+}
+static int SCP_sensorHub_heart_rate_uninit()
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_HEART_RATE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_PEDOMETER
+//static void SCP_hrm_work(struct work_struct *work)
+//{
+// if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+// SCP_FUN();
+//
+// pdr_notify();
+//}
+//static int pdr_enable(int en)
+//{
+// if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+// SCP_FUN();
+//
+// return SCP_sensor_enable(ID_PEDOMETER, en);
+//}
+static int pdr_get_data(u32 *value, int *status)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data32(ID_PEDOMETER, value, status);
+}
+static int pdr_open_report_data(int open)//open data rerport to HAL
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int pdr_enable_nodata(int en)//only enable not report event to HAL
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_PEDOMETER, en);
+}
+static int pdr_set_delay(u64 delay)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_set_delay(ID_PEDOMETER, delay);
+}
+static int SCP_sensorHub_pedometer_init()
+{
+ struct pdr_control_path ctl={0};
+ struct pdr_data_path data={0};
+ int err=0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ ctl.open_report_data= pdr_open_report_data;
+ ctl.enable_nodata = pdr_enable_nodata;
+ ctl.set_delay = pdr_set_delay;
+ ctl.is_report_input_direct = false;
+ ctl.is_support_batch = true;
+ err = pdr_register_control_path(&ctl);
+ if(err)
+ {
+ printk("register pedometer control path err\n");
+ return -1;
+ }
+
+ data.get_data = pdr_get_data;
+ //data.vender_div = 1;
+ err = pdr_register_data_path(&data);
+ if(err)
+ {
+ printk("register pedometer data path err\n");
+ return -1;
+ }
+ return 0;
+}
+static int SCP_sensorHub_pedometer_uninit()
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_PEDOMETER
+/*----------------------------------------------------------------------------*/
+#ifdef CONFIG_CUSTOM_KERNEL_ACTIVITY_SENSOR
+//static void SCP_act_work(struct work_struct *work)
+//{
+// if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+// SCP_FUN();
+//
+// act_notify();
+//}
+//static int act_enable(int en)
+//{
+// if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+// SCP_FUN();
+//
+// return SCP_sensor_enable(ID_ACTIVITY, en);
+//}
+static int act_get_data(u16 *value ,int *status)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data16(ID_ACTIVITY, value, status);
+}
+static int act_open_report_data(int open)//open data rerport to HAL
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int act_enable_nodata(int en)//only enable not report event to HAL
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_ACTIVITY, en);
+}
+static int act_set_delay(u64 delay)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_set_delay(ID_ACTIVITY, delay);
+}
+static int SCP_sensorHub_activity_init()
+{
+ struct act_control_path ctl={0};
+ struct act_data_path data={0};
+ int err=0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ ctl.open_report_data= act_open_report_data;
+ ctl.enable_nodata = act_enable_nodata;
+ ctl.set_delay = act_set_delay;
+ ctl.is_report_input_direct = false;
+ ctl.is_support_batch = true;
+ err = act_register_control_path(&ctl);
+ if(err)
+ {
+ printk("register pedometer control path err\n");
+ return -1;
+ }
+
+ data.get_data = act_get_data;
+ //data.vender_div = 1;
+ err = act_register_data_path(&data);
+ if(err)
+ {
+ printk("register pedometer data path err\n");
+ return -1;
+ }
+ return 0;
+}
+static int SCP_sensorHub_activity_uninit()
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_ACTIVITY_SENSOR
+/*----------------------------------------------------------------------------*/
+#ifdef CONFIG_CUSTOM_KERNEL_IN_POCKET_SENSOR
+static void SCP_inpk_work(struct work_struct *work)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ inpk_notify();
+}
+static int inpk_open_report_data(int open)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_IN_POCKET, open);
+}
+static int inpk_get_data(u16 *value, int *status )
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data16(ID_IN_POCKET, value, status);
+}
+static int SCP_sensorHub_in_pocket_init()
+{
+ struct inpk_control_path ctl={0};
+ struct inpk_data_path data={0};
+ int err=0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ ctl.open_report_data = inpk_open_report_data;
+ err = inpk_register_control_path(&ctl);
+ if(err)
+ {
+ printk("register in pocket control path err\n");
+ return -1;
+ }
+ data.get_data = inpk_get_data;
+ err = inpk_register_data_path(&data);
+ if(err)
+ {
+ printk("register in pocket data path err\n");
+ return -1;
+ }
+ SCP_sensorHub_rsp_registration(ID_IN_POCKET, SCP_sensorHub_notify_handler);
+ return 0;
+}
+static int SCP_sensorHub_in_pocket_uninit()
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_IN_POCKET_SENSOR
+/*----------------------------------------------------------------------------*/
+#ifdef CONFIG_CUSTOM_KERNEL_SHAKE_SENSOR
+static void SCP_shk_work(struct work_struct *work)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ shk_notify();
+}
+static int shk_open_report_data(int open)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_SHAKE, open);
+}
+static int shk_get_data(u16 *value, int *status )
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data16(ID_SHAKE, value, status);
+}
+static int SCP_sensorHub_shake_init()
+{
+ struct shk_control_path ctl={0};
+ struct shk_data_path data={0};
+ int err=0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ ctl.open_report_data = shk_open_report_data;
+ err = shk_register_control_path(&ctl);
+ if(err)
+ {
+ printk("register shake control path err\n");
+ return -1;
+ }
+ data.get_data = shk_get_data;
+ err = shk_register_data_path(&data);
+ if(err)
+ {
+ printk("register shake data path err\n");
+ return -1;
+ }
+ SCP_sensorHub_rsp_registration(ID_SHAKE, SCP_sensorHub_notify_handler);
+ return 0;
+}
+static int SCP_sensorHub_shake_uninit()
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_SHAKE_SENSOR
+/*----------------------------------------------------------------------------*/
+#ifdef CONFIG_CUSTOM_KERNEL_PICK_UP_SENSOR
+static void SCP_pkup_work(struct work_struct *work)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ pkup_notify();
+}
+static int pkup_open_report_data(int open)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_PICK_UP_GESTURE, open);
+}
+static int pkup_get_data(u16 *value , int *status)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data16(ID_PICK_UP_GESTURE, value, status);
+}
+static int SCP_sensorHub_pick_up_init()
+{
+ struct pkup_control_path ctl={0};
+ struct pkup_data_path data={0};
+ int err=0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ ctl.open_report_data = pkup_open_report_data;
+ err = pkup_register_control_path(&ctl);
+ if(err)
+ {
+ printk("register pick up control path err\n");
+ return -1;
+ }
+ data.get_data = pkup_get_data;
+ err = pkup_register_data_path(&data);
+ if(err)
+ {
+ printk("register pick up data path err\n");
+ return -1;
+ }
+ SCP_sensorHub_rsp_registration(ID_PICK_UP_GESTURE, SCP_sensorHub_notify_handler);
+ return 0;
+}
+static int SCP_sensorHub_pick_up_uninit()
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_PICK_UP_SENSOR
+/*----------------------------------------------------------------------------*/
+#ifdef CONFIG_CUSTOM_KERNEL_FACE_DOWN_SENSOR
+static void SCP_fdn_work(struct work_struct *work)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ fdn_notify();
+}
+static int fdn_open_report_data(int open)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_FACE_DOWN, open);
+}
+static int fdn_get_data(u16 *value , int *status)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data16(ID_FACE_DOWN, value, status);
+}
+static int SCP_sensorHub_face_down_init()
+{
+ struct fdn_control_path ctl={0};
+ struct fdn_data_path data={0};
+ int err=0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ ctl.open_report_data = fdn_open_report_data;
+ err = fdn_register_control_path(&ctl);
+ if(err)
+ {
+ printk("register face down control path err\n");
+ return -1;
+ }
+ data.get_data = fdn_get_data;
+ err = fdn_register_data_path(&data);
+ if(err)
+ {
+ printk("register face down data path err\n");
+ return -1;
+ }
+ SCP_sensorHub_rsp_registration(ID_FACE_DOWN, SCP_sensorHub_notify_handler);
+ return 0;
+}
+static int SCP_sensorHub_face_down_uninit()
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_FACE_DOWN_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_TILT_DETECTOR_SENSOR
+static void SCP_tilt_work(struct work_struct *work)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ tilt_notify();
+}
+static int tilt_open_report_data(int open)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_TILT_DETECTOR, open);
+}
+static int tilt_get_data(u16 *value, int *status )
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data16(ID_TILT_DETECTOR, value, status);
+}
+static int SCP_sensorHub_tilt_detector_init()
+{
+ struct tilt_control_path ctl={0};
+ struct tilt_data_path data={0};
+ int err=0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ ctl.open_report_data = tilt_open_report_data;
+ err = tilt_register_control_path(&ctl);
+ if(err)
+ {
+ printk("register tilt_detector control path err\n");
+ return -1;
+ }
+ data.get_data = tilt_get_data;
+ err = tilt_register_data_path(&data);
+ if(err)
+ {
+ printk("register tilt_detector data path err\n");
+ return -1;
+ }
+ SCP_sensorHub_rsp_registration(ID_TILT_DETECTOR, SCP_sensorHub_notify_handler);
+ return 0;
+}
+static int SCP_sensorHub_tilt_detector_uninit()
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_TILT_DETECTOR_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_WAKE_GESTURE_SENSOR
+static void SCP_wag_work(struct work_struct *work)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ wag_notify();
+}
+static int wag_open_report_data(int open)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_WAKE_GESTURE, open);
+}
+static int wag_get_data(u16 *value, int *status )
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data16(ID_WAKE_GESTURE, value, status);
+}
+static int SCP_sensorHub_wake_gesture_init()
+{
+ struct wag_control_path ctl={0};
+ struct wag_data_path data={0};
+ int err=0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ ctl.open_report_data = wag_open_report_data;
+ err = wag_register_control_path(&ctl);
+ if(err)
+ {
+ printk("register wake_gesture control path err\n");
+ return -1;
+ }
+ data.get_data = wag_get_data;
+ err = wag_register_data_path(&data);
+ if(err)
+ {
+ printk("register wake_gesture data path err\n");
+ return -1;
+ }
+ SCP_sensorHub_rsp_registration(ID_WAKE_GESTURE, SCP_sensorHub_notify_handler);
+ return 0;
+}
+static int SCP_sensorHub_wake_gesture_uninit()
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_WAKE_GESTURE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_GLANCE_GESTURE_SENSOR
+static void SCP_glg_work(struct work_struct *work)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ glg_notify();
+}
+static int glg_open_report_data(int open)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_GLANCE_GESTURE, open);
+}
+static int glg_get_data(u16 *value, int *status )
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data16(ID_GLANCE_GESTURE, value, status);
+}
+static int SCP_sensorHub_glance_gesture_init()
+{
+ struct glg_control_path ctl={0};
+ struct glg_data_path data={0};
+ int err=0;
+
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ ctl.open_report_data = glg_open_report_data;
+ err = glg_register_control_path(&ctl);
+ if(err)
+ {
+ printk("register glance_gesture control path err\n");
+ return -1;
+ }
+ data.get_data = glg_get_data;
+ err = glg_register_data_path(&data);
+ if(err)
+ {
+ printk("register glance_gesture data path err\n");
+ return -1;
+ }
+ SCP_sensorHub_rsp_registration(ID_GLANCE_GESTURE, SCP_sensorHub_notify_handler);
+ return 0;
+}
+static int SCP_sensorHub_glance_gesture_uninit()
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_GLANCE_GESTURE_SENSOR
+
+#ifdef CONFIG_CUSTOM_KERNEL_STEP_COUNTER
+static void SCP_sd_work(struct work_struct *work)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ step_notify(TYPE_STEP_DETECTOR);
+}
+/*----------------------------------------------------------------------------*/
+static void SCP_sig_work(struct work_struct *work)
+{
+ if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ mod_timer(&obj_data->notify_timer, jiffies + HZ/5);
+ step_notify(TYPE_SIGNIFICANT);
+}
+
+static void notify_ap_timeout(unsigned long data)
+{
+ wake_unlock(&sig_lock);
+}
+/*----------------------------------------------------------------------------*/
+//static int SCP_sensorHub_sd_handler(void* data, uint len)
+//{
+// SCP_SENSOR_HUB_DATA_P rsp = (SCP_SENSOR_HUB_DATA_P)data;
+//
+// if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+// SCP_FUN();
+//
+// if (SCP_TRC_IPI == atomic_read(&(obj_data->trace)))
+// SCP_LOG("len = %d, type = %d, action = %d, errCode = %d\n", len, rsp->rsp.sensorType, rsp->rsp.action, rsp->rsp.errCode);
+//
+// if(!obj_data)
+// {
+// return -1;
+// }
+//
+// switch(rsp->rsp.action)
+// {
+// case SENSOR_HUB_NOTIFY:
+// switch(rsp->notify_rsp.event)
+// {
+// case SCP_NOTIFY:
+// if (ID_STEP_DETECTOR == rsp->notify_rsp.sensorType)
+// {
+// schedule_work(&(obj_data->sd_work));
+// }
+// else
+// {
+// SCP_ERR("Unknow notify");
+// }
+// break;
+// default:
+// SCP_ERR("Error sensor hub notify");
+// break;
+// }
+// break;
+// default:
+// SCP_ERR("Error sensor hub action");
+// break;
+// }
+//
+// return 0;
+//}
+///*----------------------------------------------------------------------------*/
+//static int SCP_sensorHub_sig_handler(void* data, uint len)
+//{
+// SCP_SENSOR_HUB_DATA_P rsp = (SCP_SENSOR_HUB_DATA_P)data;
+//
+// if (SCP_TRC_FUN == atomic_read(&(obj_data->trace)))
+// SCP_FUN();
+//
+// if (SCP_TRC_IPI == atomic_read(&(obj_data->trace)))
+// SCP_LOG("len = %d, type = %d, action = %d, errCode = %d\n", len, rsp->rsp.sensorType, rsp->rsp.action, rsp->rsp.errCode);
+//
+// if(!obj_data)
+// {
+// return -1;
+// }
+//
+// switch(rsp->rsp.action)
+// {
+// case SENSOR_HUB_NOTIFY:
+// switch(rsp->notify_rsp.event)
+// {
+// case SCP_NOTIFY:
+// if (ID_SIGNIFICANT_MOTION == rsp->notify_rsp.sensorType)
+// {
+// schedule_work(&(obj_data->sig_work));
+// }
+// else
+// {
+// SCP_ERR("Unknow notify");
+// }
+// break;
+// default:
+// SCP_ERR("Error sensor hub notify");
+// break;
+// }
+// break;
+// default:
+// SCP_ERR("Error sensor hub action");
+// break;
+// }
+//
+// return 0;
+//}
+
+/*----------------------------------------------------------------------------*/
+static int step_counter_open_report_data(int open)//open data rerport to HAL
+{
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int step_counter_enable_nodata(int en)//only enable not report event to HAL
+{
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_STEP_COUNTER, en);
+}
+/*----------------------------------------------------------------------------*/
+static int step_detect_enable(int en)
+{
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_STEP_DETECTOR, en);
+}
+/*----------------------------------------------------------------------------*/
+static int significant_motion_enable(int en)
+{
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_enable(ID_SIGNIFICANT_MOTION, en);
+}
+/*----------------------------------------------------------------------------*/
+static int step_counter_set_delay(u64 delay)
+{
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int step_counter_get_data(u32 *value, int *status)
+{
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ *status = 3;
+ return SCP_sensor_get_data32(ID_STEP_COUNTER, value, status);
+}
+/*----------------------------------------------------------------------------*/
+static int step_detect_get_data(u32 *value , int *status)
+{
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data32(ID_STEP_DETECTOR, value, status);
+}
+/*----------------------------------------------------------------------------*/
+static int significant_motion_get_data(u32 *value , int *status)
+{
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return SCP_sensor_get_data32(ID_SIGNIFICANT_MOTION, value, status);
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_step_counter_init()
+{
+ struct step_c_control_path ctl={0};
+ struct step_c_data_path data={0};
+ int err=0;
+
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ //register step
+ ctl.open_report_data= step_counter_open_report_data;
+ ctl.enable_nodata = step_counter_enable_nodata;
+ ctl.set_delay = step_counter_set_delay;
+ ctl.is_report_input_direct = false;
+ ctl.is_support_batch = true;
+
+ ctl.enable_significant = significant_motion_enable;
+ ctl.enable_step_detect = step_detect_enable;
+
+ err = step_c_register_control_path(&ctl);
+ if(err)
+ {
+ printk("register step_counter control path err\n");
+ return -1;
+
+ }
+
+ data.get_data = step_counter_get_data;
+ data.get_data_significant = significant_motion_get_data;
+ data.get_data_step_d = step_detect_get_data;
+ data.vender_div = 1;
+ err = step_c_register_data_path(&data);
+ if(err)
+ {
+ printk("register step counter data path err\n");
+ return -1;
+ }
+
+ wake_lock_init(&sig_lock,WAKE_LOCK_SUSPEND,"signficiant wakelock");
+
+ SCP_sensorHub_rsp_registration(ID_SIGNIFICANT_MOTION, SCP_sensorHub_notify_handler);
+ SCP_sensorHub_rsp_registration(ID_STEP_DETECTOR, SCP_sensorHub_notify_handler);
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_step_counter_uninit()
+{
+ if (SCP_TRC_FUN & atomic_read(&(obj_data->trace)))
+ SCP_FUN();
+
+ return 0;
+}
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_STEP_COUNTER
+
+/*----------------------------------------------------------------------------*/
+static int SCP_sensorHub_local_init(void)
+{
+ SCP_sensorHub_probe();
+
+ if(-1 == SCP_sensorHub_init_flag)
+ {
+ return -1;
+ }
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int __init SCP_sensorHub_init(void)
+{
+ SCP_FUN();
+ batch_driver_add(&SCP_sensorHub_init_info);
+#ifdef CONFIG_CUSTOM_KERNEL_STEP_COUNTER
+ step_c_driver_add(&SCP_step_counter_init_info);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_STEP_COUNTER
+#ifdef CONFIG_CUSTOM_KERNEL_IN_POCKET_SENSOR
+ inpk_driver_add(&SCP_in_pocket_init_info);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_IN_POCKET_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_PEDOMETER
+ pdr_driver_add(&SCP_pedometer_init_info);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_PEDOMETER
+#ifdef CONFIG_CUSTOM_KERNEL_ACTIVITY_SENSOR
+ act_driver_add(&SCP_activity_init_info);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_ACTIVITY_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_SHAKE_SENSOR
+ shk_driver_add(&SCP_shake_init_info);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_SHAKE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_PICK_UP_SENSOR
+ pkup_driver_add(&SCP_pick_up_init_info);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_PICK_UP_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_FACE_DOWN_SENSOR
+ fdn_driver_add(&SCP_face_down_init_info);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_FACE_DOWN_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_HEART_RATE_SENSOR
+ hrm_driver_add(&SCP_heart_rate_init_info);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_HEART_RATE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_TILT_DETECTOR_SENSOR
+ tilt_driver_add(&SCP_tilt_detector_init_info);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_TILT_DETECTOR_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_WAKE_GESTURE_SENSOR
+ wag_driver_add(&SCP_wake_gesture_init_info);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_WAKE_GESTURE_SENSOR
+#ifdef CONFIG_CUSTOM_KERNEL_GLANCE_GESTURE_SENSOR
+ glg_driver_add(&SCP_glance_gesture_init_info);
+#endif //#ifdef CONFIG_CUSTOM_KERNEL_GLANCE_GESTURE_SENSOR
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static void __exit SCP_sensorHub_exit(void)
+{
+ SCP_FUN();
+}
+/*----------------------------------------------------------------------------*/
+//late_initcall(SCP_sensorHub_init);
+module_init(SCP_sensorHub_init);
+module_exit(SCP_sensorHub_exit);
+/*----------------------------------------------------------------------------*/
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SCP sensor hub driver");
+MODULE_AUTHOR("andrew.yang@mediatek.com");
diff --git a/drivers/misc/mediatek/sensorHub/SCP_shf/Makefile b/drivers/misc/mediatek/sensorHub/SCP_shf/Makefile
new file mode 100755
index 000000000..ec0826c1d
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/SCP_shf/Makefile
@@ -0,0 +1,3 @@
+include $(srctree)/drivers/misc/mediatek/Makefile.custom
+
+obj-y := shf_kernel.o
diff --git a/drivers/misc/mediatek/sensorHub/SCP_shf/shf_kernel.c b/drivers/misc/mediatek/sensorHub/SCP_shf/shf_kernel.c
new file mode 100644
index 000000000..b4671f5dd
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/SCP_shf/shf_kernel.c
@@ -0,0 +1,405 @@
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include <cust_acc.h>
+
+#include <mach/md32_ipi.h>
+#include <mach/mt_gpio.h>
+#include <mach/mt_pm_ldo.h>
+#include <mach/mt_typedefs.h>
+
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/irq.h>
+#include <linux/kobject.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wakelock.h>
+#include <linux/workqueue.h>
+
+#include "shf_kernel.h"
+
+/*----------------------------------------------------------------------------*/
+#define SHF_TAG "[shf_kernel] "
+#define SHF_FUN(f) printk( SHF_TAG"%s\n", __FUNCTION__)
+#define SHF_ERR(fmt, args...) printk(KERN_ERR SHF_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args)
+#define SHF_LOG(fmt, args...) printk( SHF_TAG fmt, ##args)
+/*----------------------------------------------------------------------------*/
+
+//static bool shf_ring_buffer_empty = true;
+static int shf_init_flag = -1; //0->ok, -1->fail
+static struct platform_driver shf_driver;
+struct wake_lock shf_suspend_lock;
+
+static DEFINE_SPINLOCK(shf_spinlock);
+bool ring_buffer_poll(ipi_buffer_t* buffer, ipi_data_t* data)
+{
+ unsigned long flags = 0;
+ spin_lock_irqsave(&shf_spinlock, flags);
+ SHF_LOG("poll: head=%zu, tail=%zu\n", buffer->head, buffer->tail);
+ if (data && buffer->head != buffer->tail) {
+ memcpy(data, buffer->data + buffer->head, sizeof(ipi_data_t));
+ buffer->head = (buffer->head + 1) % buffer->size;
+ spin_unlock_irqrestore(&shf_spinlock, flags);
+ return true;
+ }
+ spin_unlock_irqrestore(&shf_spinlock, flags);
+ return false;
+}
+
+bool ring_buffer_push(ipi_buffer_t* buffer, void* data, size_t size)
+{
+ unsigned long flags = 0;
+ spin_lock_irqsave(&shf_spinlock, flags);
+ SHF_LOG("push: head=%zu, tail=%zu, size=%zu\n", buffer->head, buffer->tail, size);
+ if ((buffer->tail + 1) % buffer->size != buffer->head) {
+ ipi_data_t* dst = buffer->data + buffer->tail;
+ memcpy((void*)dst, data, size);
+ dst->size = size;
+ buffer->tail = (buffer->tail + 1) % buffer->size;
+ spin_unlock_irqrestore(&shf_spinlock, flags);
+ return true;
+ }
+ spin_unlock_irqrestore(&shf_spinlock, flags);
+ return false;
+}
+/******************************************************************/
+//cach ipi message to buffer, so ipi callback will return quickly.
+#define IPI_TRIGGER_BUFFER_COUNT (32)
+
+static ipi_data_t trigger_data[IPI_TRIGGER_BUFFER_COUNT];
+static ipi_buffer_t trigger_buffer = {
+ .head = 0,
+ .tail = 0,
+ .size = IPI_TRIGGER_BUFFER_COUNT,
+ .data = trigger_data,
+};
+
+///******************************************************************/
+static DECLARE_WAIT_QUEUE_HEAD(data_wq);
+static void event_init(void)
+{
+ init_waitqueue_head(&data_wq);
+}
+
+static void event_destroy(void)
+{
+ //event_destroy(&shf_event);
+}
+
+static int wait(void)
+{
+ int ret;
+ ret = wait_event_interruptible(data_wq, trigger_buffer.head != trigger_buffer.tail);
+ if (ret) {
+ SHF_ERR("wait: head=0x%zx, tail=0x%zx, ret=%d\n", trigger_buffer.head, trigger_buffer.tail, ret);
+ }
+ return ret;
+}
+
+static void notify(void)
+{
+ wake_up(&data_wq);
+ wake_lock_timeout(&shf_suspend_lock, HZ / 2);
+}
+/******************************************************************************
+ * Function Configuration
+******************************************************************************/
+static ssize_t show_chipinfo_value(struct device_driver *ddri, char *buf)
+{
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static ssize_t show_buffer_value(struct device_driver *ddri, char *buf)
+{
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static DRIVER_ATTR(chipinfo, S_IWUSR | S_IRUGO, show_chipinfo_value, NULL);
+static DRIVER_ATTR(buffer, S_IWUSR | S_IRUGO, show_buffer_value, NULL);
+/*----------------------------------------------------------------------------*/
+static struct driver_attribute *shf_attr_list[] = {
+ &driver_attr_chipinfo, /*chip information*/
+ &driver_attr_buffer, /*dump buffer data*/
+};
+/*----------------------------------------------------------------------------*/
+static int shf_create_attr(struct device_driver *driver)
+{
+ int idx, err = 0;
+ int num = (int)(sizeof(shf_attr_list)/sizeof(shf_attr_list[0]));
+ if (driver == NULL) {
+ return -EINVAL;
+ }
+
+ for(idx = 0; idx < num; idx++) {
+ if((err = driver_create_file(driver, shf_attr_list[idx])) != 0) {
+ SHF_ERR("driver_create_file (%s) = %d\n", shf_attr_list[idx]->attr.name, err);
+ break;
+ }
+ }
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+static int shf_delete_attr(struct device_driver *driver)
+{
+ int idx ,err = 0;
+ int num = (int)(sizeof(shf_attr_list)/sizeof(shf_attr_list[0]));
+
+ if(driver == NULL) {
+ return -EINVAL;
+ }
+
+ for(idx = 0; idx < num; idx++) {
+ driver_remove_file(driver, shf_attr_list[idx]);
+ }
+
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+static int shf_open(struct inode *inode, struct file *file)
+{
+ SHF_FUN();
+ //Now, we don't hava any private data
+ file->private_data = NULL;
+ return nonseekable_open(inode, file);
+}
+/*----------------------------------------------------------------------------*/
+static int shf_release(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+/*
+static void shf_print_bytes(void* buffer, size_t size) {
+ uint8_t* data;
+ int i;
+ if (!buffer) {
+ SHF_ERR("print: null\n");
+ return;
+ }
+ data = (uint8_t*)buffer;
+ SHF_LOG("print: size=%d. ", size);
+ for (i = 0; i < size; i++) {
+ SHF_LOG("0x%.2x ", *(data + i));
+ }
+ SHF_LOG("\n");
+}
+*/
+/*----------------------------------------------------------------------------*/
+static long shf_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ ipi_data_t in_data;
+ ipi_data_t out_data;
+ void __user *data;
+ long err = 0;
+ ipi_status status = DONE;
+ ipi_status pre_status = DONE;
+
+ if (shf_init_flag != 0) {
+ SHF_ERR("IOCTL: initflag=%d\n", shf_init_flag);
+ return -EFAULT;//TODO should check error no
+ }
+ /*
+ if(_IOC_DIR(cmd) & _IOC_READ) {
+ err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
+ }
+ else if(_IOC_DIR(cmd) & _IOC_WRITE) {
+ err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
+ }
+
+ if(err) {
+ SHF_ERR("access error: %08X, (%2d, %2d)\n", cmd, _IOC_DIR(cmd), _IOC_SIZE(cmd));
+ return -EFAULT;
+ }
+ */
+ switch(cmd) {
+ case SHF_IPI_SEND:
+ //SHF_LOG("IOCTL: SHF_IPI_SEND\n");
+ data = (void __user *) arg;
+ if(copy_from_user((void*)&in_data, data, sizeof(ipi_data_t))) {
+ err = -EFAULT;
+ SHF_ERR("SHF_IPI_SEND: copy failed!\n");
+ break;
+ }
+ //shf_print_bytes(in_data.data, in_data.size);
+ do {
+ status = md32_ipi_send(IPI_SHF, in_data.data, in_data.size, 0);
+ if (status != pre_status || DONE == pre_status)
+ SHF_LOG("SHF_IPI_SEND: size=%zu, status=%d\n", in_data.size, status);
+ err = status;
+ pre_status = status;
+ } while(DONE != status);
+ mdelay(10);
+ //SHF_LOG("SHF_IPI_SEND: delayed 10ms.\n");
+ break;
+ case SHF_IPI_POLL:
+ //SHF_LOG("IOCTL: SHF_IPI_POLL\n");
+ data = (void __user*)arg;
+ if(data == NULL) {
+ err = -EINVAL;
+ break;
+ }
+ memset(&out_data, 0, sizeof(ipi_data_t));
+ if (trigger_buffer.head == trigger_buffer.tail) {
+ if (wait()) {
+ err = -EINTR;
+ break;
+ }
+ }
+ if(!ring_buffer_poll(&trigger_buffer, &out_data)) {
+ err = -EFAULT;
+ SHF_ERR("SHF_IPI_POLL: failed!\n");
+ break;
+ }
+ if(copy_to_user(data, &out_data, sizeof(ipi_data_t))) {
+ err = -EFAULT;
+ SHF_ERR("SHF_IPI_POLL: copy failed!\n");
+ break;
+ }
+ break;
+ case SHF_GESTURE_ENABLE:
+ //SHF_LOG("IOCTL: SHF_GESTURE_ENABLE. enable=%d\n", arg);
+#ifdef CONFIG_MTK_SENSOR_HUB_SUPPORT
+ tpd_scp_wakeup_enable(arg);
+#endif
+ break;
+ default:
+ SHF_ERR("unknown IOCTL: 0x%08x\n", cmd);
+ err = -ENOIOCTLCMD;
+ break;
+ }
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+static struct file_operations shf_fops = {
+ .owner = THIS_MODULE,
+ .open = shf_open,
+ .release = shf_release,
+ .unlocked_ioctl = shf_unlocked_ioctl,
+ //.ioctl = shf_ioctl,
+};
+/*----------------------------------------------------------------------------*/
+static struct miscdevice shf_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "shf",
+ .fops = &shf_fops,
+};
+/*----------------------------------------------------------------------------*/
+static void shf_ipi_receive_handler(int id, void* data, uint size)
+{
+ if (id == IPI_SHF) {
+ //shf_print_bytes(data, size);
+ SHF_LOG("IPI_SHF\n");
+ ring_buffer_push(&trigger_buffer, data, size);
+ notify();
+ }
+}
+/*----------------------------------------------------------------------------*/
+static int shf_driver_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ event_init();//init event for wait/notify
+ if((err = misc_register(&shf_device)) != 0) {
+ SHF_ERR("register device failed!\n");
+ goto exit_misc_device_register_failed;
+ }
+ if((err = shf_create_attr(&shf_driver.driver)) != 0) {
+ SHF_ERR("create attribute err=%d\n", err);
+ goto exit_create_attr_failed;
+ }
+ err = md32_ipi_registration(IPI_SHF, shf_ipi_receive_handler, "shf_ipi_receive_handler");
+ if (DONE != err) {
+ goto exit_ipi_receive_register_failed;
+ }
+ shf_init_flag = 0;
+ SHF_LOG("register device succeed.\n");
+ return 0;
+
+ exit_ipi_receive_register_failed:
+ exit_create_attr_failed:
+ misc_deregister(&shf_device);
+
+ exit_misc_device_register_failed:
+ SHF_ERR("%s: err=%d\n", __func__, err);
+ shf_init_flag =-1;
+ return err;
+}
+
+/*----------------------------------------------------------------------------*/
+static int shf_driver_remove(struct platform_device *pdev)
+{
+ int err = 0;
+ SHF_FUN();
+ if((err = shf_delete_attr(&shf_driver.driver)) != 0) {
+ SHF_ERR("shf_delete_attr fail: %d\n", err);
+ }
+ if((err = misc_deregister(&shf_device)) != 0) {
+ SHF_ERR("misc_deregister shf_device fail: %d\n", err);
+ }
+ md32_ipi_registration(IPI_SHF, NULL, NULL);
+ event_destroy();//destroy event for wait/notify
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+/*
+static struct platform_driver shf_driver = {
+ .probe = shf_driver_probe,
+ .remove = shf_driver_remove,
+ .driver = {
+ .name = "shf",
+ .owner = THIS_MODULE,
+ }
+};
+*/
+/*----------------------------------------------------------------------------*/
+#ifdef CONFIG_OF
+static const struct of_device_id shf_of_match[] = {
+ { .compatible = "mediatek,shf", },
+ {},
+};
+#endif
+
+static struct platform_driver shf_driver = {
+ .probe = shf_driver_probe,
+ .remove = shf_driver_remove,
+ .driver =
+ {
+ .name = "shf",
+#ifdef CONFIG_OF
+ .of_match_table = shf_of_match,
+#endif
+ }
+};
+/*----------------------------------------------------------------------------*/
+static int __init shf_driver_init(void)
+{
+ SHF_FUN();
+ if(platform_driver_register(&shf_driver)) {
+ SHF_ERR("failed to register shf driver");
+ return -ENODEV;
+ }
+ wake_lock_init(&shf_suspend_lock, WAKE_LOCK_SUSPEND, "shf_wakelock");
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static void __exit shf_driver_exit(void)
+{
+ SHF_FUN();
+ platform_driver_unregister(&shf_driver);
+}
+/*----------------------------------------------------------------------------*/
+module_init(shf_driver_init);
+module_exit(shf_driver_exit);
+/*----------------------------------------------------------------------------*/
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("sensor hub framework driver");
+MODULE_AUTHOR("mediatek.inc.");
+/*----------------------------------------------------------------------------*/
diff --git a/drivers/misc/mediatek/sensorHub/SCP_shf/shf_kernel.h b/drivers/misc/mediatek/sensorHub/SCP_shf/shf_kernel.h
new file mode 100644
index 000000000..9442c0c0b
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/SCP_shf/shf_kernel.h
@@ -0,0 +1,33 @@
+#ifndef SHF_KERNEL_H
+#define SHF_KERNEL_H
+
+#include <linux/types.h>
+
+//IPI received data cache
+#define SHF_IPI_PROTOCOL_BYTES (48)
+typedef struct ipi_data {
+ uint8_t data[SHF_IPI_PROTOCOL_BYTES];
+ size_t size;
+} ipi_data_t;
+
+typedef struct ipi_buffer {
+ size_t head;
+ size_t tail;
+ size_t size;//data count
+ ipi_data_t* data;
+} ipi_buffer_t;
+
+#define SHF_IOW(num, dtype) _IOW('S', num, dtype)
+#define SHF_IOR(num, dtype) _IOR('S', num, dtype)
+#define SHF_IOWR(num, dtype) _IOWR('S', num, dtype)
+#define SHF_IO(num) _IO('S', num)
+
+#define SHF_IPI_SEND SHF_IOW(1, ipi_data_t)
+#define SHF_IPI_POLL SHF_IOR(2, ipi_data_t)
+#define SHF_GESTURE_ENABLE SHF_IOW(3, int)
+
+#ifdef CONFIG_MTK_SENSOR_HUB_SUPPORT
+extern void tpd_scp_wakeup_enable(bool enable);
+#endif
+
+#endif//SHF_KERNEL_H \ No newline at end of file
diff --git a/drivers/misc/mediatek/sensorHub/inc/SCP_sensorHub.h b/drivers/misc/mediatek/sensorHub/inc/SCP_sensorHub.h
new file mode 100644
index 000000000..0ff3a42ae
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/inc/SCP_sensorHub.h
@@ -0,0 +1,185 @@
+/* SCP sensor hub driver
+ *
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+
+ * (C) Copyright 2011 Bosch Sensortec GmbH
+ * All Rights Reserved
+ */
+
+#ifndef SCP_SENSOR_HUB_H
+#define SCP_SENSOR_HUB_H
+
+#include <linux/ioctl.h>
+#include <cust_acc.h>
+
+#define SCP_SENSOR_HUB_TEMP_BUFSIZE 256
+
+#define SCP_SENSOR_HUB_FIFO_SIZE 32768
+
+#define SCP_SENSOR_HUB_SUCCESS 0
+#define SCP_SENSOR_HUB_FAILURE (-1)
+
+struct scp_acc_hw {
+ int i2c_num; /*!< the i2c bus used by the chip */
+ int direction; /*!< the direction of the chip */
+ int power_id; /*!< the VDD LDO ID of the chip, MT6516_POWER_NONE means the power is always on */
+ int power_vol; /*!< the VDD Power Voltage used by the chip */
+ int firlen; /*!< the length of low pass filter */
+ int reserved;
+ unsigned char i2c_addr[G_CUST_I2C_ADDR_NUM]; /*!< i2c address list,for chips which has different addresses with different HW layout */
+ int power_vio_id; /*!< the VIO LDO ID of the chip, MT6516_POWER_NONE means the power is always on */
+ int power_vio_vol; /*!< the VIO Power Voltage used by the chip */
+ bool is_batch_supported;
+};
+
+typedef enum{
+ SENSOR_HUB_ACTIVATE = 0,
+ SENSOR_HUB_SET_DELAY,
+ SENSOR_HUB_GET_DATA,
+ SENSOR_HUB_BATCH,
+ SENSOR_HUB_SET_CONFIG,
+ SENSOR_HUB_SET_CUST,
+ SENSOR_HUB_NOTIFY,
+}SCP_ACTION;
+
+typedef enum{
+ SCP_INIT_DONE = 0,
+ SCP_FIFO_FULL,
+ SCP_NOTIFY,
+}SCP_NOTIFY_EVENT;
+
+struct SCP_sensorData{
+ uint8_t dataLength;
+ uint8_t sensorType;
+ uint8_t reserve[2];
+ uint32_t timeStampH;
+ uint32_t timeStampL;
+ int16_t data[8];
+};
+
+struct sensorFIFO {
+// volatile struct SCP_sensorData * volatile rp;
+// volatile struct SCP_sensorData * volatile wp;
+ int rp; //use int for store DRAM FIFO LSB 32bit read pointer
+ int wp;
+ uint32_t FIFOSize;
+ struct SCP_sensorData data[0];
+};
+
+typedef struct{
+ uint32_t sensorType;
+ SCP_ACTION action;
+ uint32_t data[10];
+}SCP_SENSOR_HUB_REQ;
+
+typedef struct{
+ uint32_t sensorType;
+ SCP_ACTION action;
+ uint32_t errCode;
+ //uint32_t reserved[9];
+}SCP_SENSOR_HUB_RSP;
+
+typedef struct{
+ uint32_t sensorType;
+ SCP_ACTION action;
+ uint32_t enable; //0 : disable ; 1 : enable
+ //uint32_t reserved[9];
+}SCP_SENSOR_HUB_ACTIVATE_REQ;
+
+typedef SCP_SENSOR_HUB_RSP SCP_SENSOR_HUB_ACTIVATE_RSP;
+
+typedef struct{
+ uint32_t sensorType;
+ SCP_ACTION action;
+ uint32_t delay; //ms
+ //uint32_t reserved[9];
+}SCP_SENSOR_HUB_SET_DELAY_REQ;
+
+typedef SCP_SENSOR_HUB_RSP SCP_SENSOR_HUB_SET_DELAY_RSP;
+
+typedef struct{
+ uint32_t sensorType;
+ SCP_ACTION action;
+ //uint32_t reserved[10];
+}SCP_SENSOR_HUB_GET_DATA_REQ;
+
+typedef struct{
+ uint32_t sensorType;
+ SCP_ACTION action;
+ uint32_t errCode;
+ union{
+ int8_t int8_Data[0];
+ int16_t int16_Data[0];
+ int32_t int32_Data[0];
+ };
+}SCP_SENSOR_HUB_GET_DATA_RSP;
+
+typedef struct{
+ uint32_t sensorType;
+ SCP_ACTION action;
+ uint32_t flag; //see SENSORS_BATCH_WAKE_UPON_FIFO_FULL definition in hardware/libhardware/include/hardware/sensors.h
+ uint32_t period_ms; //batch reporting time in ms
+ uint32_t timeout_ms; //sampling time in ms
+ //uint32_t reserved[7];
+}SCP_SENSOR_HUB_BATCH_REQ;
+
+typedef SCP_SENSOR_HUB_RSP SCP_SENSOR_HUB_BATCH_RSP;
+
+typedef struct{
+ uint32_t sensorType;
+ SCP_ACTION action;
+ //struct sensorFIFO *bufferBase;
+ int bufferBase; //use int to store buffer DRAM base LSB 32 bits
+ uint32_t bufferSize;
+ //uint32_t reserved[8];
+}SCP_SENSOR_HUB_SET_CONFIG_REQ;
+
+typedef SCP_SENSOR_HUB_RSP SCP_SENSOR_HUB_SET_CONFIG_RSP;
+
+typedef struct{
+ uint32_t sensorType;
+ SCP_ACTION action;
+ uint32_t custData[10];
+}SCP_SENSOR_HUB_SET_CUST_REQ;
+
+typedef struct{
+ uint32_t sensorType;
+ SCP_ACTION action;
+ uint32_t errCode;
+ uint32_t custData[0];
+}SCP_SENSOR_HUB_SET_CUST_RSP;
+
+typedef struct{
+ uint32_t sensorType;
+ SCP_ACTION action;
+ SCP_NOTIFY_EVENT event;
+ uint32_t data[0];
+}SCP_SENSOR_HUB_NOTIFY_RSP;
+
+typedef union{
+ SCP_SENSOR_HUB_REQ req;
+ SCP_SENSOR_HUB_RSP rsp;
+ SCP_SENSOR_HUB_ACTIVATE_REQ activate_req;
+ SCP_SENSOR_HUB_ACTIVATE_RSP activate_rsp;
+ SCP_SENSOR_HUB_SET_DELAY_REQ set_delay_req;
+ SCP_SENSOR_HUB_SET_DELAY_RSP set_delay_rsp;
+ SCP_SENSOR_HUB_GET_DATA_REQ get_data_req;
+ SCP_SENSOR_HUB_GET_DATA_RSP get_data_rsp;
+ SCP_SENSOR_HUB_BATCH_REQ batch_req;
+ SCP_SENSOR_HUB_BATCH_RSP batch_rsp;
+ SCP_SENSOR_HUB_SET_CONFIG_REQ set_config_req;
+ SCP_SENSOR_HUB_SET_CONFIG_RSP set_config_rsp;
+ SCP_SENSOR_HUB_SET_CUST_REQ set_cust_req;
+ SCP_SENSOR_HUB_SET_CUST_RSP set_cust_rsp;
+ SCP_SENSOR_HUB_NOTIFY_RSP notify_rsp;
+}SCP_SENSOR_HUB_DATA, *SCP_SENSOR_HUB_DATA_P;
+
+typedef int (*SCP_sensorHub_handler)(void* data, uint len);
+
+int SCP_sensorHub_req_send(SCP_SENSOR_HUB_DATA_P data, uint *len, unsigned int wait);
+int SCP_sensorHub_rsp_registration(int sensor, SCP_sensorHub_handler handler);
+
+#endif
+
diff --git a/drivers/misc/mediatek/sensorHub/inc/cust_sensorHub.h b/drivers/misc/mediatek/sensorHub/inc/cust_sensorHub.h
new file mode 100644
index 000000000..96656d23f
--- /dev/null
+++ b/drivers/misc/mediatek/sensorHub/inc/cust_sensorHub.h
@@ -0,0 +1,11 @@
+#ifndef __CUST_ACC_H__
+#define __CUST_ACC_H__
+
+#define G_CUST_I2C_ADDR_NUM 2
+
+struct sensorHub_hw {
+ int is_batch_enabled;
+};
+
+extern struct sensorHub_hw* get_cust_sensorHub_hw(void);
+#endif