blob: e3c76102f81cb71af4c4da8e88b96873902c9521 [file] [log] [blame]
/*
* 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/wait.h>
#include "ssp_debug.h"
#include "ssp_type_define.h"
#include "ssp_platform.h"
#include "ssp_comm.h"
#include "ssp_dump.h"
#include "ssp_data.h"
#include "ssp_scontext.h"
#include "ssp_cmd_define.h"
/* define */
#define SSP_DEBUG_TIMER_SEC (5 * HZ)
#define LIMIT_TIMEOUT_CNT 1
#define LIMIT_COMFAIL_CNT 3
int ssp_wait_event_timeout(struct ssp_waitevent *lock, int timeout)
{
int ret;
ret = wait_event_interruptible_timeout(lock->waitqueue, atomic_read(&lock->state), msecs_to_jiffies(timeout));
if(ret == 0)
return FAIL;
else
return SUCCESS;
}
void ssp_lock_wait_event(struct ssp_waitevent *lock)
{
atomic_set(&lock->state, 0);
}
void ssp_wake_up_wait_event(struct ssp_waitevent *lock)
{
atomic_set(&lock->state, 1);
wake_up_interruptible_sync(&lock->waitqueue);
}
void reset_mcu(struct ssp_data *data, int reason)
{
if(work_busy(&data->work_reset)) {
ssp_infof("reset work state : pending or running");
return;
}
ssp_infof("- reason(%u) pending(%u)", reason, !list_empty(&data->pending_list));
data->reset_type = reason;
data->cnt_ssp_reset[RESET_TYPE_MAX]++;
if(data->reset_type < RESET_TYPE_MAX)
data->cnt_ssp_reset[data->reset_type]++;
ssp_lock_wait_event(&data->reset_lock);
queue_work(data->debug_wq, &data->work_reset);
return;
}
void reset_task(struct work_struct *work)
{
struct ssp_data *data = container_of((struct work_struct *)work,
struct ssp_data, work_reset);
int ret;
ssp_infof("");
disable_timestamp_sync_timer(data);
ret = sensorhub_reset(data);
if(ret < 0) {
ssp_errf("reset failed");
ssp_wake_up_wait_event(&data->reset_lock);
}
}
static void check_no_event(struct ssp_data *data)
{
u64 timestamp = get_current_timestamp();
int check_sensors[] = {SENSOR_TYPE_ACCELEROMETER, SENSOR_TYPE_GEOMAGNETIC_FIELD,
SENSOR_TYPE_GYROSCOPE, SENSOR_TYPE_PRESSURE, SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
SENSOR_TYPE_GAME_ROTATION_VECTOR, SENSOR_TYPE_GYROSCOPE_UNCALIBRATED};
int len = sizeof(check_sensors) / sizeof(check_sensors[0]);
int i, sensor, ret;
char buffer[9] = {0,};
bool check_reset = false;
if(data->check_noevent_reset_cnt >= 0 && data->check_noevent_reset_cnt == data->cnt_reset)
check_reset = true;
data->check_noevent_reset_cnt = -1;
for (i = 0 ; i < len ; i++) {
sensor = check_sensors[i];
/* The sensor is registered
And none batching mode
And there is no sensor event over 5sec */
if (data->en_info[sensor].enabled
&& data->delay[sensor].max_report_latency == 0
&& data->latest_timestamp[sensor] + 5000000000ULL < timestamp) {
if(check_reset) {
data->check_noevent_reset_cnt = -1;
reset_mcu(data, RESET_TYPE_KERNEL_NO_EVENT);
break;
}
data->check_noevent_reset_cnt = data->cnt_reset;
ssp_infof("sensor(%d) last = %lld, cur = %lld", sensor, data->latest_timestamp[sensor], timestamp);
buffer[0] = sensor;
memcpy(&buffer[1], &(data->delay[sensor]), sizeof(data->delay[sensor]));
ret = ssp_send_command(data, CMD_SETVALUE, TYPE_MCU, NO_EVENT_CHECK, 0, buffer, sizeof(buffer), NULL, NULL);
if(ret < 0)
ssp_errf("type %d no event comm failed ret %d", sensor, ret);
}
}
}
static void print_sensordata(struct ssp_data *data, unsigned int sensor_type)
{
if(sensor_type < SENSOR_TYPE_MAX)
{
switch (sensor_type) {
case SENSOR_TYPE_ACCELEROMETER:
case SENSOR_TYPE_GYROSCOPE:
case SENSOR_TYPE_INTERRUPT_GYRO:
ssp_info("%s(%u) : %d, %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].x, data->buf[sensor_type].y,
data->buf[sensor_type].z,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
case SENSOR_TYPE_GEOMAGNETIC_FIELD:
ssp_info("%s(%u) : %d, %d, %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].cal_x, data->buf[sensor_type].cal_y,
data->buf[sensor_type].cal_z, data->buf[sensor_type].accuracy,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
ssp_info("%s(%u) : %d, %d, %d, %d, %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].uncal_x,
data->buf[sensor_type].uncal_y,
data->buf[sensor_type].uncal_z,
data->buf[sensor_type].offset_x,
data->buf[sensor_type].offset_y,
data->buf[sensor_type].offset_z,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
case SENSOR_TYPE_PRESSURE:
ssp_info("%s(%u) : %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].pressure,
data->buf[sensor_type].temperature,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
case SENSOR_TYPE_LIGHT:
ssp_info("%s(%u) : %u, %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].lux,
data->buf[sensor_type].cct,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
case SENSOR_TYPE_LIGHT_CCT:
ssp_info("%s(%u) : %u, %u, %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].lux,
data->buf[sensor_type].cct,
data->buf[sensor_type].raw_lux,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
case SENSOR_TYPE_PROXIMITY:
ssp_info("%s(%u) : %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].prox, data->buf[sensor_type].prox_ex,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
case SENSOR_TYPE_STEP_DETECTOR:
ssp_info("%s(%u) : %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].step_det,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
case SENSOR_TYPE_GAME_ROTATION_VECTOR:
case SENSOR_TYPE_ROTATION_VECTOR:
ssp_info("%s(%u) : %d, %d, %d, %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].quat_a, data->buf[sensor_type].quat_b,
data->buf[sensor_type].quat_c, data->buf[sensor_type].quat_d,
data->buf[sensor_type].acc_rot,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
case SENSOR_TYPE_SIGNIFICANT_MOTION:
ssp_info("%s(%u) : %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].sig_motion,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
case SENSOR_TYPE_STEP_COUNTER:
ssp_info("%s(%u) : %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].step_diff,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
case SENSOR_TYPE_LIGHT_AUTOBRIGHTNESS:
ssp_info("%s(%u) : %u, %u, %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->buf[sensor_type].ab_lux,
data->buf[sensor_type].ab_min_flag,
data->buf[sensor_type].ab_brightness,
data->buf[sensor_type].timestamp,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
default:
ssp_info("%s(%u) : (%ums, %dms)", data->info[sensor_type].name, sensor_type,
data->delay[sensor_type].sampling_period,
data->delay[sensor_type].max_report_latency);
break;
}
}
else
{
char name[SENSOR_NAME_MAX_LEN] = "";
get_ss_sensor_name(data, sensor_type, name, SENSOR_NAME_MAX_LEN);
ssp_info("%s(%u)", name, sensor_type);
}
}
static void debug_work_func(struct work_struct *work)
{
struct ssp_data *data = container_of(work, struct ssp_data, work_debug);
unsigned int type;
ssp_infof("FW(%d):%u, Sensor state: 0x%llx, En: 0x%llx, Reset cnt: %d[%d : C %u(%u, %u), N %u, %u]",
data->fw_type, data->curr_fw_rev,
data->sensor_probe_state, data->sensor_en_state,
data->cnt_reset, data->cnt_ssp_reset[RESET_TYPE_MAX],
data->cnt_ssp_reset[RESET_TYPE_KERNEL_COM_FAIL], data->cnt_com_fail, data->cnt_timeout,
data->cnt_ssp_reset[RESET_TYPE_KERNEL_NO_EVENT], data->cnt_ssp_reset[RESET_TYPE_HUB_NO_EVENT]);
for (type = 0; type < SS_SENSOR_TYPE_MAX; type++)
if(data->en_info[type].enabled) {
print_sensordata(data, type);
}
if(is_sensorhub_working(data))
check_no_event(data);
}
static void debug_timer_func(unsigned long ptr)
{
struct ssp_data *data = (struct ssp_data *)ptr;
queue_work(data->debug_wq, &data->work_debug);
mod_timer(&data->debug_timer,
round_jiffies_up(jiffies + SSP_DEBUG_TIMER_SEC));
}
void enable_debug_timer(struct ssp_data *data)
{
mod_timer(&data->debug_timer,
round_jiffies_up(jiffies + SSP_DEBUG_TIMER_SEC));
}
void disable_debug_timer(struct ssp_data *data)
{
del_timer_sync(&data->debug_timer);
cancel_work_sync(&data->work_debug);
}
int initialize_debug_timer(struct ssp_data *data)
{
setup_timer(&data->debug_timer, debug_timer_func, (unsigned long)data);
data->debug_wq = create_singlethread_workqueue("ssp_debug_wq");
if (!data->debug_wq) {
return -ENOMEM;
}
INIT_WORK(&data->work_debug, debug_work_func);
return 0;
}
int print_mcu_debug(char *dataframe, int *index, int dataframe_length)
{
u16 length = 0;
int cur = *index;
memcpy(&length, dataframe + *index, 1);
*index += 1;
if (length > dataframe_length - *index || length <= 0) {
ssp_infof("[M] invalid debug length(%u/%d/%d)",
length, dataframe_length, cur);
return length ? length : -1;
}
ssp_info("[M] %s", &dataframe[*index]);
*index += length;
return 0;
}
#define SSP_LOG_MAX_BYTE 200
void print_dataframe(struct ssp_data *data, char *dataframe, int frame_len)
{
char raw_data[SSP_LOG_MAX_BYTE*4];
int i = 0, cur = 0;
while ((frame_len - cur) > 0) {
int size = 0;
int pr_size = ((frame_len - cur) > SSP_LOG_MAX_BYTE) ? SSP_LOG_MAX_BYTE : (frame_len - cur);
memset(raw_data, 0, sizeof(raw_data));
for (i = 0; i < pr_size; i++)
size += snprintf(raw_data + size, PAGE_SIZE, "%d ", *(dataframe + cur++));
ssp_info("%s", raw_data);
}
}