diff options
| author | Meizu OpenSource <patchwork@meizu.com> | 2016-08-15 10:19:42 +0800 |
|---|---|---|
| committer | Meizu OpenSource <patchwork@meizu.com> | 2016-08-15 10:19:42 +0800 |
| commit | d2e1446d81725c351dc73a03b397ce043fb18452 (patch) | |
| tree | 4dbc616b7f92aea39cd697a9084205ddb805e344 /drivers/misc/mediatek/sensorHub | |
first commit
Diffstat (limited to 'drivers/misc/mediatek/sensorHub')
| -rw-r--r-- | drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuBus.c | 827 | ||||
| -rw-r--r-- | drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor.c | 2027 | ||||
| -rw-r--r-- | drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor.h | 457 | ||||
| -rw-r--r-- | drivers/misc/mediatek/sensorHub/CwMcuSensor/CwMcuSensor_factory.c | 474 | ||||
| -rwxr-xr-x | drivers/misc/mediatek/sensorHub/CwMcuSensor/Makefile | 9 | ||||
| -rwxr-xr-x | drivers/misc/mediatek/sensorHub/Makefile | 14 | ||||
| -rwxr-xr-x | drivers/misc/mediatek/sensorHub/SCP_sensorHub/Makefile | 4 | ||||
| -rw-r--r-- | drivers/misc/mediatek/sensorHub/SCP_sensorHub/SCP_sensorHub.c | 2569 | ||||
| -rwxr-xr-x | drivers/misc/mediatek/sensorHub/SCP_shf/Makefile | 3 | ||||
| -rw-r--r-- | drivers/misc/mediatek/sensorHub/SCP_shf/shf_kernel.c | 405 | ||||
| -rw-r--r-- | drivers/misc/mediatek/sensorHub/SCP_shf/shf_kernel.h | 33 | ||||
| -rw-r--r-- | drivers/misc/mediatek/sensorHub/inc/SCP_sensorHub.h | 185 | ||||
| -rw-r--r-- | drivers/misc/mediatek/sensorHub/inc/cust_sensorHub.h | 11 |
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 |
