blob: 3e5e76215ed4e143ed372fdc8a1fda2457f2fb53 [file] [log] [blame]
/*
* Copyright (C) 2015, 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_data.h"
#define U64_US2NS 1000ULL
/*************************************************************************/
/* SSP parsing the dataframe */
/*************************************************************************/
static void get_timestamp(struct ssp_data *data, char *dataframe,
int *ptr_data, struct sensor_value *event,
u16 mode, int type)
{
u32 ts_delta_us = 0;
u64 ts_delta_ns = 0;
u64 current_timestamp = get_current_timestamp();
memset(&ts_delta_us, 0, 4);
memcpy(&ts_delta_us, dataframe + *ptr_data, 4);
ts_delta_ns = (((u64) ts_delta_us) * U64_US2NS);
if(data->info[type].report_mode == REPORT_MODE_CONTINUOUS)
{
if(data->latest_timestamp[type] == -1) /* first sensordata after resume*/
{
data->latest_timestamp[type] = current_timestamp;
}
else
{
data->latest_timestamp[type] += ts_delta_ns;
if(data->latest_timestamp[type] > current_timestamp)
{
//ssp_infof("future timestamp : last = %lld, cur = %lld",data->latest_timestamp[type],current_timestamp);
data->latest_timestamp[type] = current_timestamp;
}
}
}
else
{
data->latest_timestamp[type] = current_timestamp;
}
event->timestamp = data->latest_timestamp[type];
*ptr_data += 4;
}
void get_sensordata(struct ssp_data *data, char *dataframe,
int *ptr_data, int type, struct sensor_value *event)
{
memcpy(event, dataframe + *ptr_data, data->info[type].get_data_len);
*ptr_data += data->info[type].get_data_len;
}
int handle_big_data(struct ssp_data *data, char *dataframe, int *ptr_data)
{
u8 big_type = 0;
struct ssp_big *big = kzalloc(sizeof(*big), GFP_KERNEL);
big->data = data;
big_type = dataframe[(*ptr_data)++];
memcpy(&big->length, dataframe + *ptr_data, 4);
*ptr_data += 4;
memcpy(&big->addr, dataframe + *ptr_data, 4);
*ptr_data += 4;
if (big_type >= BIG_TYPE_MAX) {
kfree(big);
return FAIL;
}
INIT_WORK(&big->work, data->ssp_big_task[big_type]);
queue_work(data->debug_wq, &big->work);
return SUCCESS;
}
void refresh_task(struct work_struct *work)
{
struct ssp_data *data = container_of((struct delayed_work *)work,
struct ssp_data, work_refresh);
ssp_dbgf("REFESH TASK");
if (data->is_ssp_shutdown == true) {
ssp_errf("ssp already shutdown");
return;
}
wake_lock(&data->ssp_wake_lock);
ssp_errf();
data->cnt_reset++;
if (initialize_mcu(data) > 0) {
sync_sensor_state(data);
ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_RESET);
if (data->uLastAPState != 0)
ssp_send_cmd(data, data->uLastAPState, 0);
if (data->uLastResumeState != 0)
ssp_send_cmd(data, data->uLastResumeState, 0);
data->cnt_timeout = 0;
} else
data->uSensorState = 0;
data->is_reset_started = false;
wake_unlock(&data->ssp_wake_lock);
}
int queue_refresh_task(struct ssp_data *data, int delay)
{
cancel_delayed_work_sync(&data->work_refresh);
ssp_dbgf();
queue_delayed_work(data->debug_wq, &data->work_refresh,
msecs_to_jiffies(delay));
return SUCCESS;
}
int parse_dataframe(struct ssp_data *data, char *dataframe, int frame_len)
{
struct sensor_value event;
u16 batch_event_count;
u16 mode;
int type, index;
u16 length = 0;
s16 caldata[3] = {0, };
if (data->is_ssp_shutdown) {
ssp_infof("ssp shutdown, do not parse");
return SUCCESS;
}
if (data->debug_enable)
print_dataframe(data, dataframe, frame_len);
memset(&event, 0, sizeof(event));
for (index = 0; index < frame_len;) {
switch (dataframe[index++]) {
case MSG2AP_INST_BYPASS_DATA:
type = dataframe[index++];
if ((type < 0) || (type >= SENSOR_TYPE_MAX)) {
ssp_errf("Mcu bypass dataframe err %d", type);
return ERROR;
}
memcpy(&length, dataframe + index, 2);
index += 2;
batch_event_count = length;
mode = length > 1 ? BATCH_MODE_RUN : BATCH_MODE_NONE;
do {
get_sensordata(data, dataframe, &index, type, &event);
get_timestamp(data, dataframe, &index, &event, mode, type);
report_sensor_data(data, type, &event);
batch_event_count--;
} while ((batch_event_count > 0) && (index < frame_len));
if (batch_event_count > 0)
ssp_errf("batch count error (%d)", batch_event_count);
data->is_data_reported[type] = true;
break;
case MSG2AP_INST_DEBUG_DATA:
type = print_mcu_debug(dataframe, &index, frame_len);
if (type) {
ssp_errf("Mcu debug dataframe err %d", type);
return ERROR;
}
break;
case MSG2AP_INST_LIBRARY_DATA:
memcpy(&length, dataframe + index, 2);
index += 2;
ssp_sensorhub_handle_data(data, dataframe, index,
index + length);
index += length;
break;
case MSG2AP_INST_BIG_DATA:
handle_big_data(data, dataframe, &index);
break;
case MSG2AP_INST_META_DATA:
event.meta_data.what = dataframe[index++];
event.meta_data.sensor = dataframe[index++];
report_meta_data(data, SENSOR_TYPE_META, &event);
break;
case MSG2AP_INST_TIME_SYNC:
data->is_time_syncing = true;
break;
case MSG2AP_INST_RESET:
data->uSensorState = 0;
ssp_infof("Reset MSG received from MCU");
if(data->is_probe_done == true)
queue_refresh_task(data, 0);
else
ssp_infof("skip reset msg");
break;
case MSG2AP_INST_GYRO_CAL:
ssp_infof("Gyro caldata received from MCU\n");
memcpy(caldata, dataframe + index, sizeof(caldata));
wake_lock(&data->ssp_wake_lock);
save_gyro_cal_data(data, caldata);
wake_unlock(&data->ssp_wake_lock);
index += sizeof(caldata);
break;
case SH_MSG2AP_GYRO_CALIBRATION_EVENT_OCCUR:
data->gyro_lib_state = GYRO_CALIBRATION_STATE_EVENT_OCCUR;
ssp_infof("Gyro caldata event occur received from MCU\n");
break;
case MSG2AP_INST_DUMP_DATA:
debug_crash_dump(data, dataframe, frame_len);
break;
}
}
return SUCCESS;
}
void initialize_function_pointer(struct ssp_data *data)
{
data->ssp_big_task[BIG_TYPE_DUMP] = ssp_dump_task;
data->ssp_big_task[BIG_TYPE_READ_LIB] = ssp_read_big_library_task;
}