diff options
Diffstat (limited to 'drivers/sensorhub/stm/ssp_comm.c')
-rwxr-xr-x | drivers/sensorhub/stm/ssp_comm.c | 898 |
1 files changed, 898 insertions, 0 deletions
diff --git a/drivers/sensorhub/stm/ssp_comm.c b/drivers/sensorhub/stm/ssp_comm.c new file mode 100755 index 00000000000..e01548652cb --- /dev/null +++ b/drivers/sensorhub/stm/ssp_comm.c @@ -0,0 +1,898 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <mach/gpio.h> +#include "ssp.h" + +#define LIMIT_DELAY_CNT 200 +#define RECEIVEBUFFERSIZE 12 +#define DEBUG_SHOW_DATA 0 + +int waiting_wakeup_mcu(struct ssp_data *data) +{ + int iDelaycnt = 0; + + while (!data->check_mcu_busy() && (iDelaycnt++ < LIMIT_DELAY_CNT) + && (data->bSspShutdown == false)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Irq Timeout!!\n", __func__); + data->uBusyCnt++; + } else { + data->uBusyCnt = 0; + } + + iDelaycnt = 0; + data->wakeup_mcu(); + while (!data->check_mcu_ready() && (iDelaycnt++ < LIMIT_DELAY_CNT) + && (data->bSspShutdown == false)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Wakeup Timeout!!\n", __func__); + data->uTimeOutCnt++; + } else { + data->uTimeOutCnt = 0; + } + + if (data->bSspShutdown == true) + return ERROR; + + return SUCCESS; +} + +int waiting_init_mcu(struct ssp_data *data) +{ + int iDelaycnt = 0; + + while (!data->check_mcu_busy() && (iDelaycnt++ < LIMIT_DELAY_CNT)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Irq Timeout!!\n", __func__); + data->uBusyCnt++; + } else { + data->uBusyCnt = 0; + } + + iDelaycnt = 0; + data->wakeup_mcu(); + while (!data->check_mcu_ready() && (iDelaycnt++ < LIMIT_DELAY_CNT)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Wakeup Timeout!!\n", __func__); + data->uTimeOutCnt++; + } else { + data->uTimeOutCnt = 0; + } + + return SUCCESS; +} + +int ssp_spi_checkrecvstart(char *rxBuf, int len) +{ + unsigned int i; + for (i = 0; i < len ; i++) { + if (rxBuf[i] == 0x00) + continue; + break; + } + + if (i == len) + return -EFAULT; + return i; +} + +#if DEBUG_SHOW_DATA +void show_ssp_data(char *buff, int len, int type) +{ + unsigned int i; + char showdata[len*2+2]; + memset(showdata, 0, len*2+2); + for (i = 0; i < len; i++) + sprintf(showdata, "%s%02x", showdata, buff[i]); + + if (type == 1) + pr_info("[SSP]hb received len=%d %s", len, showdata); + else if (type == 2) + pr_info("[SSP]hb received while send %s", showdata); + else + pr_info("[SSP]hb sending len=%d %s", len, showdata); +} + +#endif + + +int ssp_read_data(struct ssp_data *data, char *pTxData, u16 uTxLength, + char *pRxData, u16 uRxLength, int iRetries) +{ + int iRet = 0, iDiffTime = 0, iTimeTemp; + int txlen = uTxLength; + struct timeval cur_time; + + do_gettimeofday(&cur_time); + + iTimeTemp = (int)cur_time.tv_sec; + +#if DEBUG_SHOW_DATA + show_ssp_data(pTxData, txlen, 3); +#endif + + mutex_lock(&data->comm_mutex); + + do { + char synctxbuf[RECEIVEBUFFERSIZE]; + char syncrxbuf[RECEIVEBUFFERSIZE]; + char *bulktxbuf; + char *bulkrxbuf; + + int startpos; + + if (pTxData[0] != MSG2SSP_SRM) { + /* 0xCA : MASS DATA will be received */ + memset(synctxbuf, 0, RECEIVEBUFFERSIZE); + + /* prevent re-sending CMD when retry */ + if (txlen > 0) + memcpy(synctxbuf, pTxData, uTxLength); + + /* uTxLength should small than RECEIVEBUFFERSIZE */ + iRet = ssp_spi_sync(data->spi, synctxbuf, + RECEIVEBUFFERSIZE, syncrxbuf); + +#if DEBUG_SHOW_DATA + show_ssp_data(syncrxbuf, RECEIVEBUFFERSIZE, 2); +#endif + + startpos = ssp_spi_checkrecvstart(syncrxbuf + txlen, + RECEIVEBUFFERSIZE - txlen) + txlen; +#if DEBUG_SHOW_DATA + pr_info("[SSP]hb pTxData[0]=0x%x startpos " + "%d uTxLength %d,uRxLen %d", + pTxData[0], startpos, uTxLength, uRxLength); +#endif + if (startpos >= txlen && + (RECEIVEBUFFERSIZE - startpos - uRxLength >= 0)) + memcpy(pRxData, syncrxbuf + startpos, + uRxLength); + else /* timeout if receive within RECEIVEBUFFERSIZE */ + iRet = -ETIMEDOUT; + + } else { + bulktxbuf = (char *)kzalloc( + uRxLength + RECEIVEBUFFERSIZE, GFP_KERNEL); + bulkrxbuf = (char *)kzalloc( + uRxLength + RECEIVEBUFFERSIZE, GFP_KERNEL); + + /* prevent re-sending command when retry */ + if (txlen > 0) + memcpy(bulktxbuf, pTxData, txlen); + iRet = ssp_spi_sync(data->spi, bulktxbuf, + uRxLength+RECEIVEBUFFERSIZE, bulkrxbuf); + +#if DEBUG_SHOW_DATA + show_ssp_data(bulkrxbuf, + uRxLength + RECEIVEBUFFERSIZE, 2); +#endif + + startpos = ssp_spi_checkrecvstart(bulkrxbuf + txlen, + uRxLength + RECEIVEBUFFERSIZE - txlen) + + txlen; +#if DEBUG_SHOW_DATA + pr_info("[SSP]hb WOW pTxData[0]=0x%x startpos %d " + "uTxLength %d,uRxLen %d TxLen %d", pTxData[0], + startpos, uTxLength, uRxLength, txlen); +#endif + + if (startpos >= txlen && + (uRxLength + RECEIVEBUFFERSIZE - + startpos - uRxLength >= 0)) + memcpy(pRxData, bulkrxbuf + startpos, + uRxLength); + else /* timeout if receive within RECEIVEBUFFERSIZE */ + iRet = -1; + + kfree(bulktxbuf); + kfree(bulkrxbuf); + } + + if (iRet < 0) { + do_gettimeofday(&cur_time); + iDiffTime = (int)cur_time.tv_sec - iTimeTemp; + iTimeTemp = (int)cur_time.tv_sec; + if (iDiffTime >= 4) { + pr_err("[SSP]: %s - spi time out %d!\n", + __func__, iDiffTime); + break; + } + pr_err("[SSP]: %s - spi error %d! retry...\n", + __func__, iRet); + mdelay(1); + } else { +#if DEBUG_SHOW_DATA + show_ssp_data(pRxData, uRxLength, 1); +#endif + mutex_unlock(&data->comm_mutex); + + return SUCCESS; + } + txlen = 0; + } while (iRetries--); + mutex_unlock(&data->comm_mutex); + + return ERROR; +} + +int ssp_sleep_mode(struct ssp_data *data) +{ + char chRxBuf = 0; + char chTxBuf = MSG2SSP_AP_STATUS_SLEEP; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + /* send to AP_STATUS_SLEEP */ + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD fail %d\n", + __func__, iRet); + return ERROR; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD "\ + "retry...\n", __func__); + iRet = ssp_read_data(data, &chTxBuf, 1, + &chRxBuf, 1, DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD\n", __func__); + + return SUCCESS; +} + +int ssp_resume_mode(struct ssp_data *data) +{ + char chRxBuf = 0; + char chTxBuf = MSG2SSP_AP_STATUS_WAKEUP; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + /* send to MSG2SSP_AP_STATUS_WAKEUP */ + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD fail %d\n", + __func__, iRet); + return ERROR; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD "\ + "retry...\n", __func__); + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD\n", __func__); + + return SUCCESS; +} + +int ssp_ap_suspend(struct ssp_data *data) +{ + char chRxBuf = 0; + char chTxBuf = MSG2SSP_AP_STATUS_SUSPEND; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + /* send to AP_STATUS_SLEEP */ + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD fail %d\n", + __func__, iRet); + return ERROR; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD "\ + "retry...\n", __func__); + iRet = ssp_read_data(data, &chTxBuf, 1, + &chRxBuf, 1, DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD\n", __func__); + + return SUCCESS; +} + +int ssp_ap_resume(struct ssp_data *data) +{ + char chRxBuf = 0; + char chTxBuf = MSG2SSP_AP_STATUS_RESUME; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + /* send to MSG2SSP_AP_STATUS_WAKEUP */ + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD fail %d\n", + __func__, iRet); + return ERROR; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD "\ + "retry...\n", __func__); + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD\n", __func__); + + return SUCCESS; +} + +int ssp_send_cmd(struct ssp_data *data, char command) +{ + char chRxBuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + iRet = ssp_read_data(data, &command, 1, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - command 0x%x failed %d\n", + __func__, command, iRet); + return ERROR; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - command 0x%x retry...\n", + __func__, command); + iRet = ssp_read_data(data, &command, 1, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - command 0x%x\n", __func__, command); + + return SUCCESS; +} + +int send_instruction(struct ssp_data *data, u8 uInst, + u8 uSensorType, u8 *uSendBuf, u8 uLength) +{ + char chTxbuf[uLength + 4]; + char chRxbuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (data->fw_dl_state == FW_DL_STATE_DOWNLOADING) { + pr_err("[SSP] %s - Skip Inst! DL state = %d\n", + __func__, data->fw_dl_state); + return SUCCESS; + } else if ((!(data->uSensorState & (1 << uSensorType))) + && (uInst <= CHANGE_DELAY)) { + pr_err("[SSP]: %s - Bypass Inst Skip! - %u\n", + __func__, uSensorType); + return FAIL; + } + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + chTxbuf[0] = MSG2SSP_SSM; + chTxbuf[1] = (char)(uLength + 4); + + switch (uInst) { + case REMOVE_SENSOR: + chTxbuf[2] = MSG2SSP_INST_BYPASS_SENSOR_REMOVE; + break; + case ADD_SENSOR: + chTxbuf[2] = MSG2SSP_INST_BYPASS_SENSOR_ADD; + break; + case CHANGE_DELAY: + chTxbuf[2] = MSG2SSP_INST_CHANGE_DELAY; + break; + case GO_SLEEP: + chTxbuf[2] = MSG2SSP_AP_STATUS_SLEEP; + break; + case FACTORY_MODE: + chTxbuf[2] = MSG2SSP_INST_SENSOR_SELFTEST; + break; + case REMOVE_LIBRARY: + chTxbuf[2] = MSG2SSP_INST_LIBRARY_REMOVE; + break; + case ADD_LIBRARY: + chTxbuf[2] = MSG2SSP_INST_LIBRARY_ADD; + break; + case MSG2SSP_INST_LIB_NOTI: + if (uSendBuf[0] == MSG2SSP_AP_STATUS_WAKEUP) { + iRet = ssp_resume_mode(data); + enable_debug_timer(data); + } else if (uSendBuf[0] == MSG2SSP_AP_STATUS_SLEEP) { + disable_debug_timer(data); + iRet = ssp_sleep_mode(data); + } else { + pr_err("[SSP]: %s -Wrong POWER_NOTI 0x%x\n", __func__, + uSendBuf[0]); + return ERROR; + } + return iRet; + default: + chTxbuf[2] = uInst; + break; + } + + chTxbuf[3] = uSensorType; + memcpy(&chTxbuf[4], uSendBuf, uLength); + + iRet = ssp_read_data(data, &(chTxbuf[0]), uLength + 4, &chRxbuf, 1, + DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Instruction CMD Fail %d\n", __func__, iRet); + return ERROR; + } else if (chRxbuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - Instruction CMD retry...\n", + __func__); + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + iRet = ssp_read_data(data, &(chTxbuf[0]), + uLength + 4, &chRxbuf, 1, DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxbuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - Inst = 0x%x, Sensor Type = 0x%x, data = %u\n", + __func__, chTxbuf[2], chTxbuf[3], chTxbuf[4]); + return SUCCESS; +} + +int get_chipid(struct ssp_data *data) +{ + int iRet; + char sendbuf[2]; + char recvbuf; + sendbuf[0] = MSG2SSP_AP_WHOAMI; + sendbuf[1] = '\0'; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + /* read chip id */ +#if 1 + iRet = ssp_read_data(data, sendbuf, 2, &recvbuf, 1, DEFAULT_RETRIES); + + if (iRet == SUCCESS) + return recvbuf; + else + pr_err("[SSP]: %s - ssp_read_data fail %d\n", __func__, iRet); + + return ERROR; +#else + mutex_lock(&data->comm_mutex); + + iRet = ssp_spi_sync(data->spi, sendbuf, 1, NULL); + pr_err("[SSP]hb get_chipid ssp_spi_sync return for send %d", iRet); + + iRet = ssp_spi_sync(data->spi, NULL, 1, recvbuf); + pr_err("[SSP]hb get_chipid ssp_spi_sync return for recv %d", iRet); + iRet = recvbuf[0]; + pr_err("[SSP]hb get_chipid ssp_spi_sync recved %d", iRet); + + mutex_unlock(&data->comm_mutex); +#endif +} + +int set_sensor_position(struct ssp_data *data) +{ + char chTxBuf[5] = { 0, }; + char chRxData = 0; + int iRet = 0; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + chTxBuf[0] = MSG2SSP_AP_SENSOR_FORMATION; + + /* Please refer to ssp_get_positions on the file + * board-universal_5410-sensor.c */ + chTxBuf[1] = data->accel_position; + chTxBuf[2] = data->accel_position; + chTxBuf[3] = data->mag_position; + chTxBuf[4] = 0; + + pr_info("[SSP] Sensor Posision A : %u, G : %u, M: %u, P: %u\n", + chTxBuf[1], chTxBuf[2], chTxBuf[3], chTxBuf[4]); + + iRet = ssp_read_data(data, chTxBuf, 5, &chRxData, 1, DEFAULT_RETRIES); + if ((chRxData != MSG_ACK) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - spi fail %d\n", __func__, iRet); + iRet = ERROR; + } + + return iRet; +} + +void set_proximity_threshold(struct ssp_data *data, + unsigned char uData1, unsigned char uData2) +{ + char chTxBuf[3] = { 0, }; + char chRxBuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0 || + data->fw_dl_state == FW_DL_STATE_DOWNLOADING) { + pr_info("[SSP] : %s, skip DL state = %d\n", __func__, + data->fw_dl_state); + return; + } else if (!(data->uSensorState & (1 << PROXIMITY_SENSOR))) { + pr_info("[SSP] : %s, skip uSensorState = 0x%x\n", __func__, + data->uSensorState); + return; + } + + chTxBuf[0] = MSG2SSP_AP_SENSOR_PROXTHRESHOLD; + chTxBuf[1] = uData1; + chTxBuf[2] = uData2; + + iRet = ssp_read_data(data, chTxBuf, 3, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - SENSOR_PROXTHRESHOLD CMD fail %d\n", + __func__, iRet); + return; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_PROXTHRESHOLD "\ + "CMD retry...\n", __func__); + iRet = ssp_read_data(data, chTxBuf, 3, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return; + } + } + + data->uInstFailCnt = 0; + pr_info("[SSP]: Proximity Threshold - %u, %u\n", uData1, uData2); +} + +void set_proximity_barcode_enable(struct ssp_data *data, bool bEnable) +{ + char chTxBuf[2] = { 0, }; + char chRxBuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return; + + chTxBuf[0] = MSG2SSP_AP_SENSOR_BARCODE_EMUL; + chTxBuf[1] = bEnable; + + data->bBarcodeEnabled = bEnable; + + iRet = ssp_read_data(data, chTxBuf, 2, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - SENSOR_BARCODE_EMUL CMD fail %d\n", + __func__, iRet); + return; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_BARCODE_EMUL "\ + "CMD retry...\n", __func__); + iRet = ssp_read_data(data, chTxBuf, 2, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return; + } + } + + data->uInstFailCnt = 0; + pr_info("[SSP] Proximity Barcode En : %u\n", bEnable); +} + +void set_gesture_current(struct ssp_data *data, unsigned char uData1) +{ + char chTxBuf[2] = { 0, }; + char chRxBuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0 || + data->fw_dl_state == FW_DL_STATE_DOWNLOADING) { + pr_info("[SSP] : %s, skip DL state = %d\n", __func__, + data->fw_dl_state); + return; + } + + chTxBuf[0] = MSG2SSP_AP_SENSOR_GESTURE_CURRENT; + chTxBuf[1] = uData1; + + iRet = ssp_read_data(data, chTxBuf, 2, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - SENSOR_GESTURE_CURRENT CMD fail %d\n", + __func__, iRet); + return; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_GESTURE_CURRENT "\ + "CMD retry...\n", __func__); + iRet = ssp_read_data(data, chTxBuf, 2, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return; + } + } + + data->uInstFailCnt = 0; + pr_info("[SSP]: Gesture Current Setting - %u\n", uData1); +} + +unsigned int get_sensor_scanning_info(struct ssp_data *data) +{ + char chTxBuf = MSG2SSP_AP_SENSOR_SCANNING; + char chRxData[2] = {0,}; + int iRet = 0; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + iRet = ssp_read_data(data, &chTxBuf, 1, chRxData, 2, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - spi failed %d\n", __func__, iRet); + return 0; + } + return ((unsigned int)chRxData[0] << 8) | chRxData[1]; +} + +unsigned int get_firmware_rev(struct ssp_data *data) +{ + char chTxData = MSG2SSP_AP_FIRMWARE_REV; + char chRxBuf[3] = { 0, }; + unsigned int uRev = 99999; + int iRet; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + iRet = ssp_read_data(data, &chTxData, 1, chRxBuf, 3, DEFAULT_RETRIES); + if (iRet != SUCCESS) + pr_err("[SSP]: %s - spi fail %d\n", __func__, iRet); + else + uRev = ((unsigned int)chRxBuf[0] << 16) + | ((unsigned int)chRxBuf[1] << 8) | chRxBuf[2]; + return uRev; +} + +int get_fuserom_data(struct ssp_data *data) +{ + char chTxBuf[2] = { 0, }; + char chRxBuf[2] = { 0, }; + int iRet = 0; + unsigned int uLength = 0; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + chTxBuf[0] = MSG2SSP_AP_STT; + chTxBuf[1] = MSG2SSP_AP_FUSEROM; + + /* chRxBuf is Two Byte because msg is large */ + iRet = ssp_read_data(data, chTxBuf, 2, chRxBuf, 2, DEFAULT_RETRIES); + uLength = ((unsigned int)chRxBuf[0] << 8) + (unsigned int)chRxBuf[1]; + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STT - spi fail %d\n", + __func__, iRet); + goto err_read_fuserom; + } else if (uLength == 0) { + pr_err("[SSP]: %s - No ready data. length = %u\n", + __func__, uLength); + goto err_read_fuserom; + } else { + if (data->iLibraryLength != 0) + kfree(data->pchLibraryBuf); + + data->iLibraryLength = (int)uLength; + data->pchLibraryBuf = + kzalloc((data->iLibraryLength * sizeof(char)), GFP_KERNEL); + + chTxBuf[0] = MSG2SSP_SRM; + iRet = ssp_read_data(data, chTxBuf, 1, data->pchLibraryBuf, + (u16)data->iLibraryLength, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Fail to receive SSP data %d\n", + __func__, iRet); + kfree(data->pchLibraryBuf); + data->iLibraryLength = 0; + goto err_read_fuserom; + } + } + + data->uFuseRomData[0] = data->pchLibraryBuf[0]; + data->uFuseRomData[1] = data->pchLibraryBuf[1]; + data->uFuseRomData[2] = data->pchLibraryBuf[2]; + + pr_info("[SSP] FUSE ROM Data %d , %d, %d\n", data->uFuseRomData[0], + data->uFuseRomData[1], data->uFuseRomData[2]); + + data->iLibraryLength = 0; + kfree(data->pchLibraryBuf); + return SUCCESS; + +err_read_fuserom: + data->uFuseRomData[0] = 0; + data->uFuseRomData[1] = 0; + data->uFuseRomData[2] = 0; + + return FAIL; +} + +static int ssp_receive_msg(struct ssp_data *data, u8 uLength) +{ + char chTxBuf = 0; + char *pchRcvDataFrame = NULL; /* SSP-AP Massage data buffer */ + int iRet = 0; + + if (uLength > 0) { + pchRcvDataFrame = kzalloc((uLength * sizeof(char)), GFP_KERNEL); + if (pchRcvDataFrame == NULL) { + pr_err("[SSP]: %s - fail to allocate memory for data\n", + __func__); + iRet = -ENOMEM; + return iRet; + } + chTxBuf = MSG2SSP_SRM; + iRet = ssp_read_data(data, &chTxBuf, 1, pchRcvDataFrame, + (u16)uLength, 0); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Fail to receive data %d\n", + __func__, iRet); + kfree(pchRcvDataFrame); + return ERROR; + } + } else { + pr_err("[SSP]: %s - No ready data. length = %d\n", + __func__, uLength); + return FAIL; + } + + parse_dataframe(data, pchRcvDataFrame, uLength); + + kfree(pchRcvDataFrame); + return uLength; +} + +int select_irq_msg(struct ssp_data *data) +{ + u8 chLength = 0; + char chTxBuf = 0; + char chRxBuf[2] = { 0, }; + int iRet = 0; + + chTxBuf = MSG2SSP_SSD; + iRet = ssp_read_data(data, &chTxBuf, 1, chRxBuf, 2, 4); + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_SSD error %d\n", __func__, iRet); + return ERROR; + } else { + if (chRxBuf[0] == MSG2SSP_RTS) { + chLength = (u8)chRxBuf[1]; + ssp_receive_msg(data, chLength); + data->uSsdFailCnt = 0; + } +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + else if (chRxBuf[0] == MSG2SSP_STT) { + pr_info("%s: MSG2SSP_STT irq", __func__); + iRet = ssp_sensorhub_handle_large_data(data, + (u8)chRxBuf[1]); + if (iRet < 0) { + pr_err("%s: ssp sensorhub large data err(%d)", + __func__, iRet); + } + data->uSsdFailCnt = 0; + } +#endif + else if (chRxBuf[0] == MSG2SSP_NO_DATA) { + pr_info("%s: MSG2SSP_NODATA irq [0]: 0x%x, [1]: 0x%x\n", + __func__, chRxBuf[0], chRxBuf[1]); + } else { + pr_err("[SSP]: %s - MSG2SSP_SSD Data fail "\ + "[0]: 0x%x, [1]: 0x%x\n", __func__, + chRxBuf[0], chRxBuf[1]); + if ((chRxBuf[0] == 0) && (chRxBuf[1] == 0)) + data->uSsdFailCnt++; + } + } + return SUCCESS; +} |