1093 lines
27 KiB
C
1093 lines
27 KiB
C
|
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
|
/*
|
||
|
|
* Copyright (c) 2019 MediaTek Inc.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#define pr_fmt(fmt) "<STEP_COUNTER> " fmt
|
||
|
|
|
||
|
|
#include "step_counter.h"
|
||
|
|
|
||
|
|
static struct step_c_context *step_c_context_obj;
|
||
|
|
static struct step_c_init_info *
|
||
|
|
step_counter_init_list[MAX_CHOOSE_STEP_C_NUM] = { 0 };
|
||
|
|
|
||
|
|
static void step_c_work_func(struct work_struct *work)
|
||
|
|
{
|
||
|
|
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
uint32_t counter;
|
||
|
|
uint32_t counter_floor_c;
|
||
|
|
/* hwm_sensor_data sensor_data; */
|
||
|
|
int status;
|
||
|
|
int64_t nt;
|
||
|
|
struct timespec time;
|
||
|
|
int err = 0;
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
|
||
|
|
if (cxt->step_c_data.get_data == NULL)
|
||
|
|
pr_debug("step_c driver not register data path\n");
|
||
|
|
if (cxt->step_c_data.get_data_floor_c == NULL)
|
||
|
|
pr_debug("floor_c driver not register data path\n");
|
||
|
|
|
||
|
|
|
||
|
|
status = 0;
|
||
|
|
counter = 0;
|
||
|
|
time.tv_sec = time.tv_nsec = 0;
|
||
|
|
time = get_monotonic_coarse();
|
||
|
|
nt = time.tv_sec * 1000000000LL + time.tv_nsec;
|
||
|
|
|
||
|
|
/* add wake lock to make sure data can be read before system suspend */
|
||
|
|
if ((cxt->is_active_data == true) &&
|
||
|
|
(cxt->step_c_data.get_data != NULL))
|
||
|
|
err = cxt->step_c_data.get_data(&counter, &status);
|
||
|
|
|
||
|
|
if (err) {
|
||
|
|
pr_err("get step_c data fails!!\n");
|
||
|
|
goto step_c_loop;
|
||
|
|
} else {
|
||
|
|
{
|
||
|
|
cxt->drv_data.counter = counter;
|
||
|
|
cxt->drv_data.status = status;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
status = 0;
|
||
|
|
counter_floor_c = 0;
|
||
|
|
if ((cxt->is_floor_c_active_data == true) &&
|
||
|
|
(cxt->step_c_data.get_data_floor_c != NULL))
|
||
|
|
err = cxt->step_c_data.get_data_floor_c(&counter_floor_c,
|
||
|
|
&status);
|
||
|
|
|
||
|
|
if (err) {
|
||
|
|
pr_err("get floor_c data fails!!\n");
|
||
|
|
goto step_c_loop;
|
||
|
|
} else {
|
||
|
|
{
|
||
|
|
cxt->drv_data.floor_counter = counter_floor_c;
|
||
|
|
cxt->drv_data.floor_c_status = status;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (true == cxt->is_first_data_after_enable) {
|
||
|
|
cxt->is_first_data_after_enable = false;
|
||
|
|
/* filter -1 value */
|
||
|
|
if (cxt->drv_data.counter == STEP_C_INVALID_VALUE) {
|
||
|
|
pr_debug(" read invalid data\n");
|
||
|
|
goto step_c_loop;
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (true == cxt->is_first_floor_c_data_after_enable) {
|
||
|
|
cxt->is_first_floor_c_data_after_enable = false;
|
||
|
|
/* filter -1 value */
|
||
|
|
if (cxt->drv_data.floor_counter == STEP_C_INVALID_VALUE) {
|
||
|
|
pr_debug(" read invalid data\n");
|
||
|
|
goto step_c_loop;
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* report data to input device */
|
||
|
|
/*pr_debug("step_c data[%d]\n", cxt->drv_data.counter);*/
|
||
|
|
|
||
|
|
step_c_data_report(cxt->drv_data.counter, cxt->drv_data.status);
|
||
|
|
floor_c_data_report(cxt->drv_data.floor_counter,
|
||
|
|
cxt->drv_data.floor_c_status);
|
||
|
|
|
||
|
|
step_c_loop:
|
||
|
|
if (true == cxt->is_polling_run) {
|
||
|
|
mod_timer(&cxt->timer,
|
||
|
|
jiffies + atomic_read(&cxt->delay) / (1000 / HZ));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void step_c_poll(struct timer_list *t)
|
||
|
|
{
|
||
|
|
struct step_c_context *obj = from_timer(obj, t, timer);
|
||
|
|
|
||
|
|
if (obj != NULL)
|
||
|
|
schedule_work(&obj->report);
|
||
|
|
}
|
||
|
|
|
||
|
|
static struct step_c_context *step_c_context_alloc_object(void)
|
||
|
|
{
|
||
|
|
struct step_c_context *obj = kzalloc(sizeof(*obj), GFP_KERNEL);
|
||
|
|
|
||
|
|
pr_debug("%s start\n", __func__);
|
||
|
|
if (!obj) {
|
||
|
|
pr_err("Alloc step_c object error!\n");
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
atomic_set(&obj->delay, 2000); /*0.5Hz */
|
||
|
|
atomic_set(&obj->wake, 0);
|
||
|
|
INIT_WORK(&obj->report, step_c_work_func);
|
||
|
|
timer_setup(&obj->timer, step_c_poll, 0);
|
||
|
|
obj->timer.expires = jiffies + atomic_read(&obj->delay) / (1000 / HZ);
|
||
|
|
obj->is_first_data_after_enable = false;
|
||
|
|
obj->is_polling_run = false;
|
||
|
|
mutex_init(&obj->step_c_op_mutex);
|
||
|
|
obj->is_step_c_batch_enable = false; /* for batch mode init */
|
||
|
|
obj->is_step_d_batch_enable = false; /* for batch mode init */
|
||
|
|
|
||
|
|
pr_debug("%s end\n", __func__);
|
||
|
|
return obj;
|
||
|
|
}
|
||
|
|
|
||
|
|
int step_notify_t(enum STEP_NOTIFY_TYPE type, int64_t time_stamp)
|
||
|
|
{
|
||
|
|
int err = 0;
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
struct sensor_event event;
|
||
|
|
|
||
|
|
memset(&event, 0, sizeof(struct sensor_event));
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
event.time_stamp = time_stamp;
|
||
|
|
|
||
|
|
if (type == TYPE_STEP_DETECTOR) {
|
||
|
|
event.flush_action = DATA_ACTION;
|
||
|
|
event.handle = ID_STEP_DETECTOR;
|
||
|
|
event.word[0] = 1;
|
||
|
|
err = sensor_input_event(step_c_context_obj->mdev.minor,
|
||
|
|
&event);
|
||
|
|
|
||
|
|
}
|
||
|
|
if (type == TYPE_SIGNIFICANT) {
|
||
|
|
pr_debug("fwq TYPE_SIGNIFICANT notify\n");
|
||
|
|
/* cxt->step_c_data.get_data_significant(&value); */
|
||
|
|
event.flush_action = DATA_ACTION;
|
||
|
|
event.handle = ID_SIGNIFICANT_MOTION;
|
||
|
|
event.word[0] = 1;
|
||
|
|
err = sensor_input_event(step_c_context_obj->mdev.minor,
|
||
|
|
&event);
|
||
|
|
}
|
||
|
|
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
int step_notify(enum STEP_NOTIFY_TYPE type)
|
||
|
|
{
|
||
|
|
return step_notify_t(type, 0);
|
||
|
|
}
|
||
|
|
static int step_d_real_enable(int enable)
|
||
|
|
{
|
||
|
|
int err = 0;
|
||
|
|
unsigned int i = 0;
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
if (enable == 1) {
|
||
|
|
|
||
|
|
for (i = 0; i < 3; i++) {
|
||
|
|
err = cxt->step_c_ctl.enable_step_detect(1);
|
||
|
|
if (err == 0)
|
||
|
|
break;
|
||
|
|
else if (i == 2) {
|
||
|
|
pr_err("step_d E(%d)err 3 = %d\n",
|
||
|
|
enable, err);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pr_debug("step_d real enable\n");
|
||
|
|
}
|
||
|
|
if (enable == 0) {
|
||
|
|
|
||
|
|
err = cxt->step_c_ctl.enable_step_detect(0);
|
||
|
|
if (err)
|
||
|
|
pr_err("step_d enable(%d) err = %d\n",
|
||
|
|
enable, err);
|
||
|
|
pr_debug("step_d real disable\n");
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int significant_real_enable(int enable)
|
||
|
|
{
|
||
|
|
int err = 0;
|
||
|
|
unsigned int i = 0;
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
if (enable == 1) {
|
||
|
|
|
||
|
|
for (i = 0; i < 3; i++) {
|
||
|
|
err = cxt->step_c_ctl.enable_significant(1);
|
||
|
|
if (err == 0)
|
||
|
|
break;
|
||
|
|
else if (i == 2) {
|
||
|
|
pr_err("significant E(%d)err 3 = %d\n",
|
||
|
|
enable, err);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pr_debug("enable_significant real enable\n");
|
||
|
|
}
|
||
|
|
if (enable == 0) {
|
||
|
|
err = cxt->step_c_ctl.enable_significant(0);
|
||
|
|
if (err)
|
||
|
|
pr_err("enable_significantenable(%d) err = %d\n",
|
||
|
|
enable, err);
|
||
|
|
pr_debug("enable_significant real disable\n");
|
||
|
|
|
||
|
|
}
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
static int step_c_real_enable(int enable)
|
||
|
|
{
|
||
|
|
int err = 0;
|
||
|
|
unsigned int i = 0;
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
if (enable == 1) {
|
||
|
|
if (true == cxt->is_active_data ||
|
||
|
|
true == cxt->is_active_nodata) {
|
||
|
|
|
||
|
|
for (i = 0; i < 3; i++) {
|
||
|
|
err = cxt->step_c_ctl.enable_nodata(1);
|
||
|
|
if (err == 0)
|
||
|
|
break;
|
||
|
|
else if (i == 2) {
|
||
|
|
pr_err("step_c E(%d)err 3 =%d\n",
|
||
|
|
enable, err);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pr_debug("step_c real enable\n");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (enable == 0) {
|
||
|
|
if (false == cxt->is_active_data &&
|
||
|
|
false == cxt->is_active_nodata) {
|
||
|
|
err = cxt->step_c_ctl.enable_nodata(0);
|
||
|
|
if (err)
|
||
|
|
pr_err("step_c enable(%d) err = %d\n",
|
||
|
|
enable, err);
|
||
|
|
pr_debug("step_c real disable\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
static int floor_c_real_enable(int enable)
|
||
|
|
{
|
||
|
|
int err = 0;
|
||
|
|
unsigned int i = 0;
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
if (enable == 1) {
|
||
|
|
for (i = 0; i < 3; i++) {
|
||
|
|
err = cxt->step_c_ctl.enable_floor_c(1);
|
||
|
|
if (err == 0)
|
||
|
|
break;
|
||
|
|
else if (i == 2)
|
||
|
|
pr_err("floor_c enable(%d) err 3 = %d\n",
|
||
|
|
enable, err);
|
||
|
|
}
|
||
|
|
|
||
|
|
pr_debug("floor_c real enable\n");
|
||
|
|
}
|
||
|
|
if (enable == 0) {
|
||
|
|
err = cxt->step_c_ctl.enable_floor_c(0);
|
||
|
|
if (err)
|
||
|
|
pr_err("floor_c enable(%d) err = %d\n",
|
||
|
|
enable, err);
|
||
|
|
pr_debug("floor_c real disable\n");
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static int step_c_enable_data(int enable)
|
||
|
|
{
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
if (cxt->step_c_ctl.open_report_data == NULL) {
|
||
|
|
pr_err("no step_c control path\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (enable == 1) {
|
||
|
|
pr_debug("STEP_C enable data\n");
|
||
|
|
cxt->is_active_data = true;
|
||
|
|
cxt->is_first_data_after_enable = true;
|
||
|
|
cxt->step_c_ctl.open_report_data(1);
|
||
|
|
if (false == cxt->is_polling_run &&
|
||
|
|
cxt->is_step_c_batch_enable == false) {
|
||
|
|
if (false == cxt->step_c_ctl.is_report_input_direct) {
|
||
|
|
mod_timer(&cxt->timer, jiffies +
|
||
|
|
atomic_read(&cxt->delay) / (1000 / HZ));
|
||
|
|
cxt->is_polling_run = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (enable == 0) {
|
||
|
|
pr_debug("STEP_C disable\n");
|
||
|
|
cxt->is_active_data = false;
|
||
|
|
cxt->step_c_ctl.open_report_data(0);
|
||
|
|
if (true == cxt->is_polling_run) {
|
||
|
|
if (false == cxt->step_c_ctl.is_report_input_direct) {
|
||
|
|
cxt->is_polling_run = false;
|
||
|
|
del_timer_sync(&cxt->timer);
|
||
|
|
cancel_work_sync(&cxt->report);
|
||
|
|
cxt->drv_data.counter = STEP_C_INVALID_VALUE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
step_c_real_enable(enable);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
static int floor_c_enable_data(int enable)
|
||
|
|
{
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
|
||
|
|
if (enable == 1) {
|
||
|
|
pr_debug("FLOOR_C enable data\n");
|
||
|
|
cxt->is_floor_c_active_data = true;
|
||
|
|
cxt->is_first_floor_c_data_after_enable = true;
|
||
|
|
floor_c_real_enable(1);
|
||
|
|
if (false == cxt->is_polling_run &&
|
||
|
|
cxt->is_step_c_batch_enable == false) {
|
||
|
|
if (false == cxt->step_c_ctl.is_report_input_direct) {
|
||
|
|
mod_timer(&cxt->timer, jiffies +
|
||
|
|
atomic_read(&cxt->delay) / (1000 / HZ));
|
||
|
|
cxt->is_polling_run = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (enable == 0) {
|
||
|
|
pr_debug("FLOOR_C disable\n");
|
||
|
|
cxt->is_floor_c_active_data = false;
|
||
|
|
floor_c_real_enable(0);
|
||
|
|
if (true == cxt->is_polling_run) {
|
||
|
|
if (false == cxt->step_c_ctl.is_report_input_direct) {
|
||
|
|
cxt->is_polling_run = false;
|
||
|
|
del_timer_sync(&cxt->timer);
|
||
|
|
cancel_work_sync(&cxt->report);
|
||
|
|
cxt->drv_data.floor_counter =
|
||
|
|
STEP_C_INVALID_VALUE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
int step_c_enable_nodata(int enable)
|
||
|
|
{
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
if (cxt->step_c_ctl.enable_nodata == NULL) {
|
||
|
|
pr_err("%s:step_c ctl path is NULL\n", __func__);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (enable == 1)
|
||
|
|
cxt->is_active_nodata = true;
|
||
|
|
|
||
|
|
if (enable == 0)
|
||
|
|
cxt->is_active_nodata = false;
|
||
|
|
step_c_real_enable(enable);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
static ssize_t step_cenablenodata_show(struct device *dev,
|
||
|
|
struct device_attribute *attr, char *buf)
|
||
|
|
{
|
||
|
|
int len = 0;
|
||
|
|
|
||
|
|
pr_debug(" not support now\n");
|
||
|
|
return len;
|
||
|
|
}
|
||
|
|
|
||
|
|
static ssize_t step_cenablenodata_store(struct device *dev,
|
||
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
||
|
|
{
|
||
|
|
int err = 0;
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
|
||
|
|
pr_debug("step_c_store_enable nodata buf=%s\n", buf);
|
||
|
|
mutex_lock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
if (cxt->step_c_ctl.enable_nodata == NULL) {
|
||
|
|
pr_debug("step_c_ctl enable nodata NULL\n");
|
||
|
|
mutex_unlock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
return count;
|
||
|
|
}
|
||
|
|
if (!strncmp(buf, "1", 1))
|
||
|
|
err = step_c_enable_nodata(1);
|
||
|
|
else if (!strncmp(buf, "0", 1))
|
||
|
|
err = step_c_enable_nodata(0);
|
||
|
|
else
|
||
|
|
pr_err(" step_c_store enable nodata cmd error !!\n");
|
||
|
|
mutex_unlock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
static ssize_t step_cactive_store(struct device *dev,
|
||
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
||
|
|
{
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
int res = 0;
|
||
|
|
int handle = 0;
|
||
|
|
int en = 0;
|
||
|
|
|
||
|
|
pr_debug("%s buf=%s\n", __func__, buf);
|
||
|
|
mutex_lock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
if (cxt->step_c_ctl.open_report_data == NULL) {
|
||
|
|
pr_debug("step_c_ctl enable NULL\n");
|
||
|
|
mutex_unlock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
return count;
|
||
|
|
}
|
||
|
|
res = sscanf(buf, "%d,%d", &handle, &en);
|
||
|
|
if (res != 2)
|
||
|
|
pr_debug("%s param error: res = %d\n", __func__, res);
|
||
|
|
pr_debug("%s handle=%d ,en=%d\n", __func__, handle, en);
|
||
|
|
switch (handle) {
|
||
|
|
case ID_STEP_COUNTER:
|
||
|
|
if (en == 1)
|
||
|
|
res = step_c_enable_data(1);
|
||
|
|
else if (en == 0)
|
||
|
|
res = step_c_enable_data(0);
|
||
|
|
else
|
||
|
|
pr_err("%s error !!\n", __func__);
|
||
|
|
break;
|
||
|
|
case ID_STEP_DETECTOR:
|
||
|
|
if (en == 1)
|
||
|
|
res = step_d_real_enable(1);
|
||
|
|
else if (en == 0)
|
||
|
|
res = step_d_real_enable(0);
|
||
|
|
else
|
||
|
|
pr_err(" step_d_real_enable error !!\n");
|
||
|
|
break;
|
||
|
|
case ID_SIGNIFICANT_MOTION:
|
||
|
|
if (en == 1)
|
||
|
|
res = significant_real_enable(1);
|
||
|
|
else if (en == 0)
|
||
|
|
res = significant_real_enable(0);
|
||
|
|
else
|
||
|
|
pr_err(" significant_real_enable error !!\n");
|
||
|
|
break;
|
||
|
|
case ID_FLOOR_COUNTER:
|
||
|
|
if (en == 1)
|
||
|
|
res = floor_c_enable_data(1);
|
||
|
|
else if (en == 0)
|
||
|
|
res = floor_c_enable_data(0);
|
||
|
|
else
|
||
|
|
pr_err(" fc_real_enable error !!\n");
|
||
|
|
break;
|
||
|
|
|
||
|
|
}
|
||
|
|
mutex_unlock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
pr_debug("%s done\n", __func__);
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*----------------------------------------------------------------------------*/
|
||
|
|
static ssize_t step_cactive_show(struct device *dev,
|
||
|
|
struct device_attribute *attr, char *buf)
|
||
|
|
{
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
int div;
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
div = cxt->step_c_data.vender_div;
|
||
|
|
pr_debug("step_c vender_div value: %d\n", div);
|
||
|
|
return snprintf(buf, PAGE_SIZE, "%d\n", div);
|
||
|
|
}
|
||
|
|
|
||
|
|
static ssize_t step_cdelay_store(struct device *dev,
|
||
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
||
|
|
{
|
||
|
|
int delay = 0, err = 0;
|
||
|
|
int mdelay = 0;
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
|
||
|
|
mutex_lock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
if (cxt->step_c_ctl.step_c_set_delay == NULL) {
|
||
|
|
pr_debug("step_c_ctl step_c_set_delay NULL\n");
|
||
|
|
mutex_unlock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (kstrtoint(buf, 10, &delay) != 0) {
|
||
|
|
pr_err("invalid format!!\n");
|
||
|
|
mutex_unlock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (false == cxt->step_c_ctl.is_report_input_direct) {
|
||
|
|
mdelay = (int)delay / 1000 / 1000;
|
||
|
|
atomic_set(&step_c_context_obj->delay, mdelay);
|
||
|
|
}
|
||
|
|
err = cxt->step_c_ctl.step_c_set_delay(delay);
|
||
|
|
pr_debug(" step_c_delay %d ns\n", delay);
|
||
|
|
mutex_unlock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
return err;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
static ssize_t step_cdelay_show(struct device *dev,
|
||
|
|
struct device_attribute *attr, char *buf)
|
||
|
|
{
|
||
|
|
int len = 0;
|
||
|
|
|
||
|
|
pr_debug(" not support now\n");
|
||
|
|
return len;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
static ssize_t step_cbatch_store(struct device *dev,
|
||
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
||
|
|
{
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
int handle = 0, flag = 0, res = 0;
|
||
|
|
int64_t samplingPeriodNs = 0, maxBatchReportLatencyNs = 0;
|
||
|
|
|
||
|
|
res = sscanf(buf, "%d,%d,%lld,%lld",
|
||
|
|
&handle, &flag, &samplingPeriodNs, &maxBatchReportLatencyNs);
|
||
|
|
if (res != 4)
|
||
|
|
pr_err("%s param error: err =%d\n", __func__, res);
|
||
|
|
pr_debug("handle %d, flag:%d PeriodNs:%lld, LatencyNs: %lld\n",
|
||
|
|
handle, flag, samplingPeriodNs, maxBatchReportLatencyNs);
|
||
|
|
mutex_lock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
if (handle == ID_STEP_COUNTER) {
|
||
|
|
if (!cxt->step_c_ctl.is_counter_support_batch)
|
||
|
|
maxBatchReportLatencyNs = 0;
|
||
|
|
if (cxt->step_c_ctl.step_c_batch != NULL)
|
||
|
|
res = cxt->step_c_ctl.step_c_batch(flag,
|
||
|
|
samplingPeriodNs, maxBatchReportLatencyNs);
|
||
|
|
else
|
||
|
|
pr_err("SUPPORT STEP COUNTER COM BATCH\n");
|
||
|
|
if (res < 0)
|
||
|
|
pr_err("step counter enable batch err %d\n",
|
||
|
|
res);
|
||
|
|
} else if (handle == ID_STEP_DETECTOR) {
|
||
|
|
if (!cxt->step_c_ctl.is_detector_support_batch)
|
||
|
|
maxBatchReportLatencyNs = 0;
|
||
|
|
if (cxt->step_c_ctl.step_d_batch != NULL)
|
||
|
|
res = cxt->step_c_ctl.step_d_batch(flag,
|
||
|
|
samplingPeriodNs, maxBatchReportLatencyNs);
|
||
|
|
else
|
||
|
|
pr_err("NOT SUPPORT STEP DETECTOR COM BATCH\n");
|
||
|
|
if (res < 0)
|
||
|
|
pr_err("step detector enable batch err %d\n",
|
||
|
|
res);
|
||
|
|
} else if (handle == ID_SIGNIFICANT_MOTION) {
|
||
|
|
if (!cxt->step_c_ctl.is_smd_support_batch)
|
||
|
|
maxBatchReportLatencyNs = 0;
|
||
|
|
|
||
|
|
if (cxt->step_c_ctl.smd_batch != NULL)
|
||
|
|
res = cxt->step_c_ctl.smd_batch(flag,
|
||
|
|
samplingPeriodNs, maxBatchReportLatencyNs);
|
||
|
|
else
|
||
|
|
pr_err("STEP SMD OLD NOT SUPPORT COM BATCH\n");
|
||
|
|
if (res < 0)
|
||
|
|
pr_err("step smd enable batch err %d\n", res);
|
||
|
|
} else if (handle == ID_FLOOR_COUNTER) {
|
||
|
|
if (!cxt->step_c_ctl.is_floor_c_support_batch)
|
||
|
|
maxBatchReportLatencyNs = 0;
|
||
|
|
|
||
|
|
if (cxt->step_c_ctl.floor_c_batch != NULL)
|
||
|
|
res = cxt->step_c_ctl.floor_c_batch(flag,
|
||
|
|
samplingPeriodNs, maxBatchReportLatencyNs);
|
||
|
|
else
|
||
|
|
pr_err("NOT SUPPORT FLOOR COUNT COM BATCH\n");
|
||
|
|
if (res < 0)
|
||
|
|
pr_err("floor count enable batch err %d\n", res);
|
||
|
|
}
|
||
|
|
mutex_unlock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
pr_debug("%s done: %d\n", __func__, cxt->is_step_c_batch_enable);
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
static ssize_t step_cbatch_show(struct device *dev,
|
||
|
|
struct device_attribute *attr, char *buf)
|
||
|
|
{
|
||
|
|
return snprintf(buf, PAGE_SIZE, "%d\n", 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
static ssize_t step_cflush_store(struct device *dev,
|
||
|
|
struct device_attribute *attr,
|
||
|
|
const char *buf, size_t count)
|
||
|
|
{
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
int handle = 0, err = 0;
|
||
|
|
|
||
|
|
err = kstrtoint(buf, 10, &handle);
|
||
|
|
if (err != 0)
|
||
|
|
pr_err("%s param error: err = %d\n", __func__, err);
|
||
|
|
|
||
|
|
pr_debug("%s param: handle %d\n", __func__, handle);
|
||
|
|
|
||
|
|
mutex_lock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
if (handle == ID_STEP_COUNTER) {
|
||
|
|
if (cxt->step_c_ctl.step_c_flush != NULL)
|
||
|
|
err = cxt->step_c_ctl.step_c_flush();
|
||
|
|
else
|
||
|
|
pr_err("NOT SUPPORT STEP COUNTER COM FLUSH\n");
|
||
|
|
if (err < 0)
|
||
|
|
pr_err("step counter enable flush err %d\n",
|
||
|
|
err);
|
||
|
|
} else if (handle == ID_STEP_DETECTOR) {
|
||
|
|
if (cxt->step_c_ctl.step_d_flush != NULL)
|
||
|
|
err = cxt->step_c_ctl.step_d_flush();
|
||
|
|
else
|
||
|
|
pr_err("NOT SUPPORT STEP DETECTOR COM FLUSH\n");
|
||
|
|
if (err < 0)
|
||
|
|
pr_err("step detector enable flush err %d\n",
|
||
|
|
err);
|
||
|
|
} else if (handle == ID_SIGNIFICANT_MOTION) {
|
||
|
|
if (cxt->step_c_ctl.smd_flush != NULL)
|
||
|
|
err = cxt->step_c_ctl.smd_flush();
|
||
|
|
else
|
||
|
|
pr_err("NOT SUPPORT SMD COMMON VERSION FLUSH\n");
|
||
|
|
if (err < 0)
|
||
|
|
pr_err("smd enable flush err %d\n", err);
|
||
|
|
} else if (handle == ID_FLOOR_COUNTER) {
|
||
|
|
if (cxt->step_c_ctl.floor_c_flush != NULL)
|
||
|
|
err = cxt->step_c_ctl.floor_c_flush();
|
||
|
|
else
|
||
|
|
pr_err("NOT SUPPORT FLOOR COUNTER COM FLUSH\n");
|
||
|
|
if (err < 0)
|
||
|
|
pr_err("floor counter enable flush err %d\n",
|
||
|
|
err);
|
||
|
|
|
||
|
|
}
|
||
|
|
mutex_unlock(&step_c_context_obj->step_c_op_mutex);
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
static ssize_t step_cflush_show(struct device *dev,
|
||
|
|
struct device_attribute *attr, char *buf)
|
||
|
|
{
|
||
|
|
return snprintf(buf, PAGE_SIZE, "%d\n", 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
static ssize_t step_cdevnum_show(struct device *dev,
|
||
|
|
struct device_attribute *attr, char *buf)
|
||
|
|
{
|
||
|
|
return snprintf(buf, PAGE_SIZE, "%d\n", 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int step_counter_remove(struct platform_device *pdev)
|
||
|
|
{
|
||
|
|
pr_debug("%s\n", __func__);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int step_counter_probe(struct platform_device *pdev)
|
||
|
|
{
|
||
|
|
pr_debug("%s\n", __func__);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef CONFIG_OF
|
||
|
|
static const struct of_device_id step_counter_of_match[] = {
|
||
|
|
{.compatible = "mediatek,step_counter",},
|
||
|
|
{},
|
||
|
|
};
|
||
|
|
#endif
|
||
|
|
|
||
|
|
static struct platform_driver step_counter_driver = {
|
||
|
|
.probe = step_counter_probe,
|
||
|
|
.remove = step_counter_remove,
|
||
|
|
.driver = {
|
||
|
|
|
||
|
|
.name = "step_counter",
|
||
|
|
#ifdef CONFIG_OF
|
||
|
|
.of_match_table = step_counter_of_match,
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
static int step_c_real_driver_init(void)
|
||
|
|
{
|
||
|
|
int i = 0;
|
||
|
|
int err = 0;
|
||
|
|
|
||
|
|
pr_debug("%s start\n", __func__);
|
||
|
|
for (i = 0; i < MAX_CHOOSE_STEP_C_NUM; i++) {
|
||
|
|
pr_debug(" i=%d\n", i);
|
||
|
|
if (step_counter_init_list[i] != 0) {
|
||
|
|
pr_debug(" step_c try to init driver %s\n",
|
||
|
|
step_counter_init_list[i]->name);
|
||
|
|
err = step_counter_init_list[i]->init();
|
||
|
|
if (err == 0) {
|
||
|
|
pr_debug(" step_c real driver %s probe ok\n",
|
||
|
|
step_counter_init_list[i]->name);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (i == MAX_CHOOSE_STEP_C_NUM) {
|
||
|
|
pr_debug("%s fail\n", __func__);
|
||
|
|
err = -1;
|
||
|
|
}
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
int step_c_driver_add(struct step_c_init_info *obj)
|
||
|
|
{
|
||
|
|
int err = 0;
|
||
|
|
int i = 0;
|
||
|
|
|
||
|
|
pr_debug("%s\n", __func__);
|
||
|
|
|
||
|
|
pr_debug("register step_counter driver for the first time\n");
|
||
|
|
if (platform_driver_register(&step_counter_driver))
|
||
|
|
pr_err("fail to register gensor driver already exist\n");
|
||
|
|
for (i = 0; i < MAX_CHOOSE_STEP_C_NUM; i++) {
|
||
|
|
if (step_counter_init_list[i] == NULL) {
|
||
|
|
obj->platform_diver_addr = &step_counter_driver;
|
||
|
|
step_counter_init_list[i] = obj;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (i >= MAX_CHOOSE_STEP_C_NUM) {
|
||
|
|
pr_err("STEP_C driver add err\n");
|
||
|
|
err = -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int step_open(struct inode *inode, struct file *file)
|
||
|
|
{
|
||
|
|
nonseekable_open(inode, file);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static ssize_t step_read(struct file *file, char __user *buffer,
|
||
|
|
size_t count, loff_t *ppos)
|
||
|
|
{
|
||
|
|
ssize_t read_cnt = 0;
|
||
|
|
|
||
|
|
read_cnt = sensor_event_read(step_c_context_obj->mdev.minor,
|
||
|
|
file, buffer, count, ppos);
|
||
|
|
|
||
|
|
return read_cnt;
|
||
|
|
}
|
||
|
|
|
||
|
|
static unsigned int step_poll(struct file *file, poll_table *wait)
|
||
|
|
{
|
||
|
|
return sensor_event_poll(step_c_context_obj->mdev.minor, file, wait);
|
||
|
|
}
|
||
|
|
|
||
|
|
static const struct file_operations step_fops = {
|
||
|
|
.owner = THIS_MODULE,
|
||
|
|
.open = step_open,
|
||
|
|
.read = step_read,
|
||
|
|
.poll = step_poll,
|
||
|
|
};
|
||
|
|
|
||
|
|
static int step_c_misc_init(struct step_c_context *cxt)
|
||
|
|
{
|
||
|
|
|
||
|
|
int err = 0;
|
||
|
|
/* kernel-3.10\include\linux\Miscdevice.h */
|
||
|
|
/* use MISC_DYNAMIC_MINOR exceed 64 */
|
||
|
|
cxt->mdev.minor = ID_STEP_COUNTER;
|
||
|
|
cxt->mdev.name = STEP_C_MISC_DEV_NAME;
|
||
|
|
cxt->mdev.fops = &step_fops;
|
||
|
|
err = sensor_attr_register(&cxt->mdev);
|
||
|
|
if (err)
|
||
|
|
pr_err("unable to register step_c misc device!!\n");
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
DEVICE_ATTR_RW(step_cenablenodata);
|
||
|
|
DEVICE_ATTR_RW(step_cactive);
|
||
|
|
DEVICE_ATTR_RW(step_cdelay);
|
||
|
|
DEVICE_ATTR_RW(step_cbatch);
|
||
|
|
DEVICE_ATTR_RW(step_cflush);
|
||
|
|
DEVICE_ATTR_RO(step_cdevnum);
|
||
|
|
|
||
|
|
|
||
|
|
static struct attribute *step_c_attributes[] = {
|
||
|
|
&dev_attr_step_cenablenodata.attr,
|
||
|
|
&dev_attr_step_cactive.attr,
|
||
|
|
&dev_attr_step_cdelay.attr,
|
||
|
|
&dev_attr_step_cbatch.attr,
|
||
|
|
&dev_attr_step_cflush.attr,
|
||
|
|
&dev_attr_step_cdevnum.attr,
|
||
|
|
NULL
|
||
|
|
};
|
||
|
|
|
||
|
|
static struct attribute_group step_c_attribute_group = {
|
||
|
|
.attrs = step_c_attributes
|
||
|
|
};
|
||
|
|
|
||
|
|
int step_c_register_data_path(struct step_c_data_path *data)
|
||
|
|
{
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
cxt->step_c_data.get_data = data->get_data;
|
||
|
|
cxt->step_c_data.vender_div = data->vender_div;
|
||
|
|
cxt->step_c_data.get_data_significant = data->get_data_significant;
|
||
|
|
cxt->step_c_data.get_data_step_d = data->get_data_step_d;
|
||
|
|
cxt->step_c_data.get_data_floor_c = data->get_data_floor_c;
|
||
|
|
pr_debug("step_c register data path vender_div: %d\n",
|
||
|
|
cxt->step_c_data.vender_div);
|
||
|
|
if (cxt->step_c_data.get_data == NULL
|
||
|
|
|| cxt->step_c_data.get_data_significant == NULL
|
||
|
|
|| cxt->step_c_data.get_data_step_d == NULL) {
|
||
|
|
pr_debug("step_c register data path fail\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int step_c_register_control_path(struct step_c_control_path *ctl)
|
||
|
|
{
|
||
|
|
struct step_c_context *cxt = NULL;
|
||
|
|
int err = 0;
|
||
|
|
|
||
|
|
cxt = step_c_context_obj;
|
||
|
|
cxt->step_c_ctl.step_c_set_delay = ctl->step_c_set_delay;
|
||
|
|
cxt->step_c_ctl.step_d_set_delay = ctl->step_d_set_delay;
|
||
|
|
cxt->step_c_ctl.floor_c_set_delay = ctl->floor_c_set_delay;
|
||
|
|
cxt->step_c_ctl.open_report_data = ctl->open_report_data;
|
||
|
|
cxt->step_c_ctl.enable_nodata = ctl->enable_nodata;
|
||
|
|
cxt->step_c_ctl.step_c_batch = ctl->step_c_batch;
|
||
|
|
cxt->step_c_ctl.step_c_flush = ctl->step_c_flush;
|
||
|
|
cxt->step_c_ctl.step_d_batch = ctl->step_d_batch;
|
||
|
|
cxt->step_c_ctl.step_d_flush = ctl->step_d_flush;
|
||
|
|
cxt->step_c_ctl.smd_batch = ctl->smd_batch;
|
||
|
|
cxt->step_c_ctl.smd_flush = ctl->smd_flush;
|
||
|
|
cxt->step_c_ctl.floor_c_batch = ctl->floor_c_batch;
|
||
|
|
cxt->step_c_ctl.floor_c_flush = ctl->floor_c_flush;
|
||
|
|
cxt->step_c_ctl.is_counter_support_batch =
|
||
|
|
ctl->is_counter_support_batch;
|
||
|
|
cxt->step_c_ctl.is_detector_support_batch =
|
||
|
|
ctl->is_detector_support_batch;
|
||
|
|
cxt->step_c_ctl.is_smd_support_batch = ctl->is_smd_support_batch;
|
||
|
|
cxt->step_c_ctl.is_floor_c_support_batch =
|
||
|
|
ctl->is_floor_c_support_batch;
|
||
|
|
cxt->step_c_ctl.is_report_input_direct = ctl->is_report_input_direct;
|
||
|
|
cxt->step_c_ctl.enable_significant = ctl->enable_significant;
|
||
|
|
cxt->step_c_ctl.enable_step_detect = ctl->enable_step_detect;
|
||
|
|
cxt->step_c_ctl.enable_floor_c = ctl->enable_floor_c;
|
||
|
|
|
||
|
|
if ((cxt->step_c_ctl.step_c_set_delay == NULL)
|
||
|
|
|| (cxt->step_c_ctl.open_report_data == NULL)
|
||
|
|
|| (cxt->step_c_ctl.enable_nodata == NULL)
|
||
|
|
|| (cxt->step_c_ctl.step_d_set_delay == NULL)
|
||
|
|
|| (cxt->step_c_ctl.enable_significant == NULL)
|
||
|
|
|| (cxt->step_c_ctl.enable_step_detect == NULL)) {
|
||
|
|
pr_debug("step_c register control path fail\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* add misc dev for sensor hal control cmd */
|
||
|
|
err = step_c_misc_init(step_c_context_obj);
|
||
|
|
if (err) {
|
||
|
|
pr_err("unable to register step_c misc device!!\n");
|
||
|
|
return -2;
|
||
|
|
}
|
||
|
|
err = sysfs_create_group(&step_c_context_obj->mdev.this_device->kobj,
|
||
|
|
&step_c_attribute_group);
|
||
|
|
if (err < 0) {
|
||
|
|
pr_err("unable to create step_c attribute file\n");
|
||
|
|
return -3;
|
||
|
|
}
|
||
|
|
|
||
|
|
kobject_uevent(&step_c_context_obj->mdev.this_device->kobj, KOBJ_ADD);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int step_c_data_report_t(uint32_t new_counter, int status, int64_t time_stamp)
|
||
|
|
{
|
||
|
|
int err = 0;
|
||
|
|
struct sensor_event event;
|
||
|
|
static uint32_t last_step_counter;
|
||
|
|
|
||
|
|
memset(&event, 0, sizeof(struct sensor_event));
|
||
|
|
event.time_stamp = time_stamp;
|
||
|
|
if (last_step_counter != new_counter) {
|
||
|
|
event.flush_action = DATA_ACTION;
|
||
|
|
event.handle = ID_STEP_COUNTER;
|
||
|
|
event.word[0] = new_counter;
|
||
|
|
err = sensor_input_event(step_c_context_obj->mdev.minor,
|
||
|
|
&event);
|
||
|
|
if (err >= 0)
|
||
|
|
last_step_counter = new_counter;
|
||
|
|
}
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
int step_c_data_report(uint32_t new_counter, int status)
|
||
|
|
{
|
||
|
|
return step_c_data_report_t(new_counter, status, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
int floor_c_data_report_t(uint32_t new_counter, int status, int64_t time_stamp)
|
||
|
|
{
|
||
|
|
int err = 0;
|
||
|
|
struct sensor_event event;
|
||
|
|
static uint32_t last_floor_counter;
|
||
|
|
|
||
|
|
memset(&event, 0, sizeof(struct sensor_event));
|
||
|
|
event.time_stamp = time_stamp;
|
||
|
|
if (last_floor_counter != new_counter) {
|
||
|
|
event.flush_action = DATA_ACTION;
|
||
|
|
event.handle = ID_FLOOR_COUNTER;
|
||
|
|
event.word[0] = new_counter;
|
||
|
|
err = sensor_input_event(step_c_context_obj->mdev.minor,
|
||
|
|
&event);
|
||
|
|
if (err >= 0)
|
||
|
|
last_floor_counter = new_counter;
|
||
|
|
}
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
int floor_c_data_report(uint32_t new_counter, int status)
|
||
|
|
{
|
||
|
|
return floor_c_data_report_t(new_counter, status, 0);
|
||
|
|
}
|
||
|
|
int step_c_flush_report(void)
|
||
|
|
{
|
||
|
|
struct sensor_event event;
|
||
|
|
int err = 0;
|
||
|
|
|
||
|
|
memset(&event, 0, sizeof(struct sensor_event));
|
||
|
|
|
||
|
|
event.handle = ID_STEP_COUNTER;
|
||
|
|
event.flush_action = FLUSH_ACTION;
|
||
|
|
err = sensor_input_event(step_c_context_obj->mdev.minor, &event);
|
||
|
|
pr_debug_ratelimited("flush\n");
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
int step_d_flush_report(void)
|
||
|
|
{
|
||
|
|
struct sensor_event event;
|
||
|
|
int err = 0;
|
||
|
|
|
||
|
|
memset(&event, 0, sizeof(struct sensor_event));
|
||
|
|
|
||
|
|
event.handle = ID_STEP_DETECTOR;
|
||
|
|
event.flush_action = FLUSH_ACTION;
|
||
|
|
err = sensor_input_event(step_c_context_obj->mdev.minor, &event);
|
||
|
|
pr_debug_ratelimited("flush\n");
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
int smd_flush_report(void)
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int floor_c_flush_report(void)
|
||
|
|
{
|
||
|
|
struct sensor_event event;
|
||
|
|
int err = 0;
|
||
|
|
|
||
|
|
memset(&event, 0, sizeof(struct sensor_event));
|
||
|
|
|
||
|
|
event.handle = ID_FLOOR_COUNTER;
|
||
|
|
event.flush_action = FLUSH_ACTION;
|
||
|
|
err = sensor_input_event(step_c_context_obj->mdev.minor, &event);
|
||
|
|
pr_debug_ratelimited("flush\n");
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int step_c_probe(void)
|
||
|
|
{
|
||
|
|
|
||
|
|
int err;
|
||
|
|
|
||
|
|
pr_debug("%s+++!!\n", __func__);
|
||
|
|
|
||
|
|
step_c_context_obj = step_c_context_alloc_object();
|
||
|
|
if (!step_c_context_obj) {
|
||
|
|
err = -ENOMEM;
|
||
|
|
pr_err("unable to allocate devobj!\n");
|
||
|
|
goto exit_alloc_data_failed;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* init real step_c driver */
|
||
|
|
err = step_c_real_driver_init();
|
||
|
|
if (err) {
|
||
|
|
pr_err("step_c real driver init fail\n");
|
||
|
|
goto real_driver_init_fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
pr_debug("%s---- OK !!\n", __func__);
|
||
|
|
return 0;
|
||
|
|
real_driver_init_fail:
|
||
|
|
kfree(step_c_context_obj);
|
||
|
|
exit_alloc_data_failed:
|
||
|
|
pr_debug("%s---- fail !!!\n", __func__);
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int step_c_remove(void)
|
||
|
|
{
|
||
|
|
|
||
|
|
int err = 0;
|
||
|
|
|
||
|
|
pr_debug("%s\n", __func__);
|
||
|
|
sysfs_remove_group(&step_c_context_obj->mdev.this_device->kobj,
|
||
|
|
&step_c_attribute_group);
|
||
|
|
|
||
|
|
err = sensor_attr_deregister(&step_c_context_obj->mdev);
|
||
|
|
if (err)
|
||
|
|
pr_err("misc_deregister fail: %d\n", err);
|
||
|
|
kfree(step_c_context_obj);
|
||
|
|
platform_driver_unregister(&step_counter_driver);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int __init step_c_init(void)
|
||
|
|
{
|
||
|
|
pr_debug("%s\n", __func__);
|
||
|
|
|
||
|
|
if (step_c_probe()) {
|
||
|
|
pr_err("failed to register step_c driver\n");
|
||
|
|
return -ENODEV;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void __exit step_c_exit(void)
|
||
|
|
{
|
||
|
|
step_c_remove();
|
||
|
|
platform_driver_unregister(&step_counter_driver);
|
||
|
|
}
|
||
|
|
|
||
|
|
late_initcall(step_c_init);
|
||
|
|
MODULE_LICENSE("GPL");
|
||
|
|
MODULE_DESCRIPTION("STEP_CMETER device driver");
|
||
|
|
MODULE_AUTHOR("Mediatek");
|