/* * Copyright (C) 2018, 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 #include #include #include #include #include "ssp_data.h" #include "ssp_debug.h" #include "ssp_iio.h" #include "ssp_type_define.h" #include "ssp_cmd_define.h" #include "ssp_comm.h" #include "ssp_sysfs.h" #define SSP2AP_BYPASS_DATA 0x37 #define SSP2AP_LIBRARY_DATA 0x01 #define SSP2AP_DEBUG_DATA 0x03 #define SSP2AP_BIG_DATA 0x04 #define SSP2AP_META_DATA 0x05 #define SSP2AP_TIME_SYNC 0x06 #define SSP2AP_NOTI_RESET 0x07 #define SSP2AP_GYRO_CAL 0x08 #define SSP2AP_PROX_THRESH 0x09 #define SSP2AP_REQ_RESET 0x0A #define SSP2AP_MAG_CAL 0x0B #define SSP2AP_DUMP_DATA 0xDD #define SSP2AP_CALLSTACK 0x0F #define SSP2AP_SYSTEM_INFO 0x31 #define SSP2AP_SENSOR_SPEC 0x41 typedef enum _hub_req_reset_type { HUB_RESET_REQ_NO_EVENT = 0x1a, } hub_req_reset_type; #define U64_US2NS 1000ULL #define SSP_TIMESTAMP_SYNC_TIMER_SEC (30 * HZ) /* fw */ #define SSP_INVALID_REVISION 99999 #define SSP_INVALID_REVISION2 0xFFFFFF u64 get_current_timestamp(void) { u64 timestamp; struct timespec ts; ts = ktime_to_timespec(ktime_get_boottime()); timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec; return timestamp; } void get_timestamp(struct ssp_data *data, char *dataframe, int *ptr_data, struct sensor_value *event, int type) { u64 timestamp_ns = 0; u64 current_timestamp = get_current_timestamp(); memset(×tamp_ns, 0, 8); memcpy(×tamp_ns, dataframe + *ptr_data, 8); if (timestamp_ns > current_timestamp) { //ssp_infof("future timestamp(%d) : last = %lld, cur = %lld", type, data->latest_timestamp[type], current_timestamp); timestamp_ns = current_timestamp; } event->timestamp = timestamp_ns; data->buf[type].timestamp = event->timestamp; data->latest_timestamp[type] = current_timestamp; *ptr_data += 8; } 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; memcpy(&data->buf[type], (char *)event, data->info[type].get_data_len); } void show_system_info(char *dataframe, int *idx) { typedef struct _sensor_debug_info { uint8_t uid; uint8_t total_count; uint8_t ext_client; int32_t ext_sampling; int32_t ext_report; int32_t fastest_sampling; } sensor_debug_info; typedef struct _base_timestamp { uint64_t kernel_base; uint64_t hub_base; } base_timestamp; typedef struct _utc_time { int8_t nHour; int8_t nMinute; int8_t nSecond; int16_t nMilliSecond; } utc_time; typedef struct _system_debug_info { int32_t version; int32_t rate; int8_t ap_state; utc_time time; base_timestamp timestamp; } system_debug_info; //===================================================// sensor_debug_info *info = 0; system_debug_info *s_info = 0; int i; int count = *dataframe; ++dataframe; *idx += (1 + sizeof(sensor_debug_info) * count + sizeof(system_debug_info)); ssp_info("==system info ==="); for (i = 0; i < count; ++i) { info = (sensor_debug_info *)dataframe; ssp_info("id(%d), total(%d), external(%d), e_sampling(%d), e_report(%d), fastest(%d)", info->uid, info->total_count, info->ext_client, info->ext_sampling, info->ext_report, info->fastest_sampling); dataframe += sizeof(sensor_debug_info); } s_info = (system_debug_info *)dataframe; ssp_info("version(%d), rate(%d), ap_state(%s), time(%d:%d:%d.%d), base_ts_k(%lld), base_ts_hub(%lld)", s_info->version, s_info->rate, s_info->ap_state == 0 ? "run" : "suspend", s_info->time.nHour, s_info->time.nMinute, s_info->time.nSecond, s_info->time.nMilliSecond, s_info->timestamp.kernel_base, s_info->timestamp.hub_base); } void handle_sensor_spec(struct ssp_data *data, char *dataframe, int *idx) { struct sensor_spec_t *spec = 0; int i = 0, prev_size = data->sensor_spec_size; int count = *dataframe; int size = (sizeof(struct sensor_spec_t) * count); char *prev_sensor_spec = data->sensor_spec; ++dataframe; *idx += (size + 1); if (size == 0) return; ssp_infof("prev size %d cur size %d", prev_size, size); ssp_infof("count %d unit size %d", count, sizeof(struct sensor_spec_t)); data->sensor_spec = kzalloc(size + prev_size, GFP_KERNEL); if (prev_sensor_spec != NULL) { // prev_size != 0 memcpy(data->sensor_spec, prev_sensor_spec, prev_size); kfree(prev_sensor_spec); } memcpy(data->sensor_spec + prev_size, dataframe, size); data->sensor_spec_size = size + prev_size; for (i = 0; i < count; ++i) { spec = (struct sensor_spec_t *)dataframe; dataframe += sizeof(struct sensor_spec_t); ssp_info("id(%d), name(%s), vendor(%d)", spec->uid, spec->name, spec->vendor); if (spec->uid == SENSOR_TYPE_ACCELEROMETER) { #ifdef CONFIG_SENSORS_SSP_ACCELOMETER select_accel_ops(data, spec->name); #endif } #ifdef CONFIG_SENSORS_SSP_GYROSCOPE else if (spec->uid == SENSOR_TYPE_GYROSCOPE) select_gyro_ops(data, spec->name); #endif #ifdef CONFIG_SENSORS_SSP_MAGNETIC else if (spec->uid == SENSOR_TYPE_GEOMAGNETIC_FIELD) select_magnetic_ops(data, spec->name); #endif #ifdef CONFIG_SENSORS_SSP_BAROMETER else if (spec->uid == SENSOR_TYPE_PRESSURE) select_barometer_ops(data, spec->name); #endif #ifdef CONFIG_SENSORS_SSP_LIGHT else if (spec->uid == SENSOR_TYPE_LIGHT) select_light_ops(data, spec->name); #endif #ifdef CONFIG_SENSORS_SSP_PROXIMITY else if (spec->uid == SENSOR_TYPE_PROXIMITY) select_prox_ops(data, spec->name); #endif } } int parse_dataframe(struct ssp_data *data, char *dataframe, int frame_len) { int type, index; struct sensor_value event; u16 batch_event_count; bool parsing_error = false; u16 length = 0; if (!is_sensorhub_working(data)) { ssp_infof("ssp shutdown, do not parse"); return SUCCESS; } //print_dataframe(data, dataframe, frame_len); memset(&event, 0, sizeof(event)); for (index = 0; index < frame_len && !parsing_error;) { switch (dataframe[index++]) { case SSP2AP_DEBUG_DATA: type = print_mcu_debug(dataframe, &index, frame_len); if (type) { ssp_errf("Mcu debug dataframe err %d", type); parsing_error = true; } break; case SSP2AP_BYPASS_DATA: type = dataframe[index++]; if ((type < 0) || (type >= SENSOR_TYPE_MAX)) { ssp_errf("Mcu bypass dataframe err %d", type); parsing_error = true; break; } memcpy(&length, dataframe + index, 2); index += 2; batch_event_count = length; do { get_sensordata(data, dataframe, &index, type, &event); get_timestamp(data, dataframe, &index, &event, 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); break; case SSP2AP_LIBRARY_DATA: memcpy(&length, dataframe + index, 2); index += 2; report_scontext_data(data, dataframe + index, length); index += length; break; case SSP2AP_META_DATA: event.meta_data.what = dataframe[index++]; event.meta_data.sensor = dataframe[index++]; if ((event.meta_data.sensor < 0) || (event.meta_data.sensor >= SENSOR_TYPE_MAX)) { ssp_errf("mcu meta data sensor dataframe err %d", event.meta_data.sensor); parsing_error = true; break; } report_meta_data(data, &event); break; case SSP2AP_NOTI_RESET: ssp_infof("Reset MSG received from MCU"); if (data->is_probe_done == true) { //data->sensor_probe_state = 0; //queue_refresh_task(data, 0); } else ssp_infof("skip reset msg"); break; case SSP2AP_REQ_RESET: { int reset_type = dataframe[index++]; //if (reset_type == HUB_RESET_REQ_NO_EVENT) { ssp_infof("Hub request reset[0x%x] No Event type %d", reset_type, dataframe[index++]); reset_mcu(data, RESET_TYPE_HUB_NO_EVENT); //} } break; #ifdef CONFIG_SENSORS_SSP_GYROSCOPE case SSP2AP_GYRO_CAL: { s16 caldata[3] = {0, }; 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; #endif // CONFIG_SENSORS_SSP_GYROSCOPE #ifdef CONFIG_SENSORS_SSP_MAGNETIC case SSP2AP_MAG_CAL: { #ifdef CONFIG_SENSORS_SSP_MAGNETIC_MMC5603 u8 caldata[16] = {0,}; #else u8 caldata[13] = {0,}; #endif ssp_infof("Mag caldata received from MCU(%d)\n", sizeof(caldata)); memcpy(caldata, dataframe + index, sizeof(caldata)); wake_lock(&data->ssp_wake_lock); save_mag_cal_data(data, caldata); wake_unlock(&data->ssp_wake_lock); index += sizeof(caldata); } break; #endif #ifdef CONFIG_SENSORS_SSP_PROXIMITY #ifdef CONFIG_SENSROS_SSP_PROXIMITY_THRESH_CAL case SSP2AP_PROX_THRESH: { u16 thresh[2] = {0, }; memcpy(thresh, dataframe + index, sizeof(thresh)); data->prox_thresh[0] = thresh[0]; data->prox_thresh[1] = thresh[1]; index += sizeof(thresh); ssp_infof("prox thresh received %u %u", data->prox_thresh[0], data->prox_thresh[1]); } break; #endif // CONFIG_SENSROS_SSP_PROXIMITY_THRESH_CAL #endif // CONFIG_SENSORS_SSP_PROXIMITY case SSP2AP_SYSTEM_INFO: show_system_info(dataframe + index, &index); break; case SSP2AP_SENSOR_SPEC: handle_sensor_spec(data, dataframe + index, &index); break; default : ssp_errf("0x%x cmd doesn't support", dataframe[index-1]); parsing_error = true; break; } } if (parsing_error) { print_dataframe(data, dataframe, frame_len); return ERROR; } return 0; } int get_sensor_scanning_info(struct ssp_data *data) { int ret = 0, z = 0; uint64_t result[3] = {0,}; char *buffer = NULL; unsigned int buffer_length; char sensor_scanning_state[SENSOR_TYPE_MAX + 1]; ret = ssp_send_command(data, CMD_GETVALUE, TYPE_MCU, SENSOR_SCAN_RESULT, 1000, NULL, 0, &buffer, &buffer_length); if (ret < 0) ssp_errf("MSG2SSP_AP_SENSOR_SCANNING fail %d", ret); else memcpy(&result[0], buffer, buffer_length > sizeof(result) ? sizeof(result) : buffer_length); data->sensor_probe_state = result[0]; memcpy(&data->ss_sensor_probe_state, &result[1], sizeof(data->ss_sensor_probe_state)); sensor_scanning_state[SENSOR_TYPE_MAX] = '\0'; for (z = 0; z < SENSOR_TYPE_MAX; z++) { if (!(result[0] & (1ULL << z)) && z != SENSOR_TYPE_SCONTEXT && z != SENSOR_TYPE_SENSORHUB) data->info[z].enable = false; sensor_scanning_state[SENSOR_TYPE_MAX - 1 - z] = (result[0] & (1ULL << z)) ? '1' : '0'; } ssp_info("state(0x%llx): %s", data->sensor_probe_state, sensor_scanning_state); ssp_info("probe state 0x%llx, 0x%llx, 0x%llx", result[0], result[1], result[2]); if (buffer != NULL) kfree(buffer); return ret; } int get_firmware_rev(struct ssp_data *data) { int ret; u32 result = SSP_INVALID_REVISION; char *buffer = NULL; int buffer_length; ret = ssp_send_command(data, CMD_GETVALUE, TYPE_MCU, VERSION_INFO, 1000, NULL, 0, &buffer, &buffer_length); if (ret != SUCCESS) ssp_errf("transfer fail %d", ret); else if (buffer_length != sizeof(result)) ssp_errf("VERSION_INFO length is wrong"); else memcpy(&result, buffer, buffer_length); if (buffer != NULL) kfree(buffer); data->curr_fw_rev = result; ssp_info("MCU Firm Rev : New = %8u", data->curr_fw_rev); return ret; } int set_sensor_position(struct ssp_data *data) { int ret[3] = {0,}; ssp_infof(); #ifdef CONFIG_SENSORS_SSP_ACCELOMETER ret[0] = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_ACCELEROMETER, SENSOR_AXIS, 0, (char *)&(data->accel_position), sizeof(data->accel_position), NULL, NULL); ssp_infof("A : %u", data->accel_position); #endif #ifdef CONFIG_SENSORS_SSP_GYROSCOPE ret[1] = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_GYROSCOPE, SENSOR_AXIS, 0, (char *)&(data->gyro_position), sizeof(data->gyro_position), NULL, NULL); ssp_infof("G : %u", data->gyro_position); #endif #ifdef CONFIG_SENSORS_SSP_MAGNETIC ret[2] = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_GEOMAGNETIC_FIELD, SENSOR_AXIS, 0, (char *)&(data->mag_position), sizeof(data->mag_position), NULL, NULL); ssp_infof("M : %u", data->mag_position); #endif if ((ret[0] & ret[1] & ret[2]) != 0) { ssp_errf("fail to set_sensor_position %d %d %d", ret[0], ret[1], ret[2]); return ERROR; } return 0; } #ifdef CONFIG_SENSORS_SSP_PROXIMITY #ifdef CONFIG_SENSROS_SSP_PROXIMITY_THRESH_CAL void set_proximity_threshold_addval(struct ssp_data *data) { int ret = 0; u16 prox_th_addval[PROX_THRESH_SIZE + 1] = {0, }; if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_PROXIMITY))) { ssp_infof("Skip this function!, proximity sensor is not connected(0x%llx)", data->sensor_probe_state); return; } memcpy(prox_th_addval, data->prox_thresh_addval, sizeof(prox_th_addval)); ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_PROXIMITY, PROXIMITY_ADDVAL, 0, (char *)prox_th_addval, sizeof(prox_th_addval), NULL, NULL); if (ret != SUCCESS) { ssp_err("SENSOR_PROXTHRESHOLD CMD fail %d", ret); return; } ssp_info("Proximity Threshold Additional Value(%d) - %u, %u", sizeof(prox_th_addval), data->prox_thresh_addval[PROX_THRESH_HIGH], data->prox_thresh_addval[PROX_THRESH_LOW]); } #endif #ifdef CONFIG_SENSORS_SSP_PROXIMITY_MODIFY_SETTINGS #define PROX_SETTINGS_FILE_PATH "/efs/FactoryApp/prox_settings" int save_proximity_setting_mode(struct ssp_data *data) { struct file *filp = NULL; mm_segment_t old_fs; int ret = -1; char buf[3] = ""; int buf_len = 0; buf_len = snprintf(buf, PAGE_SIZE, "%d", data->prox_setting_mode); old_fs = get_fs(); set_fs(KERNEL_DS); filp = filp_open(PROX_SETTINGS_FILE_PATH, O_CREAT | O_TRUNC | O_RDWR | O_SYNC, 0666); if (filp == NULL) { ssp_infof("filp is NULL"); return ret; } if (IS_ERR(filp)) { set_fs(old_fs); ret = PTR_ERR(filp); ssp_errf("Can't open prox settings file (%d)", ret); return ret; } ret = vfs_write(filp, buf, buf_len, &filp->f_pos); if (ret != buf_len) { ssp_errf("Can't write the prox settings data to file, ret=%d", ret); ret = -EIO; } filp_close(filp, current->files); set_fs(old_fs); msleep(150); return ret; } int open_proximity_setting_mode(struct ssp_data *data) { struct file *filp = NULL; mm_segment_t old_fs; int ret = -1; char buf[3] = ""; old_fs = get_fs(); set_fs(KERNEL_DS); filp = filp_open(PROX_SETTINGS_FILE_PATH, O_RDONLY, 0); if (IS_ERR(filp)) { set_fs(old_fs); ret = PTR_ERR(filp); ssp_errf("Can't open prox settings file (%d)", ret); return ret; } ret = vfs_read(filp, buf, sizeof(buf), &filp->f_pos); ssp_infof("buf=%s", buf); if (ret <= 0) { ssp_errf("Can't read the prox settings data from file, bytes=%d", ret); ret = -EIO; } else { sscanf(buf, "%d", &data->prox_setting_mode); ssp_infof("prox_settings %d", data->prox_setting_mode); if (data->prox_setting_mode != 1 && data->prox_setting_mode != 2) { data->prox_setting_mode = 1; ssp_errf("leg_reg_val is wrong. set defulat setting"); } } filp_close(filp, current->files); set_fs(old_fs); if (data->prox_setting_mode != 1) memcpy(data->prox_thresh, data->prox_mode_thresh, sizeof(data->prox_thresh)); return ret; } void set_proximity_setting_mode(struct ssp_data *data) { int ret = 0; u8 mode = data->prox_setting_mode; if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_PROXIMITY))) { ssp_infof("Skip this function!, proximity sensor is not connected(0x%llx)", data->sensor_probe_state); return; } ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_PROXIMITY, PROXIMITY_SETTING_MODE, 0, (char *)&mode, sizeof(mode), NULL, NULL); if (ret != SUCCESS) { ssp_err("PROXIMITY_SETTING_MODE CMD fail %d", ret); return; } ssp_infof("%d", mode); } #endif void proximity_calibration_off(struct ssp_data *data) { ssp_infof(""); disable_legacy_sensor(data, SENSOR_TYPE_PROXIMITY_CALIBRATION); } void do_proximity_calibration(struct ssp_data *data) { ssp_infof(""); set_delay_legacy_sensor(data, SENSOR_TYPE_PROXIMITY_CALIBRATION, 10, 0); enable_legacy_sensor(data, SENSOR_TYPE_PROXIMITY_CALIBRATION); } void set_proximity_threshold(struct ssp_data *data) { int ret = 0; #if defined(CONFIG_SENSORS_SSP_PROXIMITY_AUTO_CAL_TMD3725) char prox_th[PROX_THRESH_SIZE] = {0, }; #else u16 prox_th[PROX_THRESH_SIZE] = {0, }; #endif if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_PROXIMITY))) { ssp_infof("Skip this function!, proximity sensor is not connected(0x%llx)", data->sensor_probe_state); return; } memcpy(prox_th, data->prox_thresh, sizeof(prox_th)); ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_PROXIMITY, PROXIMITY_THRESHOLD, 0, (char *)prox_th, sizeof(prox_th), NULL, NULL); if (ret != SUCCESS) { ssp_err("SENSOR_PROXTHRESHOLD CMD fail %d", ret); return; } #if defined(CONFIG_SENSORS_SSP_PROXIMITY_AUTO_CAL_TMD3725) ssp_info("Proximity Threshold - %u, %u, %u, %u", data->prox_thresh[PROX_THRESH_HIGH], data->prox_thresh[PROX_THRESH_LOW], data->prox_thresh[PROX_THRESH_DETECT_HIGH], data->prox_thresh[PROX_THRESH_DETECT_LOW]); #else ssp_info("Proximity Threshold - %u, %u", data->prox_thresh[PROX_THRESH_HIGH], data->prox_thresh[PROX_THRESH_LOW]); #endif } #endif #ifdef CONFIG_SENSORS_SSP_LIGHT void set_light_coef(struct ssp_data *data) { int ret = 0; if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_LIGHT))) { pr_info("[SSP]: %s - Skip this function!!!,"\ "light sensor is not connected(0x%llx)\n", __func__, data->sensor_probe_state); return; } ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_LIGHT, LIGHT_COEF, 0, (char *)data->light_coef, sizeof(data->light_coef), NULL, NULL); if (ret != SUCCESS) { pr_err("[SSP]: %s - MSG2SSP_AP_SET_LIGHT_COEF CMD fail %d\n", __func__, ret); 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_light_brightness(struct ssp_data *data) { int ret = 0; if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_LIGHT))) { ssp_infof("Skip this function!!!,"\ "light sensor is not connected(0x%llx)\n", data->sensor_probe_state); return; } ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_LIGHT, LIGHT_BRIGHTNESS, 0, (char *)&data->brightness, sizeof(data->brightness), NULL, NULL); if (ret != SUCCESS) { ssp_errf("CMD fail %d\n", ret); return; } ssp_infof("%d \n", data->brightness); } void set_light_ab_camera_hysteresis(struct ssp_data *data) { int ret = 0; int buf[4]; if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_LIGHT_AUTOBRIGHTNESS))) { ssp_infof("Skip this function!!!,"\ "light sensor is not connected(0x%llx)\n", data->sensor_probe_state); return; } memcpy(buf, data->camera_lux_hysteresis, sizeof(data->camera_lux_hysteresis)); memcpy(&buf[2], data->camera_br_hysteresis, sizeof(data->camera_br_hysteresis)); ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_LIGHT_AUTOBRIGHTNESS, LIGHT_AB_HYSTERESIS, 0, (char *)buf, sizeof(buf), NULL, NULL); if (ret != SUCCESS) { ssp_errf("CMD fail %d\n", ret); return; } ssp_infof("%d %d %d %d\n", buf[0], buf[1], buf[2], buf[3]); } #endif #ifdef CONFIG_SENSORS_SSP_GYROSCOPE #define GYRO_CALIBRATION_FILE_PATH "/efs/FactoryApp/gyro_cal_data" int gyro_open_calibration(struct ssp_data *data) { int ret = 0; #ifdef CONFIG_SENSORS_SSP_GYROFILE_FOR_MAG ssp_infof("gyrofile for mag"); #else mm_segment_t old_fs; struct file *cal_filp = NULL; old_fs = get_fs(); set_fs(KERNEL_DS); cal_filp = filp_open(GYRO_CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW | O_NONBLOCK, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); ret = PTR_ERR(cal_filp); data->gyrocal.x = 0; data->gyrocal.y = 0; data->gyrocal.z = 0; pr_err("[SSP]: %s - Can't open calibration file %d\n", __func__, ret); return ret; } ret = vfs_read(cal_filp, (char *)&data->gyrocal, sizeof(data->gyrocal), &cal_filp->f_pos); if (ret != sizeof(data->gyrocal)) ret = -EIO; filp_close(cal_filp, current->files); set_fs(old_fs); ssp_info("open gyro calibration %d, %d, %d", data->gyrocal.x, data->gyrocal.y, data->gyrocal.z); #endif return ret; } int save_gyro_cal_data(struct ssp_data *data, s16 *cal_data) { int ret = 0; #ifdef CONFIG_SENSORS_SSP_GYROFILE_FOR_MAG ssp_infof("gyrofile for mag"); #else struct file *cal_filp = NULL; mm_segment_t old_fs; data->gyrocal.x = cal_data[0]; data->gyrocal.y = cal_data[1]; data->gyrocal.z = cal_data[2]; ssp_info("do gyro calibrate %d, %d, %d", data->gyrocal.x, data->gyrocal.y, data->gyrocal.z); old_fs = get_fs(); set_fs(KERNEL_DS); cal_filp = filp_open(GYRO_CALIBRATION_FILE_PATH, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_NONBLOCK, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); ret = PTR_ERR(cal_filp); return -EIO; } ret = vfs_write(cal_filp, (char *)&data->gyrocal, sizeof(data->gyrocal), &cal_filp->f_pos); if (ret != sizeof(data->gyrocal)) { pr_err("[SSP]: %s - Can't write gyro cal to file\n", __func__); ret = -EIO; } filp_close(cal_filp, current->files); set_fs(old_fs); #endif return ret; } int set_gyro_cal(struct ssp_data *data) { int ret = 0; #ifdef CONFIG_SENSORS_SSP_GYROFILE_FOR_MAG ssp_infof("gyrofile for mag"); #else s16 gyro_cal[3] = {0, }; if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_GYROSCOPE))) { pr_info("[SSP]: %s - Skip this function!!!"\ ", gyro sensor is not connected(0x%llx)\n", __func__, data->sensor_probe_state); return ret; } gyro_cal[0] = data->gyrocal.x; gyro_cal[1] = data->gyrocal.y; gyro_cal[2] = data->gyrocal.z; ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_GYROSCOPE, CAL_DATA, 0, (char *)gyro_cal, 6 * sizeof(char), NULL, NULL); if (ret != SUCCESS) { ssp_errf("ssp_send_command Fail %d", ret); goto exit; } pr_info("[SSP] Set temp gyro cal data %d, %d, %d\n", gyro_cal[0], gyro_cal[1], gyro_cal[2]); pr_info("[SSP] Set gyro cal data %d, %d, %d\n", data->gyrocal.x, data->gyrocal.y, data->gyrocal.z); exit: #endif return ret; } #endif #ifdef CONFIG_SENSORS_SSP_ACCELOMETER #define ACCEL_CALIBRATION_FILE_PATH "/efs/FactoryApp/calibration_data" int accel_open_calibration(struct ssp_data *data) { int ret = 0; mm_segment_t old_fs; struct file *cal_filp = NULL; old_fs = get_fs(); set_fs(KERNEL_DS); cal_filp = filp_open(ACCEL_CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); ret = PTR_ERR(cal_filp); data->accelcal.x = 0; data->accelcal.y = 0; data->accelcal.z = 0; return ret; } ret = vfs_read(cal_filp, (char *)&data->accelcal, 3 * sizeof(int), &cal_filp->f_pos); if (ret != 3 * sizeof(int)) ret = -EIO; filp_close(cal_filp, current->files); set_fs(old_fs); ssp_infof("open accel calibration %d, %d, %d\n", data->accelcal.x, data->accelcal.y, data->accelcal.z); if ((data->accelcal.x == 0) && (data->accelcal.y == 0) && (data->accelcal.z == 0)) return ERROR; return ret; } int set_accel_cal(struct ssp_data *data) { int ret = 0; s16 accel_cal[3] = {0, }; if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_ACCELEROMETER))) { pr_info("[SSP]: %s - Skip this function!!!"\ ", accel sensor is not connected(0x%llx)\n", __func__, data->sensor_probe_state); return ret; } accel_cal[0] = data->accelcal.x; accel_cal[1] = data->accelcal.y; accel_cal[2] = data->accelcal.z; ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_ACCELEROMETER, CAL_DATA, 0, (char *)accel_cal, 6 * sizeof(char), NULL, NULL); if (ret != SUCCESS) ssp_errf("ssp_send_command Fail %d", ret); pr_info("[SSP] Set accel cal data %d, %d, %d\n", data->accelcal.x, data->accelcal.y, data->accelcal.z); return ret; } #endif #ifdef CONFIG_SENSORS_SSP_BAROMETER #define BARO_CALIBRATION_FILE_PATH "/efs/FactoryApp/baro_delta" int pressure_open_calibration(struct ssp_data *data) { char chBuf[10] = {0,}; int ret = 0; mm_segment_t old_fs; struct file *cal_filp = NULL; old_fs = get_fs(); set_fs(KERNEL_DS); cal_filp = filp_open(BARO_CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { ret = PTR_ERR(cal_filp); if (ret != -ENOENT) pr_err("[SSP]: %s - Can't open calibration file(%d)\n", __func__, ret); set_fs(old_fs); return ret; } ret = vfs_read(cal_filp, chBuf, 10 * sizeof(char), &cal_filp->f_pos); if (ret < 0) { pr_err("[SSP]: %s - Can't read the cal data from file (%d)\n", __func__, ret); filp_close(cal_filp, current->files); set_fs(old_fs); return ret; } filp_close(cal_filp, current->files); set_fs(old_fs); ret = kstrtoint(chBuf, 10, &data->buf[SENSOR_TYPE_PRESSURE].pressure_cal); if (ret < 0) { pr_err("[SSP]: %s - kstrtoint failed. %d", __func__, ret); return ret; } ssp_info("open barometer calibration %d", data->buf[SENSOR_TYPE_PRESSURE].pressure_cal); return ret; } #endif #ifdef CONFIG_SENSORS_SSP_MAGNETIC #ifdef CONFIG_SENSORS_SSP_GYROFILE_FOR_MAG #define MAG_CALIBRATION_FILE_PATH "/efs/FactoryApp/gyro_cal_data" #else #define MAG_CALIBRATION_FILE_PATH "/efs/FactoryApp/mag_cal_data" #endif int set_pdc_matrix(struct ssp_data *data) { int ret = 0; if (!(data->sensor_probe_state & 1ULL << SENSOR_TYPE_GEOMAGNETIC_FIELD)) { pr_info("[SSP] %s - Skip this function!!!"\ ", magnetic sensor is not connected(0x%llx)\n", __func__, data->sensor_probe_state); return ret; } ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_GEOMAGNETIC_FIELD, MAGNETIC_STATIC_MATRIX, 0, &data->pdc_matrix[0], sizeof(data->pdc_matrix), NULL, NULL); if (ret != SUCCESS) { ssp_errf("ssp_send_command Fail %d", ret); goto exit; } pr_info("[SSP] %s: finished\n", __func__); exit: return ret; } #ifdef CONFIG_SENSORS_SSP_MAGNETIC_MMC5603 int mag_open_calibration(struct ssp_data *data) { int ret = 0; mm_segment_t old_fs; struct file *cal_filp = NULL; char buffer[16] = {0,}; old_fs = get_fs(); set_fs(KERNEL_DS); cal_filp = filp_open(MAG_CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW | O_NONBLOCK, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); ret = PTR_ERR(cal_filp); memset(&data->magcal, 0, sizeof(data->magcal)); pr_err("[SSP]: %s - Can't open calibration file %d\n", __func__, ret); return ret; } ret = vfs_read(cal_filp, buffer, sizeof(buffer), &cal_filp->f_pos); if ((ret != sizeof(buffer))) { ret = -EIO; memset(&data->magcal, 0, sizeof(data->magcal)); } memcpy(&data->magcal, buffer, sizeof(buffer)); filp_close(cal_filp, current->files); set_fs(old_fs); ssp_infof("%d, %d, %d, %d", data->magcal.offset_x, data->magcal.offset_y, data->magcal.offset_z, data->magcal.radius); return ret; } int save_mag_cal_data(struct ssp_data *data, u8 *cal_data) { int ret = 0; struct file *cal_filp = NULL; mm_segment_t old_fs; char buffer[16] = {0,}; memcpy(&data->magcal, cal_data, sizeof(buffer)); ssp_infof("%d, %d, %d, %d", data->magcal.offset_x, data->magcal.offset_y, data->magcal.offset_z, data->magcal.radius); memcpy(buffer, cal_data, sizeof(buffer)); old_fs = get_fs(); set_fs(KERNEL_DS); cal_filp = filp_open(MAG_CALIBRATION_FILE_PATH, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_NONBLOCK, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); ret = PTR_ERR(cal_filp); return -EIO; } ret = vfs_write(cal_filp, buffer, sizeof(buffer), &cal_filp->f_pos); if (ret != sizeof(buffer)) { pr_err("[SSP]: %s - Can't write mag cal to file\n", __func__); ret = -EIO; } filp_close(cal_filp, current->files); set_fs(old_fs); return ret; } int set_mag_cal(struct ssp_data *data) { int ret = 0; char buffer[16]; if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_GEOMAGNETIC_FIELD))) { pr_info("[SSP]: %s - Skip this function!!!"\ ", mag sensor is not connected(0x%llx)\n", __func__, data->sensor_probe_state); return ret; } memcpy(buffer, &data->magcal, sizeof(buffer)); ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_GEOMAGNETIC_FIELD, CAL_DATA, 0, (char *)&buffer, sizeof(buffer), NULL, NULL); if (ret != SUCCESS) { ssp_errf("ssp_send_command Fail %d", ret); goto exit; } ssp_infof("%d, %d, %d, %d", data->magcal.offset_x, data->magcal.offset_y, data->magcal.offset_z, data->magcal.radius); exit: return ret; } #else int mag_open_calibration(struct ssp_data *data) { int ret = 0; mm_segment_t old_fs; struct file *cal_filp = NULL; char buffer[14] = {0,}; old_fs = get_fs(); set_fs(KERNEL_DS); cal_filp = filp_open(MAG_CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW | O_NONBLOCK, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); ret = PTR_ERR(cal_filp); memset(&data->magcal, 0, sizeof(data->magcal)); pr_err("[SSP]: %s - Can't open calibration file %d\n", __func__, ret); return ret; } ret = vfs_read(cal_filp, buffer, sizeof(buffer), &cal_filp->f_pos); if ((ret != sizeof(buffer))) { ret = -EIO; memset(&data->magcal, 0, sizeof(data->magcal)); } if (buffer[0] == 'M') { data->magcal.accuracy = buffer[1]; memcpy(&data->magcal.offset_x, (s16 *)&buffer[2], sizeof(s16)); memcpy(&data->magcal.offset_y, (s16 *)&buffer[4], sizeof(s16)); memcpy(&data->magcal.offset_z, (s16 *)&buffer[6], sizeof(s16)); memcpy(&data->magcal.flucv_x, (s16 *)&buffer[8], sizeof(s16)); memcpy(&data->magcal.flucv_y, (s16 *)&buffer[10], sizeof(s16)); memcpy(&data->magcal.flucv_z, (s16 *)&buffer[12], sizeof(s16)); } else memset(&data->magcal, 0, sizeof(data->magcal)); filp_close(cal_filp, current->files); set_fs(old_fs); ssp_infof("%u, %d, %d, %d, %d, %d, %d", data->magcal.accuracy, data->magcal.offset_x, data->magcal.offset_y, data->magcal.offset_z, data->magcal.flucv_x, data->magcal.flucv_y, data->magcal.flucv_z); return ret; } int save_mag_cal_data(struct ssp_data *data, u8 *cal_data) { int ret = 0; struct file *cal_filp = NULL; mm_segment_t old_fs; char buffer[14] = {0,}; data->magcal.accuracy = cal_data[0]; memcpy(&data->magcal.offset_x, (s16 *)&cal_data[1], sizeof(s16)); memcpy(&data->magcal.offset_y, (s16 *)&cal_data[3], sizeof(s16)); memcpy(&data->magcal.offset_z, (s16 *)&cal_data[5], sizeof(s16)); memcpy(&data->magcal.flucv_x, (s16 *)&cal_data[7], sizeof(s16)); memcpy(&data->magcal.flucv_y, (s16 *)&cal_data[9], sizeof(s16)); memcpy(&data->magcal.flucv_z, (s16 *)&cal_data[11], sizeof(s16)); ssp_infof("%u, %d, %d, %d, %d, %d, %d", data->magcal.accuracy, data->magcal.offset_x, data->magcal.offset_y, data->magcal.offset_z, data->magcal.flucv_x, data->magcal.flucv_y, data->magcal.flucv_z); buffer[0] = 'M'; memcpy(&buffer[1], cal_data, 13); old_fs = get_fs(); set_fs(KERNEL_DS); cal_filp = filp_open(MAG_CALIBRATION_FILE_PATH, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_NONBLOCK, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); ret = PTR_ERR(cal_filp); return -EIO; } ret = vfs_write(cal_filp, buffer, sizeof(buffer), &cal_filp->f_pos); if (ret != sizeof(buffer)) { pr_err("[SSP]: %s - Can't write mag cal to file\n", __func__); ret = -EIO; } filp_close(cal_filp, current->files); set_fs(old_fs); return ret; } int set_mag_cal(struct ssp_data *data) { int ret = 0; char buffer[13]; if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_GEOMAGNETIC_FIELD))) { pr_info("[SSP]: %s - Skip this function!!!"\ ", mag sensor is not connected(0x%llx)\n", __func__, data->sensor_probe_state); return ret; } buffer[0] = data->magcal.accuracy; memcpy(&buffer[1], &data->magcal.offset_x, sizeof(s16)); memcpy(&buffer[3], &data->magcal.offset_y, sizeof(s16)); memcpy(&buffer[5], &data->magcal.offset_z, sizeof(s16)); memcpy(&buffer[7], &data->magcal.flucv_x, sizeof(s16)); memcpy(&buffer[9], &data->magcal.flucv_y, sizeof(s16)); memcpy(&buffer[11], &data->magcal.flucv_z, sizeof(s16)); ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_GEOMAGNETIC_FIELD, CAL_DATA, 0, (char *)&buffer, sizeof(buffer), NULL, NULL); if (ret != SUCCESS) { ssp_errf("ssp_send_command Fail %d", ret); goto exit; } ssp_infof("%u, %d, %d, %d, %d, %d, %d", data->magcal.accuracy, data->magcal.offset_x, data->magcal.offset_y, data->magcal.offset_z, data->magcal.flucv_x, data->magcal.flucv_y, data->magcal.flucv_z); exit: return ret; } #endif #endif int get_sensorname(struct ssp_data *data, int sensor_type, char *name, int size) { char *buffer = NULL; int buffer_length = 0; int ret; ret = ssp_send_command(data, CMD_GETVALUE, sensor_type, SENSOR_NAME, 1000, NULL, 0, &buffer, &buffer_length); if (ret != SUCCESS) { ssp_errf("ssp_send_command Fail %d", ret); if (buffer != NULL) kfree(buffer); return FAIL; } if (buffer == NULL) { ssp_errf("buffer is null"); return FAIL; } memcpy(name, buffer, (size > buffer_length) ? buffer_length : size); kfree(buffer); ssp_infof("type %d name %s", sensor_type, name); return SUCCESS; } static void timestamp_sync_work_func(struct work_struct *work) { struct ssp_data *data = container_of(work, struct ssp_data, work_ts_sync); int ret; ret = ssp_send_command(data, CMD_SETVALUE, TYPE_MCU, RTC_TIME, 0, NULL, 0, NULL, NULL); if (ret != SUCCESS) { pr_err("[SSP]: %s - TIMESTAMP_SYNC CMD fail %d\n", __func__, ret); return; } } static void timestamp_sync_timer_func(unsigned long ptr) { struct ssp_data *data = (struct ssp_data *)ptr; queue_work(data->ts_sync_wq, &data->work_ts_sync); mod_timer(&data->ts_sync_timer, round_jiffies_up(jiffies + SSP_TIMESTAMP_SYNC_TIMER_SEC)); } void enable_timestamp_sync_timer(struct ssp_data *data) { mod_timer(&data->ts_sync_timer, round_jiffies_up(jiffies + SSP_TIMESTAMP_SYNC_TIMER_SEC)); } void disable_timestamp_sync_timer(struct ssp_data *data) { del_timer_sync(&data->ts_sync_timer); cancel_work_sync(&data->work_ts_sync); } int initialize_timestamp_sync_timer(struct ssp_data *data) { setup_timer(&data->ts_sync_timer, timestamp_sync_timer_func, (unsigned long)data); data->ts_sync_wq = create_singlethread_workqueue("ssp_ts_sync_wq"); if (!data->ts_sync_wq) return -ENOMEM; INIT_WORK(&data->work_ts_sync, timestamp_sync_work_func); return 0; }