blob: df39648898b0f10b2267ffc0b6de954220bc0928 [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_sysfs.h"
struct batch_config {
int64_t timeout;
int64_t delay;
int flag;
};
/*************************************************************************/
/* SSP data delay function */
/*************************************************************************/
int get_msdelay(int64_t delay)
{
/*
* From Android 5.0, There is MaxDelay Concept.
* If App request lower frequency then MaxDelay,
* Sensor have to work with MaxDelay.
*/
if (delay > 200000000)
delay = 200000000;
return div_s64(delay, NSEC_PER_MSEC);
}
static void enable_sensor(struct ssp_data *data,
int type, int64_t delay)
{
u8 uBuf[9];
u64 new_enable = 0;
s32 batch_latency = 0;
s8 batch_options = 0;
int64_t temp_delay = data->delay[type];
s32 ms_delay = get_msdelay(delay);
int ret = 0;
data->delay[type] = delay;
batch_latency = data->batch_max_latency[type];
batch_options = data->batch_opt[type];
switch (data->aiCheckStatus[type]) {
case ADD_SENSOR_STATE:
/*ssp_infof("add %u, New = %lldns", 1 << type, delay);*/
ssp_infof("ADD %s , type %d DELAY %lld ns", data->info[type].name, type, delay);
if (type == SENSOR_TYPE_PROXIMITY) {
set_proximity_threshold(data);
ssp_infof("send threshold hi %d, low %d \n", data->uProxHiThresh, data->uProxLoThresh);
}
else if(type == SENSOR_TYPE_LIGHT) {
data->light_log_cnt = 0;
}
memcpy(&uBuf[0], &ms_delay, 4);
memcpy(&uBuf[4], &batch_latency, 4);
uBuf[8] = batch_options;
ret = send_instruction(data, ADD_SENSOR,
type, uBuf, 9);
ssp_infof("delay %d, timeout %d, flag=%d, ret%d",
ms_delay, batch_latency, uBuf[8], ret);
if (ret <= 0) {
new_enable =
(uint64_t)atomic64_read(&data->aSensorEnable)
& (~(uint64_t)(1 << type));
atomic64_set(&data->aSensorEnable, new_enable);
data->aiCheckStatus[type] = NO_SENSOR_STATE;
break;
}
data->aiCheckStatus[type] = RUNNING_SENSOR_STATE;
break;
case RUNNING_SENSOR_STATE:
#if 0 /* Declaration problem. */
change_sensor_delay(data, type, delay);
#else
if (get_msdelay(temp_delay)
== get_msdelay(data->delay[type]))
break;
ssp_infof("Change %u, New = %lldns",
1 << type, delay);
memcpy(&uBuf[0], &ms_delay, 4);
memcpy(&uBuf[4], &batch_latency, 4);
uBuf[8] = batch_options;
send_instruction(data, CHANGE_DELAY, type, uBuf, 9);
#endif
break;
default:
data->aiCheckStatus[type] = ADD_SENSOR_STATE;
}
}
static void change_sensor_delay(struct ssp_data *data,
int type, int64_t delay)
{
u8 uBuf[9];
s32 batch_latency = 0;
s8 batch_options = 0;
int64_t temp_delay = data->delay[type];
s32 ms_delay = get_msdelay(delay);
u64 timestamp = 0;
data->delay[type] = delay;
data->batch_max_latency[type] = batch_latency;
data->batch_opt[type] = batch_options;
switch (data->aiCheckStatus[type]) {
case RUNNING_SENSOR_STATE:
if (get_msdelay(temp_delay)
== get_msdelay(data->delay[type]))
break;
ssp_infof("Change %u, New = %lldns",
1 << type, delay);
memcpy(&uBuf[0], &ms_delay, 4);
memcpy(&uBuf[4], &batch_latency, 4);
uBuf[8] = batch_options;
send_instruction(data, CHANGE_DELAY, type, uBuf, 9);
timestamp = get_current_timestamp();
//pr_info("[SSP] compare c %lld l %lld\n", timestamp, data->latest_timestamp[sensor]);
if(data->latest_timestamp[type] < timestamp)
data->latest_timestamp[type] = timestamp;
break;
default:
break;
}
}
/*************************************************************************/
/* SSP data enable function */
/*************************************************************************/
static int ssp_remove_sensor(struct ssp_data *data,
unsigned int type, uint64_t new_enable)
{
u8 uBuf[4];
int64_t delay = data->delay[type];
ssp_infof("remove sensor = %d, current state = %lld",
(1 << type), new_enable);
data->delay[type] = DEFUALT_POLLING_DELAY;
data->batch_max_latency[type] = 0;
data->batch_opt[type] = 0;
if (type == SENSOR_TYPE_ORIENTATION) {
if (!(atomic64_read(&data->aSensorEnable)
& (1 << SENSOR_TYPE_ACCELEROMETER))) {
type = SENSOR_TYPE_ACCELEROMETER;
} else {
change_sensor_delay(data, SENSOR_TYPE_ACCELEROMETER,
data->delay[SENSOR_TYPE_ACCELEROMETER]);
return 0;
}
} else if (type == SENSOR_TYPE_ACCELEROMETER) {
if (atomic64_read(&data->aSensorEnable)
& (1 << SENSOR_TYPE_ORIENTATION)) {
change_sensor_delay(data, SENSOR_TYPE_ORIENTATION,
data->delay[SENSOR_TYPE_ORIENTATION]);
return 0;
}
}
if (!data->is_ssp_shutdown)
if (atomic64_read(&data->aSensorEnable) & (1 << type)) {
s32 ms_delay = get_msdelay(delay);
memcpy(&uBuf[0], &ms_delay, 4);
send_instruction(data, REMOVE_SENSOR,
type, uBuf, 4);
}
data->aiCheckStatus[type] = NO_SENSOR_STATE;
return 0;
}
/*************************************************************************/
/* ssp Sysfs */
/*************************************************************************/
static ssize_t show_enable_irq(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ssp_data *data = dev_get_drvdata(dev);
ssp_infof("%d", !data->is_ssp_shutdown);
return snprintf(buf, PAGE_SIZE, "%d\n", !data->is_ssp_shutdown);
}
static ssize_t set_enable_irq(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
u8 dTemp;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtou8(buf, 10, &dTemp) < 0)
return -EINVAL;
ssp_infof("%d start", dTemp);
if (dTemp) {
data->is_reset_from_sysfs = true;
reset_mcu(data);
enable_debug_timer(data);
} else if (!dTemp) {
disable_debug_timer(data);
ssp_enable(data, 0);
} else
ssp_errf("invalid value");
ssp_infof("%d end", dTemp);
return size;
}
static ssize_t show_sensors_enable(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ssp_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE,
"%llu\n", (uint64_t)atomic64_read(&data->aSensorEnable));
}
static ssize_t set_sensors_enable(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t dTemp;
int ret;
uint64_t new_enable = 0, type = 0;
struct ssp_data *data = dev_get_drvdata(dev);
mutex_lock(&data->enable_mutex);
if (kstrtoll(buf, 10, &dTemp) < 0) {
mutex_unlock(&data->enable_mutex);
return -EINVAL;
}
new_enable = (uint64_t)dTemp;
ssp_infof("new_enable = %llu, old_enable = %llu",
new_enable, (uint64_t)atomic64_read(&data->aSensorEnable));
if ((new_enable != atomic64_read(&data->aSensorEnable)) &&
!(data->uSensorState
& (new_enable - atomic64_read(&data->aSensorEnable)))) {
ssp_infof("%llu is not connected(sensor state: 0x%llx)",
new_enable - atomic64_read(&data->aSensorEnable),
data->uSensorState);
mutex_unlock(&data->enable_mutex);
return -EINVAL;
}
if (new_enable == atomic64_read(&data->aSensorEnable)) {
mutex_unlock(&data->enable_mutex);
return size;
}
for (type = 0; type < SENSOR_TYPE_MAX; type++) {
if ((atomic64_read(&data->aSensorEnable) & (1 << type))
!= (new_enable & (1 << type))) {
if (!(new_enable & (1 << type))) {
data->is_data_reported[type] = false;
ssp_remove_sensor(data, type,
new_enable); /* disable */
} else { /* Change to ADD_SENSOR_STATE from KitKat */
if (data->aiCheckStatus[type]
== INITIALIZATION_STATE) {
if (type == SENSOR_TYPE_ACCELEROMETER) {
accel_open_calibration(data);
ret = set_accel_cal(data);
if (ret < 0)
ssp_errf("set_accel_cal failed %d", ret);
} else if (type == SENSOR_TYPE_PRESSURE) {
pressure_open_calibration(data);
} else if (type == SENSOR_TYPE_PROXIMITY) {
set_proximity_threshold(data);
}
}
data->aiCheckStatus[type] = ADD_SENSOR_STATE;
enable_sensor(data, type, data->delay[type]);
}
break;
}
}
atomic64_set(&data->aSensorEnable, new_enable);
mutex_unlock(&data->enable_mutex);
return size;
}
static ssize_t set_flush(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t dTemp;
u8 sensor_type = 0;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &dTemp) < 0)
return -EINVAL;
sensor_type = (u8)dTemp;
if (!(atomic64_read(&data->aSensorEnable) & (1 << sensor_type)))
return -EINVAL;
if (flush(data, sensor_type) < 0) {
ssp_err("ssp returns error for flush(%x)", sensor_type);
return -EINVAL;
}
return size;
}
static ssize_t show_sensor_delay(struct device *dev, char *buf, int type)
{
struct ssp_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%lld\n", data->delay[type]);
}
static ssize_t show_acc_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_ACCELEROMETER);
}
static ssize_t set_acc_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
if ((atomic64_read(&data->aSensorEnable) & (1 << SENSOR_TYPE_ORIENTATION)) &&
(data->delay[SENSOR_TYPE_ORIENTATION] < delay))
data->delay[SENSOR_TYPE_ACCELEROMETER] = delay;
else
change_sensor_delay(data, SENSOR_TYPE_ACCELEROMETER, delay);
return size;
}
static ssize_t show_gyro_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_GYROSCOPE);
}
static ssize_t set_gyro_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_GYROSCOPE, delay);
return size;
}
static ssize_t show_mag_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_GEOMAGNETIC_FIELD);
}
static ssize_t set_mag_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_GEOMAGNETIC_FIELD, delay);
return size;
}
static ssize_t show_uncal_mag_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED);
}
static ssize_t set_uncal_mag_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED, delay);
return size;
}
static ssize_t show_rot_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_ROTATION_VECTOR);
}
static ssize_t set_rot_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_ROTATION_VECTOR, delay);
return size;
}
static ssize_t show_game_rot_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_GAME_ROTATION_VECTOR);
}
static ssize_t set_game_rot_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_GAME_ROTATION_VECTOR, delay);
return size;
}
static ssize_t show_step_det_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_STEP_DETECTOR);
}
static ssize_t set_step_det_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_STEP_DETECTOR, delay);
return size;
}
static ssize_t show_sig_motion_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_SIGNIFICANT_MOTION);
}
static ssize_t set_sig_motion_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_SIGNIFICANT_MOTION, delay);
return size;
}
static ssize_t show_step_cnt_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_STEP_COUNTER);
}
static ssize_t set_step_cnt_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_STEP_COUNTER, delay);
return size;
}
static ssize_t show_uncalib_gyro_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_GYROSCOPE_UNCALIBRATED);
}
static ssize_t set_uncalib_gyro_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_GYROSCOPE_UNCALIBRATED, delay);
return size;
}
static ssize_t show_pressure_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_PRESSURE);
}
static ssize_t set_pressure_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_PRESSURE, delay);
return size;
}
static ssize_t show_light_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_LIGHT);
}
static ssize_t set_light_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_LIGHT, delay);
return size;
}
static ssize_t show_prox_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_PROXIMITY);
}
static ssize_t set_prox_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_PROXIMITY, delay);
return size;
}
static ssize_t show_tilt_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_TILT_DETECTOR);
}
static ssize_t set_tilt_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_TILT_DETECTOR, delay);
return size;
}
static ssize_t show_pickup_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_sensor_delay(dev, buf, SENSOR_TYPE_PICK_UP_GESTURE);
}
static ssize_t set_pickup_delay(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int64_t delay;
struct ssp_data *data = dev_get_drvdata(dev);
if (kstrtoll(buf, 10, &delay) < 0)
return -EINVAL;
change_sensor_delay(data, SENSOR_TYPE_PICK_UP_GESTURE, delay);
return size;
}
static ssize_t show_debug_enable(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ssp_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", data->debug_enable);
}
static ssize_t set_debug_enable(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct ssp_data *data = dev_get_drvdata(dev);
int64_t debug_enable;
if (kstrtoll(buf, 10, &debug_enable) < 0)
return -EINVAL;
if (debug_enable != 1 && debug_enable != 0)
return -EINVAL;
data->debug_enable = (bool)debug_enable;
return size;
}
static ssize_t show_sensor_axis(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ssp_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%d: %d\n%d: %d\n",
SENSOR_TYPE_ACCELEROMETER, data->accel_position,
SENSOR_TYPE_GEOMAGNETIC_FIELD, data->mag_position);
}
static ssize_t set_sensor_axis(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct ssp_data *data = dev_get_drvdata(dev);
int sensor = 0;
int position = 0;
int ret = 0;
sscanf(buf, "%9d,%9d", &sensor, &position);
if (position < 0 || position > 7)
return -EINVAL;
if (sensor == SENSOR_TYPE_ACCELEROMETER)
data->accel_position = position;
else if (sensor == SENSOR_TYPE_GEOMAGNETIC_FIELD)
data->mag_position = position;
else
return -EINVAL;
ret = set_sensor_position(data);
if (ret < 0) {
ssp_errf("set_sensor_position failed");
return -EIO;
}
return size;
}
static ssize_t show_sensor_dot(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ssp_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", data->accel_dot);
}
static ssize_t set_sensor_dot(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct ssp_data *data = dev_get_drvdata(dev);
int64_t new_dot = 0;
int old_dot = data->accel_dot;
int ret = 0;
if (kstrtoll(buf, 10, &new_dot) < 0)
return -EINVAL;
if (new_dot < 0 || new_dot > 7)
return -EINVAL;
data->accel_dot = (int)new_dot;
ret = set_6axis_dot(data);
if (ret < 0) {
data->accel_dot = old_dot;
ssp_errf("set_6axis_dot failed");
return -EIO;
}
return size;
}
static ssize_t set_send_instruction(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct ssp_data *data = dev_get_drvdata(dev);
int instruction[4] = { 0, };
int ret = 0;
sscanf(buf, "%9d,%9d,%9d,%9d",
&instruction[0], &instruction[1],
&instruction[2], &instruction[3]);
ret = send_instruction(data,
(unsigned char)instruction[0],
(unsigned char)instruction[1],
(unsigned char *)&instruction[2], 2);
if (ret < 0) {
ssp_errf("send_instruction failed");
return -EIO;
}
return size;
}
static ssize_t show_sensor_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ssp_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", data->sensor_state);
}
static DEVICE_ATTR(mcu_rev, S_IRUGO, mcu_revision_show, NULL);
static DEVICE_ATTR(mcu_name, S_IRUGO, mcu_model_name_show, NULL);
static DEVICE_ATTR(mcu_update, S_IRUGO, mcu_update_kernel_bin_show, NULL);
static DEVICE_ATTR(mcu_update2, S_IRUGO,
mcu_update_kernel_crashed_bin_show, NULL);
static DEVICE_ATTR(mcu_update_ums, S_IRUGO, mcu_update_ums_bin_show, NULL);
static DEVICE_ATTR(mcu_reset, S_IRUGO, mcu_reset_show, NULL);
static DEVICE_ATTR(mcu_dump, S_IRUGO, mcu_dump_show, NULL);
static DEVICE_ATTR(mcu_test, S_IRUGO | S_IWUSR | S_IWGRP,
mcu_factorytest_show, mcu_factorytest_store);
static DEVICE_ATTR(mcu_sleep_test, S_IRUGO | S_IWUSR | S_IWGRP,
mcu_sleep_factorytest_show, mcu_sleep_factorytest_store);
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP,
show_sensors_enable, set_sensors_enable);
static DEVICE_ATTR(enable_irq, S_IRUGO | S_IWUSR | S_IWGRP,
show_enable_irq, set_enable_irq);
static DEVICE_ATTR(accel_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_acc_delay, set_acc_delay);
static DEVICE_ATTR(gyro_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_gyro_delay, set_gyro_delay);
static DEVICE_ATTR(uncal_mag_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_uncal_mag_delay, set_uncal_mag_delay);
static DEVICE_ATTR(mag_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_mag_delay, set_mag_delay);
static DEVICE_ATTR(pressure_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_pressure_delay, set_pressure_delay);
static DEVICE_ATTR(prox_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_prox_delay, set_prox_delay);
static DEVICE_ATTR(light_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_light_delay, set_light_delay);
static DEVICE_ATTR(step_det_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_step_det_delay, set_step_det_delay);
static DEVICE_ATTR(sig_motion_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_sig_motion_delay, set_sig_motion_delay);
static DEVICE_ATTR(uncal_gyro_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_uncalib_gyro_delay, set_uncalib_gyro_delay);
static DEVICE_ATTR(game_rot_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_game_rot_delay, set_game_rot_delay);
static DEVICE_ATTR(rot_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_rot_delay, set_rot_delay);
static DEVICE_ATTR(step_cnt_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_step_cnt_delay, set_step_cnt_delay);
static DEVICE_ATTR(tilt_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_tilt_delay, set_tilt_delay);
static DEVICE_ATTR(pickup_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
show_pickup_delay, set_pickup_delay);
static DEVICE_ATTR(ssp_flush, S_IWUSR | S_IWGRP,
NULL, set_flush);
static DEVICE_ATTR(debug_enable, S_IRUGO | S_IWUSR | S_IWGRP,
show_debug_enable, set_debug_enable);
static DEVICE_ATTR(sensor_axis, S_IRUGO | S_IWUSR | S_IWGRP,
show_sensor_axis, set_sensor_axis);
static DEVICE_ATTR(sensor_dot, S_IRUGO | S_IWUSR | S_IWGRP,
show_sensor_dot, set_sensor_dot);
static DEVICE_ATTR(send_instruction, S_IWUSR | S_IWGRP,
NULL, set_send_instruction);
static DEVICE_ATTR(sensor_state, S_IRUGO, show_sensor_state, NULL);
static struct device_attribute *mcu_attrs[] = {
&dev_attr_enable,
&dev_attr_mcu_rev,
&dev_attr_mcu_name,
&dev_attr_mcu_test,
&dev_attr_mcu_reset,
&dev_attr_mcu_dump,
&dev_attr_mcu_update,
&dev_attr_mcu_update2,
&dev_attr_mcu_update_ums,
&dev_attr_mcu_sleep_test,
&dev_attr_enable_irq,
&dev_attr_accel_poll_delay,
&dev_attr_gyro_poll_delay,
&dev_attr_uncal_mag_poll_delay,
&dev_attr_mag_poll_delay,
&dev_attr_pressure_poll_delay,
&dev_attr_prox_poll_delay,
&dev_attr_light_poll_delay,
&dev_attr_step_det_poll_delay,
&dev_attr_sig_motion_poll_delay,
&dev_attr_uncal_gyro_poll_delay,
&dev_attr_game_rot_poll_delay,
&dev_attr_rot_poll_delay,
&dev_attr_step_cnt_poll_delay,
&dev_attr_tilt_poll_delay,
&dev_attr_pickup_poll_delay,
&dev_attr_ssp_flush,
&dev_attr_debug_enable,
&dev_attr_sensor_axis,
&dev_attr_sensor_dot,
&dev_attr_send_instruction,
&dev_attr_sensor_state,
NULL,
};
static long ssp_batch_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct ssp_data *data
= container_of(file->private_data,
struct ssp_data, batch_io_device);
struct batch_config batch;
void __user *argp = (void __user *)arg;
int retries = 2;
int ret = 0;
int sensor_type, ms_delay;
int timeout_ms = 0;
u8 uBuf[9];
sensor_type = (cmd & 0xFF);
ssp_info("cmd = %d, sensor_type = %d", cmd, sensor_type);
if ((cmd >> 8 & 0xFF) != BATCH_IOCTL_MAGIC) {
ssp_err("Invalid BATCH CMD %x", cmd);
return -EINVAL;
}
if(sensor_type >= SENSOR_TYPE_MAX)
{
ssp_err("Invalid sensor_type %d", sensor_type);
return -EINVAL;
}
while (retries--) {
ret = copy_from_user(&batch, argp, sizeof(batch));
if (likely(!ret))
break;
}
if (unlikely(ret)) {
ssp_err("batch ioctl err(%d)", ret);
return -EINVAL;
}
ms_delay = get_msdelay(batch.delay);
timeout_ms = div_s64(batch.timeout, NSEC_PER_MSEC);
memcpy(&uBuf[0], &ms_delay, 4);
memcpy(&uBuf[4], &timeout_ms, 4);
uBuf[8] = batch.flag;
if (batch.timeout) { /* add or dry */
/* real batch, NOT DRY, change delay */
if (!(batch.flag & SENSORS_BATCH_DRY_RUN)) {
ret = 1;
/* if sensor is not running state, enable will be called.
MCU return fail when receive chage delay inst during NO_SENSOR STATE */
if (data->aiCheckStatus[sensor_type]
== RUNNING_SENSOR_STATE)
ret = send_instruction_sync(data, CHANGE_DELAY,
sensor_type, uBuf, 9);
if (ret > 0) { /* ret 1 is success */
data->batch_opt[sensor_type] = (u8)batch.flag;
data->batch_max_latency[sensor_type] = timeout_ms;
data->delay[sensor_type] = batch.delay;
}
} else { /* real batch, DRY RUN */
ret = send_instruction_sync(data, CHANGE_DELAY,
sensor_type, uBuf, 9);
if (ret > 0) { /* ret 1 is success */
data->batch_opt[sensor_type] = (u8)batch.flag;
data->batch_max_latency[sensor_type] = timeout_ms;
data->delay[sensor_type] = batch.delay;
}
}
} else { /* remove batch or normal change delay, remove or add will be called */
/* no batch, NOT DRY, change delay */
if (!(batch.flag & SENSORS_BATCH_DRY_RUN)) {
data->batch_opt[sensor_type] = 0;
data->batch_max_latency[sensor_type] = 0;
data->delay[sensor_type] = batch.delay;
if (data->aiCheckStatus[sensor_type]
== RUNNING_SENSOR_STATE) {
send_instruction(data, CHANGE_DELAY,
sensor_type, uBuf, 9);
}
}
}
ssp_info("batch %d: delay %lld, timeout %lld, flag %d, ret %d",
sensor_type, batch.delay, batch.timeout, batch.flag, ret);
if (!batch.timeout)
return 0;
if (ret <= 0)
return -EINVAL;
else
return 0;
}
static struct file_operations ssp_batch_fops = {
.owner = THIS_MODULE,
.open = nonseekable_open,
.unlocked_ioctl = ssp_batch_ioctl,
};
static void initialize_mcu_factorytest(struct ssp_data *data)
{
sensors_register(data->mcu_device, data, mcu_attrs, "ssp_sensor");
}
static void remove_mcu_factorytest(struct ssp_data *data)
{
sensors_unregister(data->mcu_device, mcu_attrs);
}
int initialize_sysfs(struct ssp_data *data)
{
data->batch_io_device.minor = MISC_DYNAMIC_MINOR;
data->batch_io_device.name = "batch_io";
data->batch_io_device.fops = &ssp_batch_fops;
if (misc_register(&data->batch_io_device))
goto err_batch_io_dev;
initialize_accel_factorytest(data);
initialize_gyro_factorytest(data);
initialize_prox_factorytest(data);
initialize_light_factorytest(data);
initialize_barometer_factorytest(data);
initialize_magnetic_factorytest(data);
initialize_mcu_factorytest(data);
#ifdef CONFIG_SENSORS_SSP_TMD4903
initialize_irled_factorytest(data);
#endif
#ifdef CONFIG_SENSORS_SSP_MOBEAM
initialize_mobeam(data);
#endif
return SUCCESS;
err_batch_io_dev:
ssp_err("error init sysfs");
return ERROR;
}
void remove_sysfs(struct ssp_data *data)
{
ssp_batch_fops.unlocked_ioctl = NULL;
misc_deregister(&data->batch_io_device);
remove_accel_factorytest(data);
remove_gyro_factorytest(data);
remove_prox_factorytest(data);
remove_light_factorytest(data);
remove_barometer_factorytest(data);
remove_magnetic_factorytest(data);
remove_mcu_factorytest(data);
#ifdef CONFIG_SENSORS_SSP_TMD4903
remove_irled_factorytest(data);
#endif
#ifdef CONFIG_SENSORS_SSP_MOBEAM
remove_mobeam(data);
#endif
destroy_sensor_class();
}