1095 lines
27 KiB
C
1095 lines
27 KiB
C
|
|
#include "alsps.h"
|
|
|
|
static struct alsps_context *alsps_context_obj = NULL;
|
|
|
|
|
|
static struct alsps_init_info* alsps_init_list[MAX_CHOOSE_ALSPS_NUM]= {0}; //modified
|
|
static void alsps_early_suspend(struct early_suspend *h);
|
|
static void alsps_late_resume(struct early_suspend *h);
|
|
|
|
|
|
int als_data_report(struct input_dev *dev, int value, int status)
|
|
{
|
|
//ALSPS_LOG("+als_data_report! %d, %d\n",value,status);
|
|
input_report_abs(dev, EVENT_TYPE_ALS_VALUE, value);
|
|
input_report_abs(dev, EVENT_TYPE_ALS_STATUS, status);
|
|
input_sync(dev);
|
|
return 0;
|
|
}
|
|
|
|
int ps_data_report(struct input_dev *dev, int value,int status)
|
|
{
|
|
//ALSPS_LOG("+ps_data_report! %d, %d\n",value,status);
|
|
input_report_abs(dev, EVENT_TYPE_PS_VALUE, value);
|
|
input_report_abs(dev, EVENT_TYPE_PS_STATUS, status);
|
|
input_sync(dev);
|
|
return 0;
|
|
}
|
|
|
|
static void als_work_func(struct work_struct *work)
|
|
{
|
|
|
|
struct alsps_context *cxt = NULL;
|
|
int out_size;
|
|
//hwm_sensor_data sensor_data;
|
|
int value,status,div;
|
|
int64_t nt;
|
|
struct timespec time;
|
|
int err, idx;
|
|
|
|
cxt = alsps_context_obj;
|
|
|
|
if(NULL == cxt->als_data.get_data)
|
|
{
|
|
ALSPS_LOG("alsps driver not register data path\n");
|
|
}
|
|
|
|
|
|
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
|
|
err = cxt->als_data.get_data(&value,&status);
|
|
|
|
if(err)
|
|
{
|
|
ALSPS_ERR("get alsps data fails!!\n" );
|
|
goto als_loop;
|
|
}
|
|
else
|
|
{
|
|
{
|
|
cxt->drv_data.als_data.values[0] = value;
|
|
cxt->drv_data.als_data.status = status;
|
|
cxt->drv_data.als_data.time = nt;
|
|
|
|
}
|
|
}
|
|
|
|
if(true == cxt->is_als_first_data_after_enable)
|
|
{
|
|
cxt->is_als_first_data_after_enable = false;
|
|
//filter -1 value
|
|
if(ALSPS_INVALID_VALUE == cxt->drv_data.als_data.values[0] )
|
|
{
|
|
ALSPS_LOG(" read invalid data \n");
|
|
goto als_loop;
|
|
|
|
}
|
|
}
|
|
//report data to input device
|
|
//printk("new alsps work run....\n");
|
|
//ALSPS_LOG("als data[%d] \n" ,cxt->drv_data.als_data.values[0]);
|
|
|
|
als_data_report(cxt->idev,
|
|
cxt->drv_data.als_data.values[0],
|
|
cxt->drv_data.als_data.status);
|
|
|
|
als_loop:
|
|
if(true == cxt->is_als_polling_run)
|
|
{
|
|
{
|
|
mod_timer(&cxt->timer_als, jiffies + atomic_read(&cxt->delay_als)/(1000/HZ));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
static void ps_work_func(struct work_struct *work)
|
|
{
|
|
|
|
struct alsps_context *cxt = NULL;
|
|
int out_size;
|
|
//hwm_sensor_data sensor_data;
|
|
int value,status,div;
|
|
int64_t nt;
|
|
struct timespec time;
|
|
int err, idx;
|
|
|
|
cxt = alsps_context_obj;
|
|
|
|
if(NULL == cxt->ps_data.get_data)
|
|
{
|
|
ALSPS_LOG("alsps driver not register data path\n");
|
|
}
|
|
|
|
|
|
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
|
|
err = cxt->ps_data.get_data(&value,&status);
|
|
|
|
if(err)
|
|
{
|
|
ALSPS_ERR("get alsps data fails!!\n" );
|
|
goto ps_loop;
|
|
}
|
|
else
|
|
{
|
|
{
|
|
cxt->drv_data.ps_data.values[0] = value;
|
|
cxt->drv_data.ps_data.status = status;
|
|
cxt->drv_data.ps_data.time = nt;
|
|
|
|
}
|
|
}
|
|
|
|
if(true == cxt->is_ps_first_data_after_enable)
|
|
{
|
|
cxt->is_ps_first_data_after_enable = false;
|
|
//filter -1 value
|
|
if(ALSPS_INVALID_VALUE == cxt->drv_data.ps_data.values[0])
|
|
{
|
|
ALSPS_LOG(" read invalid data \n");
|
|
goto ps_loop;
|
|
|
|
}
|
|
}
|
|
//report data to input device
|
|
//printk("new alsps work run....\n");
|
|
//ALSPS_LOG("alsps data[%d,%d,%d] \n" ,cxt->drv_data.alsps_data.values[0],
|
|
//cxt->drv_data.alsps_data.values[1],cxt->drv_data.alsps_data.values[2]);
|
|
|
|
ps_data_report(cxt->idev,
|
|
cxt->drv_data.ps_data.values[0],
|
|
cxt->drv_data.ps_data.status);
|
|
|
|
ps_loop:
|
|
if(true == cxt->is_ps_polling_run)
|
|
{
|
|
{
|
|
mod_timer(&cxt->timer_ps, jiffies + atomic_read(&cxt->delay_ps)/(1000/HZ));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
static void als_poll(unsigned long data)
|
|
{
|
|
struct alsps_context *obj = (struct alsps_context *)data;
|
|
if(obj != NULL)
|
|
{
|
|
schedule_work(&obj->report_als);
|
|
}
|
|
}
|
|
|
|
static void ps_poll(unsigned long data)
|
|
{
|
|
struct alsps_context *obj = (struct alsps_context *)data;
|
|
if(obj != NULL)
|
|
{
|
|
if(obj->ps_ctl.is_polling_mode)
|
|
schedule_work(&obj->report_ps);
|
|
}
|
|
}
|
|
|
|
static struct alsps_context *alsps_context_alloc_object(void)
|
|
{
|
|
|
|
struct alsps_context *obj = kzalloc(sizeof(*obj), GFP_KERNEL);
|
|
ALSPS_LOG("alsps_context_alloc_object++++\n");
|
|
if(!obj)
|
|
{
|
|
ALSPS_ERR("Alloc alsps object error!\n");
|
|
return NULL;
|
|
}
|
|
atomic_set(&obj->delay_als, 200); /*5Hz*/// set work queue delay time 200ms
|
|
atomic_set(&obj->delay_ps, 200); /*5Hz*/// set work queue delay time 200ms
|
|
atomic_set(&obj->wake, 0);
|
|
INIT_WORK(&obj->report_als, als_work_func);
|
|
INIT_WORK(&obj->report_ps, ps_work_func);
|
|
init_timer(&obj->timer_als);
|
|
init_timer(&obj->timer_ps);
|
|
obj->timer_als.expires = jiffies + atomic_read(&obj->delay_als)/(1000/HZ);
|
|
obj->timer_als.function = als_poll;
|
|
obj->timer_als.data = (unsigned long)obj;
|
|
|
|
obj->timer_ps.expires = jiffies + atomic_read(&obj->delay_ps)/(1000/HZ);
|
|
obj->timer_ps.function = ps_poll;
|
|
obj->timer_ps.data = (unsigned long)obj;
|
|
|
|
obj->is_als_first_data_after_enable = false;
|
|
obj->is_als_polling_run = false;
|
|
obj->is_ps_first_data_after_enable = false;
|
|
obj->is_ps_polling_run = false;
|
|
mutex_init(&obj->alsps_op_mutex);
|
|
obj->is_als_batch_enable = false;//for batch mode init
|
|
obj->is_ps_batch_enable = false;//for batch mode init
|
|
|
|
ALSPS_LOG("alsps_context_alloc_object----\n");
|
|
return obj;
|
|
}
|
|
|
|
static int als_real_enable(int enable)
|
|
{
|
|
int err =0;
|
|
struct alsps_context *cxt = NULL;
|
|
cxt = alsps_context_obj;
|
|
if(1==enable)
|
|
{
|
|
|
|
if(true==cxt->is_als_active_data || true ==cxt->is_als_active_nodata)
|
|
{
|
|
err = cxt->als_ctl.enable_nodata(1);
|
|
if(err)
|
|
{
|
|
err = cxt->als_ctl.enable_nodata(1);
|
|
if(err)
|
|
{
|
|
err = cxt->als_ctl.enable_nodata(1);
|
|
if(err)
|
|
ALSPS_ERR("alsps enable(%d) err 3 timers = %d\n", enable, err);
|
|
}
|
|
}
|
|
ALSPS_LOG("alsps real enable \n" );
|
|
}
|
|
|
|
}
|
|
if(0==enable)
|
|
{
|
|
if(false==cxt->is_als_active_data && false ==cxt->is_als_active_nodata)
|
|
{
|
|
err = cxt->als_ctl.enable_nodata(0);
|
|
if(err)
|
|
{
|
|
ALSPS_ERR("alsps enable(%d) err = %d\n", enable, err);
|
|
}
|
|
ALSPS_LOG("alsps real disable \n" );
|
|
}
|
|
|
|
}
|
|
|
|
return err;
|
|
}
|
|
static int als_enable_data(int enable)
|
|
{
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
if(NULL == cxt->als_ctl.open_report_data)
|
|
{
|
|
ALSPS_ERR("no als control path\n");
|
|
return -1;
|
|
}
|
|
|
|
if(1 == enable)
|
|
{
|
|
ALSPS_LOG("ALSPS enable data\n");
|
|
cxt->is_als_active_data =true;
|
|
cxt->is_als_first_data_after_enable = true;
|
|
cxt->als_ctl.open_report_data(1);
|
|
if(false == cxt->is_als_polling_run && cxt->is_als_batch_enable == false)
|
|
{
|
|
if(false == cxt->als_ctl.is_report_input_direct)
|
|
{
|
|
mod_timer(&cxt->timer_als, jiffies + atomic_read(&cxt->delay_als)/(1000/HZ));
|
|
cxt->is_als_polling_run = true;
|
|
}
|
|
}
|
|
}
|
|
if(0 == enable)
|
|
{
|
|
ALSPS_LOG("ALSPS disable \n");
|
|
cxt->is_als_active_data =false;
|
|
cxt->als_ctl.open_report_data(0);
|
|
if(true == cxt->is_als_polling_run)
|
|
{
|
|
if(false == cxt->als_ctl.is_report_input_direct )
|
|
{
|
|
cxt->is_als_polling_run = false;
|
|
del_timer_sync(&cxt->timer_als);
|
|
cancel_work_sync(&cxt->report_als);
|
|
cxt->drv_data.als_data.values[0] = ALSPS_INVALID_VALUE;
|
|
}
|
|
}
|
|
}
|
|
als_real_enable(enable);
|
|
return 0;
|
|
}
|
|
|
|
static int ps_real_enable(int enable)
|
|
{
|
|
int err =0;
|
|
struct alsps_context *cxt = NULL;
|
|
cxt = alsps_context_obj;
|
|
if(1==enable)
|
|
{
|
|
|
|
if(true==cxt->is_ps_active_data || true ==cxt->is_ps_active_nodata)
|
|
{
|
|
err = cxt->ps_ctl.enable_nodata(1);
|
|
if(err)
|
|
{
|
|
err = cxt->ps_ctl.enable_nodata(1);
|
|
if(err)
|
|
{
|
|
err = cxt->ps_ctl.enable_nodata(1);
|
|
if(err)
|
|
ALSPS_ERR("ps enable(%d) err 3 timers = %d\n", enable, err);
|
|
}
|
|
}
|
|
ALSPS_LOG("ps real enable \n" );
|
|
}
|
|
|
|
}
|
|
if(0==enable)
|
|
{
|
|
if(false==cxt->is_ps_active_data && false ==cxt->is_ps_active_nodata)
|
|
{
|
|
err = cxt->ps_ctl.enable_nodata(0);
|
|
if(err)
|
|
{
|
|
ALSPS_ERR("ps enable(%d) err = %d\n", enable, err);
|
|
}
|
|
ALSPS_LOG("ps real disable \n" );
|
|
}
|
|
|
|
}
|
|
|
|
return err;
|
|
}
|
|
static int ps_enable_data(int enable)
|
|
{
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
if(NULL == cxt->ps_ctl.open_report_data)
|
|
{
|
|
ALSPS_ERR("no ps control path\n");
|
|
return -1;
|
|
}
|
|
|
|
if(1 == enable)
|
|
{
|
|
ALSPS_LOG("PS enable data\n");
|
|
cxt->is_ps_active_data =true;
|
|
cxt->is_ps_first_data_after_enable = true;
|
|
cxt->ps_ctl.open_report_data(1);
|
|
if(false == cxt->is_ps_polling_run && cxt->is_ps_batch_enable == false)
|
|
{
|
|
if(false == cxt->ps_ctl.is_report_input_direct)
|
|
{
|
|
mod_timer(&cxt->timer_ps, jiffies + atomic_read(&cxt->delay_ps)/(1000/HZ));
|
|
cxt->is_ps_polling_run = true;
|
|
}
|
|
}
|
|
}
|
|
if(0 == enable)
|
|
{
|
|
ALSPS_LOG("PS disable \n");
|
|
cxt->is_ps_active_data =false;
|
|
cxt->ps_ctl.open_report_data(0);
|
|
if(true == cxt->is_ps_polling_run)
|
|
{
|
|
if(false == cxt->ps_ctl.is_report_input_direct )
|
|
{
|
|
cxt->is_ps_polling_run = false;
|
|
del_timer_sync(&cxt->timer_ps);
|
|
cancel_work_sync(&cxt->report_ps);
|
|
cxt->drv_data.ps_data.values[0] = ALSPS_INVALID_VALUE;
|
|
}
|
|
}
|
|
}
|
|
ps_real_enable(enable);
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t als_store_active(struct device* dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
ALSPS_LOG("als_store_active buf=%s\n",buf);
|
|
mutex_lock(&alsps_context_obj->alsps_op_mutex);
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
|
|
if (!strncmp(buf, "1", 1))
|
|
{
|
|
als_enable_data(1);
|
|
}
|
|
else if (!strncmp(buf, "0", 1))
|
|
{
|
|
als_enable_data(0);
|
|
}
|
|
else
|
|
{
|
|
ALSPS_ERR(" alsps_store_active error !!\n");
|
|
}
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
ALSPS_LOG(" alsps_store_active done\n");
|
|
return count;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
static ssize_t als_show_active(struct device* dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct alsps_context *cxt = NULL;
|
|
cxt = alsps_context_obj;
|
|
int div=cxt->als_data.vender_div;
|
|
ALSPS_LOG("als vender_div value: %d\n", div);
|
|
return snprintf(buf, PAGE_SIZE, "%d\n", div);
|
|
}
|
|
|
|
static ssize_t als_store_delay(struct device* dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
mutex_lock(&alsps_context_obj->alsps_op_mutex);
|
|
struct alsps_context *devobj = (struct alsps_context*)dev_get_drvdata(dev);
|
|
int delay;
|
|
int mdelay=0;
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
if(NULL == cxt->als_ctl.set_delay)
|
|
{
|
|
ALSPS_LOG("als_ctl set_delay NULL\n");
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
return count;
|
|
}
|
|
|
|
if (1 != sscanf(buf, "%d", &delay)) {
|
|
ALSPS_ERR("invalid format!!\n");
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
return count;
|
|
}
|
|
|
|
if(false == cxt->als_ctl.is_report_input_direct)
|
|
{
|
|
mdelay = (int)delay/1000/1000;
|
|
atomic_set(&alsps_context_obj->delay_als, mdelay);
|
|
}
|
|
cxt->als_ctl.set_delay(delay);
|
|
ALSPS_LOG(" als_delay %d ns\n",delay);
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
return count;
|
|
|
|
}
|
|
|
|
static ssize_t als_show_delay(struct device* dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int len = 0;
|
|
ALSPS_LOG(" not support now\n");
|
|
return len;
|
|
}
|
|
|
|
|
|
static ssize_t als_store_batch(struct device* dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
ALSPS_LOG("als_store_batch buf=%s\n",buf);
|
|
mutex_lock(&alsps_context_obj->alsps_op_mutex);
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
if(cxt->als_ctl.is_support_batch){
|
|
if (!strncmp(buf, "1", 1))
|
|
{
|
|
cxt->is_als_batch_enable = true;
|
|
}
|
|
else if (!strncmp(buf, "0", 1))
|
|
{
|
|
cxt->is_als_batch_enable = false;
|
|
}
|
|
else
|
|
{
|
|
ALSPS_ERR(" als_store_batch error !!\n");
|
|
}
|
|
}else{
|
|
ALSPS_LOG(" als_store_batch not supported\n");
|
|
}
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
ALSPS_LOG(" als_store_batch done: %d\n", cxt->is_als_batch_enable);
|
|
return count;
|
|
|
|
}
|
|
|
|
static ssize_t als_show_batch(struct device* dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return snprintf(buf, PAGE_SIZE, "%d\n", 0);
|
|
}
|
|
|
|
static ssize_t als_store_flush(struct device* dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
mutex_lock(&alsps_context_obj->alsps_op_mutex);
|
|
struct alsps_context *devobj = (struct alsps_context*)dev_get_drvdata(dev);
|
|
//do read FIFO data function and report data immediately
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t als_show_flush(struct device* dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return snprintf(buf, PAGE_SIZE, "%d\n", 0);
|
|
}
|
|
|
|
static ssize_t als_show_devnum(struct device* dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
char *devname =NULL;
|
|
devname = dev_name(&alsps_context_obj->idev->dev);
|
|
return snprintf(buf, PAGE_SIZE, "%s\n", devname+5);
|
|
}
|
|
static ssize_t ps_store_active(struct device* dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
ALSPS_LOG("ps_store_active buf=%s\n",buf);
|
|
mutex_lock(&alsps_context_obj->alsps_op_mutex);
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
|
|
if (!strncmp(buf, "1", 1))
|
|
{
|
|
ps_enable_data(1);
|
|
}
|
|
else if (!strncmp(buf, "0", 1))
|
|
{
|
|
ps_enable_data(0);
|
|
}
|
|
else
|
|
{
|
|
ALSPS_ERR(" ps_store_active error !!\n");
|
|
}
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
ALSPS_LOG(" ps_store_active done\n");
|
|
return count;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
static ssize_t ps_show_active(struct device* dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct alsps_context *cxt = NULL;
|
|
cxt = alsps_context_obj;
|
|
int div=cxt->ps_data.vender_div;
|
|
ALSPS_LOG("ps vender_div value: %d\n", div);
|
|
return snprintf(buf, PAGE_SIZE, "%d\n", div);
|
|
}
|
|
|
|
static ssize_t ps_store_delay(struct device* dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
mutex_lock(&alsps_context_obj->alsps_op_mutex);
|
|
struct alsps_context *devobj = (struct alsps_context*)dev_get_drvdata(dev);
|
|
int delay;
|
|
int mdelay=0;
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
if(NULL == cxt->ps_ctl.set_delay)
|
|
{
|
|
ALSPS_LOG("ps_ctl set_delay NULL\n");
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
return count;
|
|
}
|
|
|
|
if (1 != sscanf(buf, "%d", &delay)) {
|
|
ALSPS_ERR("invalid format!!\n");
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
return count;
|
|
}
|
|
|
|
if(false == cxt->ps_ctl.is_report_input_direct)
|
|
{
|
|
mdelay = (int)delay/1000/1000;
|
|
atomic_set(&alsps_context_obj->delay_ps, mdelay);
|
|
}
|
|
cxt->ps_ctl.set_delay(delay);
|
|
ALSPS_LOG(" ps_delay %d ns\n",delay);
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
return count;
|
|
|
|
}
|
|
|
|
static ssize_t ps_show_delay(struct device* dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int len = 0;
|
|
ALSPS_LOG(" not support now\n");
|
|
return len;
|
|
}
|
|
|
|
|
|
static ssize_t ps_store_batch(struct device* dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
ALSPS_LOG("ps_store_batch buf=%s\n",buf);
|
|
mutex_lock(&alsps_context_obj->alsps_op_mutex);
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
if(cxt->ps_ctl.is_support_batch){
|
|
if (!strncmp(buf, "1", 1))
|
|
{
|
|
cxt->is_ps_batch_enable = true;
|
|
}
|
|
else if (!strncmp(buf, "0", 1))
|
|
{
|
|
cxt->is_ps_batch_enable = false;
|
|
}
|
|
else
|
|
{
|
|
ALSPS_ERR(" ps_store_batch error !!\n");
|
|
}
|
|
}else{
|
|
ALSPS_LOG(" ps_store_batch not supported\n");
|
|
}
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
ALSPS_LOG(" ps_store_batch done: %d\n", cxt->is_ps_batch_enable);
|
|
return count;
|
|
|
|
}
|
|
|
|
static ssize_t ps_show_batch(struct device* dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return snprintf(buf, PAGE_SIZE, "%d\n", 0);
|
|
}
|
|
|
|
static ssize_t ps_store_flush(struct device* dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
mutex_lock(&alsps_context_obj->alsps_op_mutex);
|
|
struct alsps_context *devobj = (struct alsps_context*)dev_get_drvdata(dev);
|
|
//do read FIFO data function and report data immediately
|
|
mutex_unlock(&alsps_context_obj->alsps_op_mutex);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t ps_show_flush(struct device* dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return snprintf(buf, PAGE_SIZE, "%d\n", 0);
|
|
}
|
|
|
|
static ssize_t ps_show_devnum(struct device* dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
char *devname =NULL;
|
|
devname = dev_name(&alsps_context_obj->idev->dev);
|
|
return snprintf(buf, PAGE_SIZE, "%s\n", devname+5);
|
|
}
|
|
static int als_ps_remove(struct platform_device *pdev)
|
|
{
|
|
ALSPS_LOG("als_ps_remove\n");
|
|
return 0;
|
|
}
|
|
|
|
static int als_ps_probe(struct platform_device *pdev)
|
|
{
|
|
ALSPS_LOG("als_ps_probe\n");
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver als_ps_driver = {
|
|
.probe = als_ps_probe,
|
|
.remove = als_ps_remove,
|
|
.driver =
|
|
{
|
|
.name = "als_ps",
|
|
}
|
|
};
|
|
|
|
static int alsps_real_driver_init(void)
|
|
{
|
|
int i =0;
|
|
int err=0;
|
|
ALSPS_LOG(" alsps_real_driver_init +\n");
|
|
for(i = 0; i < MAX_CHOOSE_ALSPS_NUM; i++)
|
|
{
|
|
ALSPS_LOG("alsps_real_driver_init i=%d\n",i);
|
|
if(0 != alsps_init_list[i])
|
|
{
|
|
ALSPS_LOG(" alsps try to init driver %s\n", alsps_init_list[i]->name);
|
|
err = alsps_init_list[i]->init();
|
|
if(0 == err)
|
|
{
|
|
ALSPS_LOG(" alsps real driver %s probe ok\n", alsps_init_list[i]->name);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(i == MAX_CHOOSE_ALSPS_NUM)
|
|
{
|
|
ALSPS_LOG(" alsps_real_driver_init fail\n");
|
|
err=-1;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int alsps_driver_add(struct alsps_init_info* obj)
|
|
{
|
|
int err=0;
|
|
int i =0;
|
|
|
|
ALSPS_FUN();
|
|
|
|
for(i =0; i < MAX_CHOOSE_ALSPS_NUM; i++ )
|
|
{
|
|
if(i == 0){
|
|
ALSPS_LOG("register alsps driver for the first time\n");
|
|
if(platform_driver_register(&als_ps_driver))
|
|
{
|
|
ALSPS_ERR("failed to register gensor driver already exist\n");
|
|
}
|
|
}
|
|
|
|
if(NULL == alsps_init_list[i])
|
|
{
|
|
obj->platform_diver_addr = &als_ps_driver;
|
|
alsps_init_list[i] = obj;
|
|
break;
|
|
}
|
|
}
|
|
if(NULL==alsps_init_list[i])
|
|
{
|
|
ALSPS_ERR("ALSPS driver add err \n");
|
|
err=-1;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(alsps_driver_add);
|
|
|
|
int ps_report_interrupt_data(int value)
|
|
{
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
ps_data_report(cxt->idev,value,3);
|
|
|
|
return 0;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
EXPORT_SYMBOL_GPL(ps_report_interrupt_data);
|
|
|
|
static int alsps_misc_init(struct alsps_context *cxt)
|
|
{
|
|
|
|
int err=0;
|
|
cxt->mdev.minor = MISC_DYNAMIC_MINOR;
|
|
cxt->mdev.name = ALSPS_MISC_DEV_NAME;
|
|
if((err = misc_register(&cxt->mdev)))
|
|
{
|
|
ALSPS_ERR("unable to register alsps misc device!!\n");
|
|
}
|
|
return err;
|
|
}
|
|
|
|
static void alsps_input_destroy(struct alsps_context *cxt)
|
|
{
|
|
struct input_dev *dev = cxt->idev;
|
|
|
|
input_unregister_device(dev);
|
|
input_free_device(dev);
|
|
}
|
|
|
|
static int alsps_input_init(struct alsps_context *cxt)
|
|
{
|
|
struct input_dev *dev;
|
|
int err = 0;
|
|
|
|
dev = input_allocate_device();
|
|
if (NULL == dev)
|
|
return -ENOMEM;
|
|
|
|
dev->name = ALSPS_INPUTDEV_NAME;
|
|
|
|
input_set_capability(dev, EV_ABS, EVENT_TYPE_ALS_VALUE);
|
|
input_set_capability(dev, EV_ABS, EVENT_TYPE_PS_VALUE);
|
|
input_set_capability(dev, EV_ABS, EVENT_TYPE_ALS_STATUS);
|
|
input_set_capability(dev, EV_ABS, EVENT_TYPE_PS_STATUS);
|
|
|
|
input_set_abs_params(dev, EVENT_TYPE_ALS_VALUE, ALSPS_VALUE_MIN, ALSPS_VALUE_MAX, 0, 0);
|
|
input_set_abs_params(dev, EVENT_TYPE_PS_VALUE, ALSPS_VALUE_MIN, ALSPS_VALUE_MAX, 0, 0);
|
|
input_set_abs_params(dev, EVENT_TYPE_ALS_STATUS, ALSPS_STATUS_MIN, ALSPS_STATUS_MAX, 0, 0);
|
|
input_set_abs_params(dev, EVENT_TYPE_PS_STATUS, ALSPS_STATUS_MIN, ALSPS_STATUS_MAX, 0, 0);
|
|
input_set_drvdata(dev, cxt);
|
|
|
|
err = input_register_device(dev);
|
|
if (err < 0) {
|
|
input_free_device(dev);
|
|
return err;
|
|
}
|
|
cxt->idev= dev;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
DEVICE_ATTR(alsactive, S_IWUSR | S_IRUGO, als_show_active, als_store_active);
|
|
DEVICE_ATTR(alsdelay, S_IWUSR | S_IRUGO, als_show_delay, als_store_delay);
|
|
DEVICE_ATTR(alsbatch, S_IWUSR | S_IRUGO, als_show_batch, als_store_batch);
|
|
DEVICE_ATTR(alsflush, S_IWUSR | S_IRUGO, als_show_flush, als_store_flush);
|
|
DEVICE_ATTR(alsdevnum, S_IWUSR | S_IRUGO, als_show_devnum, NULL);
|
|
DEVICE_ATTR(psactive, S_IWUSR | S_IRUGO, ps_show_active, ps_store_active);
|
|
DEVICE_ATTR(psdelay, S_IWUSR | S_IRUGO, ps_show_delay, ps_store_delay);
|
|
DEVICE_ATTR(psbatch, S_IWUSR | S_IRUGO, ps_show_batch, ps_store_batch);
|
|
DEVICE_ATTR(psflush, S_IWUSR | S_IRUGO, ps_show_flush, ps_store_flush);
|
|
DEVICE_ATTR(psdevnum, S_IWUSR | S_IRUGO, ps_show_devnum, NULL);
|
|
|
|
|
|
static struct attribute *alsps_attributes[] = {
|
|
&dev_attr_alsactive.attr,
|
|
&dev_attr_alsdelay.attr,
|
|
&dev_attr_alsbatch.attr,
|
|
&dev_attr_alsflush.attr,
|
|
&dev_attr_alsdevnum.attr,
|
|
&dev_attr_psactive.attr,
|
|
&dev_attr_psdelay.attr,
|
|
&dev_attr_psbatch.attr,
|
|
&dev_attr_psflush.attr,
|
|
&dev_attr_psdevnum.attr,
|
|
NULL
|
|
};
|
|
|
|
static struct attribute_group alsps_attribute_group = {
|
|
.attrs = alsps_attributes
|
|
};
|
|
|
|
int als_register_data_path(struct als_data_path *data)
|
|
{
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
cxt->als_data.get_data = data->get_data;
|
|
cxt->als_data.vender_div = data->vender_div;
|
|
ALSPS_LOG("alsps register data path vender_div: %d\n", cxt->als_data.vender_div);
|
|
if(NULL == cxt->als_data.get_data)
|
|
{
|
|
ALSPS_LOG("alsps register data path fail \n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int ps_register_data_path(struct ps_data_path *data)
|
|
{
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
cxt->ps_data.get_data = data->get_data;
|
|
cxt->ps_data.vender_div = data->vender_div;
|
|
ALSPS_LOG("alsps register data path vender_div: %d\n", cxt->ps_data.vender_div);
|
|
if(NULL == cxt->ps_data.get_data)
|
|
{
|
|
ALSPS_LOG("alsps register data path fail \n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int als_register_control_path(struct als_control_path *ctl)
|
|
{
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
cxt->als_ctl.set_delay = ctl->set_delay;
|
|
cxt->als_ctl.open_report_data= ctl->open_report_data;
|
|
cxt->als_ctl.enable_nodata = ctl->enable_nodata;
|
|
cxt->als_ctl.is_support_batch = ctl->is_support_batch;
|
|
cxt->als_ctl.is_report_input_direct= ctl->is_report_input_direct;
|
|
|
|
if(NULL==cxt->als_ctl.set_delay || NULL==cxt->als_ctl.open_report_data
|
|
|| NULL==cxt->als_ctl.enable_nodata)
|
|
{
|
|
ALSPS_LOG("alsps register control path fail \n");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ps_register_control_path(struct ps_control_path *ctl)
|
|
{
|
|
struct alsps_context *cxt = NULL;
|
|
int err =0;
|
|
cxt = alsps_context_obj;
|
|
cxt->ps_ctl.set_delay = ctl->set_delay;
|
|
cxt->ps_ctl.open_report_data= ctl->open_report_data;
|
|
cxt->ps_ctl.enable_nodata = ctl->enable_nodata;
|
|
cxt->ps_ctl.is_support_batch = ctl->is_support_batch;
|
|
cxt->ps_ctl.is_report_input_direct= ctl->is_report_input_direct;
|
|
|
|
if(NULL==cxt->ps_ctl.set_delay || NULL==cxt->ps_ctl.open_report_data
|
|
|| NULL==cxt->ps_ctl.enable_nodata)
|
|
{
|
|
ALSPS_LOG("ps register control path fail \n");
|
|
return -1;
|
|
}
|
|
|
|
//add misc dev for sensor hal control cmd
|
|
err = alsps_misc_init(alsps_context_obj);
|
|
if(err)
|
|
{
|
|
ALSPS_ERR("unable to register alsps misc device!!\n");
|
|
return -2;
|
|
}
|
|
err = sysfs_create_group(&alsps_context_obj->mdev.this_device->kobj,
|
|
&alsps_attribute_group);
|
|
if (err < 0)
|
|
{
|
|
ALSPS_ERR("unable to create alsps attribute file\n");
|
|
return -3;
|
|
}
|
|
|
|
|
|
kobject_uevent(&alsps_context_obj->mdev.this_device->kobj, KOBJ_ADD);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int alsps_probe(struct platform_device *pdev)
|
|
{
|
|
|
|
int err;
|
|
ALSPS_LOG("+++++++++++++alsps_probe!!\n");
|
|
|
|
alsps_context_obj = alsps_context_alloc_object();
|
|
if (!alsps_context_obj)
|
|
{
|
|
err = -ENOMEM;
|
|
ALSPS_ERR("unable to allocate devobj!\n");
|
|
goto exit_alloc_data_failed;
|
|
}
|
|
|
|
//init real alspseleration driver
|
|
err = alsps_real_driver_init();
|
|
if(err)
|
|
{
|
|
ALSPS_ERR("alsps real driver init fail\n");
|
|
goto real_driver_init_fail;
|
|
}
|
|
|
|
//init input dev
|
|
err = alsps_input_init(alsps_context_obj);
|
|
if(err)
|
|
{
|
|
ALSPS_ERR("unable to register alsps input device!\n");
|
|
goto exit_alloc_input_dev_failed;
|
|
}
|
|
|
|
atomic_set(&(alsps_context_obj->early_suspend), 0);
|
|
alsps_context_obj->early_drv.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING - 1,
|
|
alsps_context_obj->early_drv.suspend = alsps_early_suspend,
|
|
alsps_context_obj->early_drv.resume = alsps_late_resume,
|
|
register_early_suspend(&alsps_context_obj->early_drv);
|
|
|
|
|
|
ALSPS_LOG("----alsps_probe OK !!\n");
|
|
return 0;
|
|
|
|
exit_hwmsen_create_attr_failed:
|
|
exit_misc_register_failed:
|
|
|
|
exit_err_sysfs:
|
|
|
|
if (err)
|
|
{
|
|
ALSPS_ERR("sysfs node creation error \n");
|
|
alsps_input_destroy(alsps_context_obj);
|
|
}
|
|
|
|
real_driver_init_fail:
|
|
exit_alloc_input_dev_failed:
|
|
kfree(alsps_context_obj);
|
|
|
|
exit_alloc_data_failed:
|
|
|
|
|
|
ALSPS_LOG("----alsps_probe fail !!!\n");
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
static int alsps_remove(struct platform_device *pdev)
|
|
{
|
|
ALSPS_FUN(f);
|
|
int err=0;
|
|
input_unregister_device(alsps_context_obj->idev);
|
|
sysfs_remove_group(&alsps_context_obj->idev->dev.kobj,
|
|
&alsps_attribute_group);
|
|
|
|
if((err = misc_deregister(&alsps_context_obj->mdev)))
|
|
{
|
|
ALSPS_ERR("misc_deregister fail: %d\n", err);
|
|
}
|
|
kfree(alsps_context_obj);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void alsps_early_suspend(struct early_suspend *h)
|
|
{
|
|
atomic_set(&(alsps_context_obj->early_suspend), 1);
|
|
ALSPS_LOG(" alsps_early_suspend ok------->hwm_obj->early_suspend=%d \n",atomic_read(&(alsps_context_obj->early_suspend)));
|
|
return ;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
static void alsps_late_resume(struct early_suspend *h)
|
|
{
|
|
atomic_set(&(alsps_context_obj->early_suspend), 0);
|
|
ALSPS_LOG(" alsps_late_resume ok------->hwm_obj->early_suspend=%d \n",atomic_read(&(alsps_context_obj->early_suspend)));
|
|
return ;
|
|
}
|
|
|
|
static int alsps_suspend(struct platform_device *dev, pm_message_t state)
|
|
{
|
|
return 0;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
static int alsps_resume(struct platform_device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver alsps_driver =
|
|
{
|
|
.probe = alsps_probe,
|
|
.remove = alsps_remove,
|
|
.suspend = alsps_suspend,
|
|
.resume = alsps_resume,
|
|
.driver =
|
|
{
|
|
.name = ALSPS_PL_DEV_NAME,
|
|
}
|
|
};
|
|
|
|
static int __init alsps_init(void)
|
|
{
|
|
ALSPS_FUN();
|
|
|
|
if(platform_driver_register(&alsps_driver))
|
|
{
|
|
ALSPS_ERR("failed to register alsps driver\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __exit alsps_exit(void)
|
|
{
|
|
platform_driver_unregister(&alsps_driver);
|
|
platform_driver_unregister(&als_ps_driver);
|
|
|
|
}
|
|
|
|
module_init(alsps_init);
|
|
module_exit(alsps_exit);
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("ALSPS device driver");
|
|
MODULE_AUTHOR("Mediatek");
|
|
|