/* * 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 "ssp.h" #define LIMIT_DELAY_CNT 200 #define RECEIVEBUFFERSIZE 12 #define DEBUG_SHOW_DATA 0 void clean_msg(struct ssp_msg *msg) { if (msg->free_buffer) kfree(msg->buffer); kfree(msg); } static int do_transfer(struct ssp_data *data, struct ssp_msg *msg, struct completion *done, int timeout) { return bbd_do_transfer(data, msg, done, timeout); } int ssp_spi_async(struct ssp_data *data, struct ssp_msg *msg) { int status = 0; u64 diff = get_current_timestamp() - data->resumeTimestamp; int timeout = diff < 5000000000ULL ? 400 : 1000; // unit: ms if (msg->length) return ssp_spi_sync(data, msg, timeout); status = do_transfer(data, msg, NULL, 0); return status; } int ssp_spi_sync(struct ssp_data *data, struct ssp_msg *msg, int timeout) { DECLARE_COMPLETION_ONSTACK(done); int status = 0; if (msg->length == 0) { pr_err("[SSP]: %s length must not be 0\n", __func__); clean_msg(msg); return status; } status = do_transfer(data, msg, &done, timeout); return status; } int select_irq_msg(struct ssp_data *data) { struct ssp_msg *msg, *n; bool found = false; u16 chLength = 0, msg_options = 0; u8 msg_type = 0; int iRet = 0; char *buffer; char chTempBuf[4] = { -1 }; data->bHandlingIrq = true; iRet = spi_read(data->spi, chTempBuf, sizeof(chTempBuf)); if (iRet < 0) { pr_err("[SSP] %s spi_read fail, ret = %d\n", __func__, iRet); data->bHandlingIrq = false; return iRet; } memcpy(&msg_options, &chTempBuf[0], 2); msg_type = msg_options & SSP_SPI_MASK; memcpy(&chLength, &chTempBuf[2], 2); switch (msg_type) { case AP2HUB_READ: case AP2HUB_WRITE: mutex_lock(&data->pending_mutex); if (!list_empty(&data->pending_list)) { list_for_each_entry_safe(msg, n, &data->pending_list, list) { if (msg->options == msg_options) { list_del(&msg->list); found = true; break; } } if (!found) { pr_err("[SSP]: %s %d - Not match error\n", __func__, msg_options); goto exit; } if (msg->dead && !msg->free_buffer) { msg->buffer = kzalloc(msg->length, GFP_KERNEL); msg->free_buffer = 1; } /* For dead msg, make a temporary buffer to read. */ if (msg_type == AP2HUB_READ) { iRet = spi_read(data->spi, msg->buffer, msg->length); } if (msg_type == AP2HUB_WRITE) { iRet = spi_write(data->spi, msg->buffer, msg->length); if (msg_options & AP2HUB_RETURN) { msg->options = AP2HUB_READ | AP2HUB_RETURN; msg->length = 1; list_add_tail(&msg->list, &data->pending_list); goto exit; } } if (msg->done != NULL && !completion_done(msg->done)) complete(msg->done); if (msg->dead_hook != NULL) *(msg->dead_hook) = true; clean_msg(msg); } else pr_err("[SSP]List empty error(%d)\n", msg_type); exit: mutex_unlock(&data->pending_mutex); break; case HUB2AP_WRITE: buffer = kzalloc(chLength, GFP_KERNEL); iRet = spi_read(data->spi, buffer, chLength); if (iRet < 0) pr_err("[SSP] %s spi_read fail\n", __func__); else parse_dataframe(data, buffer, chLength); kfree(buffer); break; default: pr_err("[SSP]No type error(%d)\n", msg_type); break; } if (iRet < 0) { pr_err("[SSP]: %s - MSG2SSP_SSD error %d\n", __func__, iRet); data->bHandlingIrq = false; return ERROR; } data->bHandlingIrq = false; return SUCCESS; } void clean_pending_list(struct ssp_data *data) { struct ssp_msg *msg, *n; mutex_lock(&data->pending_mutex); list_for_each_entry_safe(msg, n, &data->pending_list, list) { list_del(&msg->list); if (msg->done != NULL && !completion_done(msg->done)) complete(msg->done); if (msg->dead_hook != NULL) *(msg->dead_hook) = true; clean_msg(msg); } mutex_unlock(&data->pending_mutex); } int ssp_send_cmd(struct ssp_data *data, char command, int arg) { int iRet = 0; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = command; msg->length = 0; msg->options = AP2HUB_WRITE; msg->data = arg; msg->free_buffer = 0; iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP]: %s - command 0x%x failed %d\n", __func__, command, iRet); return ERROR; } ssp_dbg("[SSP]: %s - command 0x%x %d\n", __func__, command, arg); return SUCCESS; } int send_instruction(struct ssp_data *data, u8 uInst, u8 uSensorType, u8 *uSendBuf, u16 uLength) { char command; int iRet = 0; struct ssp_msg *msg; //u64 current_Ts = 0; #ifdef CONFIG_SENSORS_SSP_HIFI_BATCHING u64 timestamp; #endif if ((!(data->uSensorState & (1ULL << uSensorType))) && (uInst <= CHANGE_DELAY)) { pr_err("[SSP]: %s - Bypass Inst Skip! - %u\n", __func__, uSensorType); return FAIL; } if (uSensorType >= SENSOR_MAX && (uInst == ADD_SENSOR || uInst == CHANGE_DELAY)){ pr_err("[SSP]: %s - Invalid SensorType! - %u\n", __func__, uSensorType); return FAIL; } switch (uInst) { case REMOVE_SENSOR: command = MSG2SSP_INST_BYPASS_SENSOR_REMOVE; break; case ADD_SENSOR: command = MSG2SSP_INST_BYPASS_SENSOR_ADD; #ifdef CONFIG_SENSORS_SSP_HIFI_BATCHING timestamp = get_current_timestamp(); data->lastTimestamp[uSensorType] = data->LastSensorTimeforReset[uSensorType] = timestamp; data->ts_avg_buffer_idx[uSensorType] = 0; data->ts_avg_buffer_cnt[uSensorType] = 0; data->ts_avg_buffer_sum[uSensorType] = 0; data->ts_prev_index[uSensorType] = 0; data->ts_avg_skip_cnt[uSensorType] = SKIP_CNT_MOVING_AVG_ADD; data->ts_last_enable_cmd_time = timestamp; memset(data->ts_avg_buffer[uSensorType], 0, sizeof(u64)*SIZE_MOVING_AVG_BUFFER); #endif data->first_sensor_data[uSensorType] = true; break; case CHANGE_DELAY: command = MSG2SSP_INST_CHANGE_DELAY; #ifdef CONFIG_SENSORS_SSP_HIFI_BATCHING timestamp = get_current_timestamp(); data->LastSensorTimeforReset[uSensorType] = timestamp; data->ts_avg_buffer_idx[uSensorType] = 0; data->ts_avg_buffer_cnt[uSensorType] = 0; data->ts_avg_buffer_sum[uSensorType] = 0; data->ts_prev_index[uSensorType] = 0; data->ts_avg_skip_cnt[uSensorType] = SKIP_CNT_MOVING_AVG_CHANGE; memset(data->ts_avg_buffer[uSensorType], 0, sizeof(u64)*SIZE_MOVING_AVG_BUFFER); #endif data->first_sensor_data[uSensorType] = true; break; case GO_SLEEP: command = MSG2SSP_AP_STATUS_SLEEP; data->uLastAPState = MSG2SSP_AP_STATUS_SLEEP; break; case REMOVE_LIBRARY: command = MSG2SSP_INST_LIBRARY_REMOVE; break; case ADD_LIBRARY: command = MSG2SSP_INST_LIBRARY_ADD; break; default: command = uInst; break; } msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = command; msg->length = uLength + 1; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(uLength + 1, GFP_KERNEL); msg->free_buffer = 1; msg->buffer[0] = uSensorType; memcpy(&msg->buffer[1], uSendBuf, uLength); ssp_dbg("[SSP]: %s - Inst = 0x%x, Sensor Type = 0x%x, data = %u\n", __func__, command, uSensorType, msg->buffer[1]); iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP]: %s - Instruction CMD Fail %d\n", __func__, iRet); return ERROR; } if (uInst == ADD_SENSOR || uInst == CHANGE_DELAY) { unsigned int BatchTimeforReset = 0; //current_Ts = get_current_timestamp(); if (uLength >= 9) BatchTimeforReset = *(unsigned int *)(&uSendBuf[4]);// Add / change normal case, not factory. //pr_info("[SSP] %s timeForRest %d", __func__, BatchTimeforReset); data->IsBypassMode[uSensorType] = (BatchTimeforReset == 0); //pr_info("[SSP] sensor%d mode%d Time %lld\n", uSensorType, data->IsBypassMode[uSensorType], current_Ts); } return iRet; } int send_instruction_sync(struct ssp_data *data, u8 uInst, u8 uSensorType, u8 *uSendBuf, u16 uLength) { char command; int iRet = 0; char buffer[10] = { 0, }; struct ssp_msg *msg; //u64 current_Ts = 0; #ifdef CONFIG_SENSORS_SSP_HIFI_BATCHING u64 timestamp; #endif if ((!(data->uSensorState & (1ULL << uSensorType))) && (uInst <= CHANGE_DELAY)) { pr_err("[SSP]: %s - Bypass Inst Skip! - %u\n", __func__, uSensorType); return FAIL; } switch (uInst) { case REMOVE_SENSOR: command = MSG2SSP_INST_BYPASS_SENSOR_REMOVE; break; case ADD_SENSOR: command = MSG2SSP_INST_BYPASS_SENSOR_ADD; #ifdef CONFIG_SENSORS_SSP_HIFI_BATCHING timestamp = get_current_timestamp(); data->lastTimestamp[uSensorType] = data->LastSensorTimeforReset[uSensorType] = timestamp; data->ts_avg_buffer_idx[uSensorType] = 0; data->ts_avg_buffer_cnt[uSensorType] = 0; data->ts_avg_buffer_sum[uSensorType] = 0; data->ts_prev_index[uSensorType] = 0; data->ts_avg_skip_cnt[uSensorType] = SKIP_CNT_MOVING_AVG_ADD; data->ts_last_enable_cmd_time = timestamp; memset(data->ts_avg_buffer[uSensorType], 0, sizeof(u64)*SIZE_MOVING_AVG_BUFFER); #endif data->first_sensor_data[uSensorType] = true; break; case CHANGE_DELAY: command = MSG2SSP_INST_CHANGE_DELAY; #ifdef CONFIG_SENSORS_SSP_HIFI_BATCHING timestamp = get_current_timestamp(); data->LastSensorTimeforReset[uSensorType] = timestamp; data->ts_avg_buffer_idx[uSensorType] = 0; data->ts_avg_buffer_cnt[uSensorType] = 0; data->ts_avg_buffer_sum[uSensorType] = 0; data->ts_prev_index[uSensorType] = 0; data->ts_avg_skip_cnt[uSensorType] = SKIP_CNT_MOVING_AVG_CHANGE; memset(data->ts_avg_buffer[uSensorType], 0, sizeof(u64)*SIZE_MOVING_AVG_BUFFER); #endif data->first_sensor_data[uSensorType] = true; break; case GO_SLEEP: command = MSG2SSP_AP_STATUS_SLEEP; data->uLastAPState = MSG2SSP_AP_STATUS_SLEEP; break; case REMOVE_LIBRARY: command = MSG2SSP_INST_LIBRARY_REMOVE; break; case ADD_LIBRARY: command = MSG2SSP_INST_LIBRARY_ADD; break; default: command = uInst; break; } msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = command; msg->length = uLength + 1; msg->options = AP2HUB_WRITE | AP2HUB_RETURN; msg->buffer = buffer; msg->free_buffer = 0; msg->buffer[0] = uSensorType; memcpy(&msg->buffer[1], uSendBuf, uLength); ssp_dbg("[SSP]: %s - Inst Sync = 0x%x, Sensor Type = %u, data = %u\n", __func__, command, uSensorType, msg->buffer[0]); iRet = ssp_spi_sync(data, msg, 1000); if (iRet != SUCCESS) { pr_err("[SSP]: %s - Instruction CMD Fail %d\n", __func__, iRet); return ERROR; } if (uInst == ADD_SENSOR || uInst == CHANGE_DELAY) { unsigned int BatchTimeforReset = 0; //current_Ts = get_current_timestamp(); if (uLength >= 9) BatchTimeforReset = *(unsigned int *)(&uSendBuf[4]);// Add / change normal case, not factory. //pr_info("[SSP] %s timeForRest %d", __func__, BatchTimeforReset); data->IsBypassMode[uSensorType] = (BatchTimeforReset == 0); //pr_info("[SSP] sensor%d mode%d Time %lld\n", uSensorType, data->IsBypassMode[uSensorType], current_Ts); } return buffer[0]; } int flush(struct ssp_data *data, u8 uSensorType) { int iRet = 0; char buffer = 0; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_MCU_BATCH_FLUSH; msg->length = 1; msg->options = AP2HUB_READ; msg->data = uSensorType; msg->buffer = &buffer; msg->free_buffer = 0; iRet = ssp_spi_sync(data, msg, 1000); if (iRet != SUCCESS) { pr_err("[SSP]: %s - fail %d\n", __func__, iRet); return ERROR; } ssp_dbg("[SSP]: %s Sensor Type = 0x%x, data = %u\n", __func__, uSensorType, buffer); return buffer ? 0 : -1; } int get_batch_count(struct ssp_data *data, u8 uSensorType) { int iRet = 0; s32 result = 0; char buffer[4] = {0, }; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_MCU_BATCH_COUNT; msg->length = 4; msg->options = AP2HUB_READ; msg->data = uSensorType; msg->buffer = buffer; msg->free_buffer = 0; iRet = ssp_spi_sync(data, msg, 1000); if (iRet != SUCCESS) { pr_err("[SSP]: %s - fail %d\n", __func__, iRet); return ERROR; } memcpy(&result, buffer, 4); ssp_dbg("[SSP]: %s Sensor Type = 0x%x, data = %u\n", __func__, uSensorType, result); return result; } int get_chipid(struct ssp_data *data) { int iRet, iReties = 0; char buffer = 0; struct ssp_msg *msg; retries: msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_WHOAMI; msg->length = 1; msg->options = AP2HUB_READ; msg->buffer = &buffer; msg->free_buffer = 0; iRet = ssp_spi_sync(data, msg, 1000); if (buffer != DEVICE_ID && iReties++ < 2) { mdelay(5); pr_err("[SSP] %s - get chip ID retry\n", __func__); goto retries; } if (iRet == SUCCESS) return buffer; pr_err("[SSP] %s - get chip ID failed %d\n", __func__, iRet); return ERROR; } int set_sensor_position(struct ssp_data *data) { int iRet = 0; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_SENSOR_FORMATION; msg->length = 3; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(3, GFP_KERNEL); msg->free_buffer = 1; msg->buffer[0] = data->accel_position; msg->buffer[1] = data->accel_position; msg->buffer[2] = data->mag_position; iRet = ssp_spi_async(data, msg); pr_info("[SSP] Sensor Posision A : %u, G : %u, M: %u, P: %u\n", data->accel_position, data->accel_position, data->mag_position, 0); if (iRet != SUCCESS) { pr_err("[SSP] %s -fail to %s %d\n", __func__, __func__, iRet); iRet = ERROR; } return iRet; } #ifdef CONFIG_SENSORS_MULTIPLE_GLASS_TYPE int set_glass_type(struct ssp_data *data) { int iRet = 0; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_GLASS_TYPE; msg->length = 1; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(1, GFP_KERNEL); msg->free_buffer = 1; msg->buffer[0] = data->glass_type; iRet = ssp_spi_async(data, msg); pr_info("[SSP] glass_type : %u\n", data->glass_type); if (iRet != SUCCESS) { pr_err("[SSP] %s -fail to %s %d\n", __func__, __func__, iRet); iRet = ERROR; } return iRet; } #endif int set_magnetic_static_matrix(struct ssp_data *data) { int iRet = 0; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_SET_MAGNETIC_STATIC_MATRIX; msg->length = data->mag_matrix_size; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(data->mag_matrix_size, GFP_KERNEL); msg->free_buffer = 1; memcpy(msg->buffer, data->mag_matrix, data->mag_matrix_size); iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP] %s -fail to %s %d\n", __func__, __func__, iRet); iRet = ERROR; } return iRet; } void set_proximity_threshold(struct ssp_data *data) { int iRet = 0; struct ssp_msg *msg; if (!(data->uSensorState & (1 << PROXIMITY_SENSOR))) { pr_info("[SSP]: %s - Skip this function!!!,proximity sensor is not connected(0x%llx)\n", __func__, data->uSensorState); return; } msg = kzalloc(sizeof(*msg), GFP_KERNEL); #if defined(CONFIG_SENSORS_SSP_TMG399x) msg->cmd = MSG2SSP_AP_SENSOR_PROXTHRESHOLD; msg->length = 2; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(2, GFP_KERNEL); msg->free_buffer = 1; msg->buffer[0] = (char)data->uProxHiThresh; msg->buffer[1] = (char)data->uProxLoThresh; #elif defined(CONFIG_SENSORS_SSP_PROX_AUTOCAL_AMS) msg->cmd = MSG2SSP_AP_SENSOR_PROXTHRESHOLD; msg->length = 8; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(8, GFP_KERNEL); msg->free_buffer = 1; msg->buffer[0] = ((char) (data->uProxHiThresh >> 8) & 0xff); msg->buffer[1] = (char) data->uProxHiThresh; msg->buffer[2] = ((char) (data->uProxLoThresh >> 8) & 0xff); msg->buffer[3] = (char) data->uProxLoThresh; msg->buffer[4] = ((char) (data->uProxHiThresh_detect >> 8) & 0xff); msg->buffer[5] = (char) data->uProxHiThresh_detect; msg->buffer[6] = ((char) (data->uProxLoThresh_detect >> 8) & 0xff); msg->buffer[7] = (char) data->uProxLoThresh_detect; #else /* CONFIG_SENSORS_SSP_PROX_FACTORYCAL */ msg->cmd = MSG2SSP_AP_SENSOR_PROXTHRESHOLD; msg->length = 4; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(4, GFP_KERNEL); msg->free_buffer = 1; msg->buffer[0] = ((char) (data->uProxHiThresh >> 8) & 0xff); msg->buffer[1] = (char) data->uProxHiThresh; msg->buffer[2] = ((char) (data->uProxLoThresh >> 8) & 0xff); msg->buffer[3] = (char) data->uProxLoThresh; #endif iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP]: %s - SENSOR_PROXTHRESHOLD CMD fail %d\n", __func__, iRet); return; } #if defined(CONFIG_SENSORS_SSP_PROX_AUTOCAL_AMS) pr_info("[SSP]: Proximity Threshold - %u, %u, %u, %u\n", data->uProxHiThresh, data->uProxLoThresh, data->uProxHiThresh_detect, data->uProxLoThresh_detect); #else pr_info("[SSP]: Proximity Threshold - %u, %u\n", data->uProxHiThresh, data->uProxLoThresh); #endif } void set_proximity_alert_threshold(struct ssp_data *data) { int iRet = 0; struct ssp_msg *msg; if (!(data->uSensorState & (1 << PROXIMITY_ALERT_SENSOR))) { pr_info("[SSP]: %s - Skip this function!!!,proximity alert sensor is not connected(0x%llx)\n", __func__, data->uSensorState); return; } msg = kzalloc(sizeof(*msg), GFP_KERNEL); msg->cmd = MSG2SSP_AP_SENSOR_PROX_ALERT_THRESHOLD; msg->length = 2; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(2, GFP_KERNEL); msg->free_buffer = 1; msg->buffer[0] = ((char) (data->uProxAlertHiThresh >> 8) & 0xff); msg->buffer[1] = (char) data->uProxAlertHiThresh; iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP]: %s - SENSOR_PROX_ALERT_THRESHOLD CMD fail %d\n", __func__, iRet); return; } pr_info("[SSP]: %s Proximity alert Threshold - %u\n", __func__, data->uProxAlertHiThresh); } void set_light_coef(struct ssp_data *data) { int iRet = 0; struct ssp_msg *msg; if (!(data->uSensorState & (1 << LIGHT_SENSOR))) { pr_info("[SSP]: %s - Skip this function!!!,light sensor is not connected(0x%llx)\n", __func__, data->uSensorState); return; } msg = kzalloc(sizeof(*msg), GFP_KERNEL); msg->cmd = MSG2SSP_AP_SET_LIGHT_COEF; msg->length = sizeof(data->light_coef); msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(sizeof(data->light_coef), GFP_KERNEL); msg->free_buffer = 1; memcpy(msg->buffer, data->light_coef, sizeof(data->light_coef)); iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP]: %s - MSG2SSP_AP_SET_LIGHT_COEF CMD fail %d\n", __func__, iRet); return; } pr_info("[SSP]: %s - %d %d %d %d %d %d %d\n", __func__, data->light_coef[0], data->light_coef[1], data->light_coef[2], data->light_coef[3], data->light_coef[4], data->light_coef[5], data->light_coef[6]); } void set_proximity_barcode_enable(struct ssp_data *data, bool bEnable) { int iRet = 0; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); msg->cmd = MSG2SSP_AP_SENSOR_BARCODE_EMUL; msg->length = 1; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(1, GFP_KERNEL); msg->free_buffer = 1; data->bBarcodeEnabled = bEnable; msg->buffer[0] = bEnable; iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP]: %s - SENSOR_BARCODE_EMUL CMD fail %d\n", __func__, iRet); return; } pr_info("[SSP] Proximity Barcode En : %u\n", bEnable); } void set_gesture_current(struct ssp_data *data, unsigned char uData1) { int iRet = 0; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); msg->cmd = MSG2SSP_AP_SENSOR_GESTURE_CURRENT; msg->length = 1; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(1, GFP_KERNEL); msg->free_buffer = 1; msg->buffer[0] = uData1; iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP]: %s - SENSOR_GESTURE_CURRENT CMD fail %d\n", __func__, iRet); return; } pr_info("[SSP]: Gesture Current Setting - %u\n", uData1); } int set_hall_threshold(struct ssp_data *data) { int iRet = 0; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP]: %s - failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_SET_HALL_THRESHOLD; msg->length = sizeof(data->hall_threshold); msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(sizeof(data->hall_threshold), GFP_KERNEL); msg->free_buffer = 1; memcpy(msg->buffer, data->hall_threshold, sizeof(data->hall_threshold)); iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP]: %s - fail to %s %d\n", __func__, __func__, iRet); iRet = ERROR; } return iRet; } u64 get_sensor_scanning_info(struct ssp_data *data) { int iRet = 0, z = 0; u64 result = 0; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_SENSOR_SCANNING; msg->length = 8; msg->options = AP2HUB_READ; msg->buffer = (char *) &result; msg->free_buffer = 0; iRet = ssp_spi_sync(data, msg, 1000); if (iRet != SUCCESS) pr_err("[SSP]: %s - i2c fail %d\n", __func__, iRet); data->sensor_state[SENSOR_MAX] = '\0'; for (z = 0; z < SENSOR_MAX; z++) data->sensor_state[SENSOR_MAX - 1 - z] = (result & (1ULL << z)) ? '1' : '0'; pr_err("[SSP]: state: %s\n", data->sensor_state); return result; } unsigned int get_firmware_rev(struct ssp_data *data) { int iRet; u32 result = SSP_INVALID_REVISION; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_FIRMWARE_REV; msg->length = 4; msg->options = AP2HUB_READ; msg->buffer = (char *) &result; msg->free_buffer = 0; iRet = ssp_spi_sync(data, msg, 1000); if (iRet != SUCCESS) pr_err("[SSP]: %s - transfer fail %d\n", __func__, iRet); return result; } int set_big_data_start(struct ssp_data *data, u8 type, u32 length) { int iRet = 0; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_START_BIG_DATA; msg->length = 5; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(5, GFP_KERNEL); msg->free_buffer = 1; msg->buffer[0] = type; memcpy(&msg->buffer[1], &length, 4); iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP]: %s - i2c fail %d\n", __func__, iRet); iRet = ERROR; } return iRet; } int set_time(struct ssp_data *data) { int iRet; struct ssp_msg *msg; struct timespec ts; struct rtc_time tm; getnstimeofday(&ts); rtc_time_to_tm(ts.tv_sec, &tm); pr_info("[SSP]: %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n", __func__, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_MCU_SET_TIME; msg->length = 12; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(12, GFP_KERNEL); msg->free_buffer = 1; msg->buffer[0] = tm.tm_hour; msg->buffer[1] = tm.tm_min; msg->buffer[2] = tm.tm_sec; msg->buffer[3] = tm.tm_hour > 11 ? 64 : 0; msg->buffer[4] = tm.tm_wday; msg->buffer[5] = tm.tm_mon + 1; msg->buffer[6] = tm.tm_mday; msg->buffer[7] = tm.tm_year % 100; memcpy(&msg->buffer[8], &ts.tv_nsec, 4); iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP]: %s - i2c fail %d\n", __func__, iRet); iRet = ERROR; } return iRet; } int get_time(struct ssp_data *data) { int iRet; char buffer[12] = { 0, }; struct ssp_msg *msg; struct timespec ts; struct rtc_time tm; getnstimeofday(&ts); rtc_time_to_tm(ts.tv_sec, &tm); pr_info("[SSP]: %s ap %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n", __func__, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { iRet = -ENOMEM; pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); return iRet; } msg->cmd = MSG2SSP_AP_MCU_GET_TIME; msg->length = 12; msg->options = AP2HUB_READ; msg->buffer = buffer; msg->free_buffer = 0; iRet = ssp_spi_sync(data, msg, 1000); if (iRet != SUCCESS) { pr_err("[SSP]: %s - i2c failed %d\n", __func__, iRet); return 0; } tm.tm_hour = buffer[0]; tm.tm_min = buffer[1]; tm.tm_sec = buffer[2]; tm.tm_mon = msg->buffer[5] - 1; tm.tm_mday = buffer[6]; tm.tm_year = buffer[7] + 100; rtc_tm_to_time(&tm, &ts.tv_sec); memcpy(&ts.tv_nsec, &msg->buffer[8], 4); rtc_time_to_tm(ts.tv_sec, &tm); pr_info("[SSP]: %s mcu %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n", __func__, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); return iRet; } void set_gyro_cal_lib_enable(struct ssp_data *data, bool bEnable) { int iRet = 0; u8 cmd; struct ssp_msg *msg; pr_info("[SSP] %s - enable %d(cur %d)\n", __func__, bEnable, data->gyro_lib_state); if (bEnable) cmd = SH_MSG2AP_GYRO_CALIBRATION_START; else cmd = SH_MSG2AP_GYRO_CALIBRATION_STOP; msg = kzalloc(sizeof(*msg), GFP_KERNEL); msg->cmd = cmd; msg->length = 1; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(1, GFP_KERNEL); msg->free_buffer = 1; msg->buffer[0] = bEnable; iRet = ssp_spi_async(data, msg); if (iRet == SUCCESS) { if (bEnable) data->gyro_lib_state = GYRO_CALIBRATION_STATE_REGISTERED; else data->gyro_lib_state = GYRO_CALIBRATION_STATE_DONE; } else pr_err("[SSP] %s - gyro lib enable cmd fail\n", __func__); } #if defined(CONFIG_SSP_MOTOR_CALLBACK) int send_motor_state(struct ssp_data *data) { int iRet = 0; struct ssp_msg *msg; msg = kzalloc(sizeof(*msg), GFP_KERNEL); msg->cmd = MSG2SSP_AP_MCU_SET_MOTOR_STATUS; msg->length = 1; msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(1, GFP_KERNEL); msg->free_buffer = 1; /*if 1: start, 0: stop*/ msg->buffer[0] = data->motor_state; iRet = ssp_spi_async(data, msg); if (iRet != SUCCESS) { pr_err("[SSP]: %s - fail %d\n", __func__, iRet); return iRet; } pr_info("[SSP] %s - En : %u\n", __func__, data->motor_state); return data->motor_state; } #endif u8 get_accel_range(struct ssp_data *data) { int iRet = 0; struct ssp_msg *msg; u8 rxbuffer[1] = {0x00}; msg = kzalloc(sizeof(*msg), GFP_KERNEL); msg->cmd = MSG2SSP_AP_MCU_GET_ACCEL_RANGE; msg->length = 1; msg->options = AP2HUB_READ; msg->buffer = rxbuffer; msg->free_buffer = 0; iRet = ssp_spi_sync(data, msg, 1000); if (iRet != SUCCESS) { pr_err("[SSP]: %s - fail %d\n", __func__, iRet); return iRet; } pr_info("[SSP] %s - Range : %u\n", __func__, rxbuffer[0]); return rxbuffer[0]; }