| /* |
| * 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 <linux/kernel.h> |
| #include <linux/io.h> |
| #include <linux/slab.h> |
| #include <linux/uaccess.h> |
| #include <linux/delay.h> |
| |
| #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; |
| } |
| |
| |
| #define ORIENTATION_CMD_MODE 128 |
| int set_device_orientation_mode(struct ssp_data *data) |
| { |
| int ret = 0; |
| |
| if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_DEVICE_ORIENTATION))) { |
| ssp_infof("sensor is not connected(0x%llx)", data->sensor_probe_state); |
| return ret; |
| } |
| |
| ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_DEVICE_ORIENTATION, ORIENTATION_CMD_MODE, 0, |
| &data->orientation_mode, sizeof(data->orientation_mode), NULL, NULL); |
| if (ret < 0) { |
| ssp_errf("CMD fail %d", ret); |
| return ret; |
| } |
| |
| ssp_infof("%d", data->orientation_mode); |
| |
| return ret; |
| } |
| |
| #define SBM_RESET_CMD 128 |
| int set_sar_backoff_motion_reset_value(struct ssp_data *data, int32_t value) |
| { |
| int ret = 0; |
| |
| if (!(data->sensor_probe_state & (1ULL << SENSOR_TYPE_SAR_BACKOFF_MOTION))) { |
| ssp_infof("Skip this function!!! sbm is not connected(0x%llx)", data->sensor_probe_state); |
| return ret; |
| } |
| |
| ret = ssp_send_command(data, CMD_SETVALUE, SENSOR_TYPE_SAR_BACKOFF_MOTION, SBM_RESET_CMD, 0, |
| (char *)&value, sizeof(value), NULL, NULL); |
| |
| if (ret != SUCCESS) { |
| ssp_errf("ssp_send_command Fail %d", ret); |
| return ret; |
| } |
| |
| ssp_infof("%d", value); |
| |
| 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; |
| } |
| |
| |