/*
MTK sensor 经过了一个中间层,数据上报数据为:
应用层: /dev/input/xxx
----------------------------------------------------------------------------------
内核:
[Input 子系统]
/\
||
[MTK 添加的 hwmsen 层] [轮询传感器上报或传感器中断自己上报]
/\
||
--------------------------------------
[sensor 1] [sensor 2] ..... [sensor n]
【传感器驱动调用接口】:
hwmsen_attach(int sensor, struct hwmsen_object *obj)
////////////////////////////////////////////////////////
// 创建一个 hwmsen_context 添加全局数组 dev_context
// 这样 hwmsen 模块就会轮询检查上报此传感器的值
mcxt->cxt[sensor] = kzalloc(sizeof(struct hwmsen_context), GFP_KERNEL)
memcpy(&mcxt->cxt[sensor]->obj, obj, sizeof(*obj));
hwmsen_detach(int sensor)
kfree(mcxt->cxt[sensor]);
mcxt->cxt[sensor] = NULL;
【应用程序操作入口流程】:
hwmsen_unlocked_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
switch(cmd)
{
case HWM_IO_SET_DELAY:
copy_from_user(&delayPara, argp, sizeof(delayPara))
hwmsen_set_delay(delayPara.delay,delayPara.handle);//modified for android2.3
// 获得操作上下文,上下文是在初始化流程中做的
struct hwmsen_context *cxt = NULL;
cxt = hwm_obj->dc->cxt[handle];
////////////////////////////////////////////////////////////////////////////////////////
// 调用具体 sensor 驱动中注册的函数
cxt->obj.sensor_operate(cxt->obj.self, SENSOR_DELAY, &delay,sizeof(int), NULL, 0, NULL)
update_workqueue_polling_rate(delayPara.delay);
//use the fastest sensor polling delay as work queue polling delay base time
//upadate all sensors delayCountSet
case HWM_IO_SET_WAKE:
hwmsen_wakeup(hwm_obj);
input_event(obj->idev, EV_SYN, SYN_CONFIG, 0);
case HWM_IO_ENABLE_SENSOR:
copy_from_user(&flag, argp, sizeof(flag))
hwmsen_enable(hwm_obj, flag, 1);
if(enable == 1)
////////////////////////////////////////////////////////////////
// 上电使能传感器
cxt->obj.sensor_operate(cxt->obj.self, SENSOR_ENABLE, &enable,sizeof(int), NULL, 0, NULL)
// Need to complete the interrupt sensor work
///////////////////////////////////////////////////////////////
// 打开定时器,让其定时轮询传感器数据
obj->dc->polling_running = 1;
mod_timer(&obj->timer, jiffies + atomic_read(&obj->delay)/(1000/HZ));
else
cxt->obj.sensor_operate(cxt->obj.self, SENSOR_ENABLE, &enable,sizeof(int), NULL, 0, NULL)
update_workqueue_polling_rate(200);// re-update workqueue polling rate
///////////////////////////////////////////////////////////////
// 取消定时器,关闭轮询传感器数据
obj->dc->polling_running = 0;
del_timer_sync(&obj->timer);
cancel_work_sync(&obj->report);
// 传感器数据设置为无效
obj_data.sensors_data[sensor].values[0] = SENSOR_INVALID_VALUE;
obj_data.sensors_data[sensor].values[1] = SENSOR_INVALID_VALUE;
obj_data.sensors_data[sensor].values[2] = SENSOR_INVALID_VALUE;
case HWM_IO_DISABLE_SENSOR:
copy_from_user(&flag, argp, sizeof(flag))
hwmsen_enable(hwm_obj, flag, 0);
case HWM_IO_GET_SENSORS_DATA:
copy_from_user(&hwm_sensors_data, argp, sizeof(hwm_sensors_data))
case HWM_IO_ENABLE_SENSOR_NODATA:
copy_from_user(&flag, argp, sizeof(flag))
hwmsen_enable_nodata(hwm_obj, flag, 1)
if(enable == 1)
cxt->obj.sensor_operate(cxt->obj.self, SENSOR_ENABLE, &enable, sizeof(int), NULL, 0, NULL)
else
cxt->obj.sensor_operate(cxt->obj.self, SENSOR_ENABLE, &enable,sizeof(int), NULL, 0, NULL)
case HWM_IO_DISABLE_SENSOR_NODATA:
hwmsen_enable_nodata(hwm_obj, flag, 0);
case HWM_IO_DISABLE_SENSOR_NODATA:
hwmsen_enable_nodata(hwm_obj, flag, 0);
【模块初始化流程总结】 :
module_init(hwmsen_init);
hwmsen_init(void)
// 注册平台设备
platform_driver_register(&hwmsen_driver)
// 匹配设备后调用
hwmsen_probe(struct platform_device *pdev)
// 初始化静态数组
init_static_data();
// 主要用两个数组:hwmsen_data 与 dev_context 数据结构的数组
// -------------Sensor daa-----------------------------------------------------
// struct hwmsen_data{
// hwm_sensor_data sensors_data[MAX_ANDROID_SENSOR_NUM+1];
// typedef struct {
// int sensor; // 传感器识别 sensor identifier
// int values[3]; // 传感器值 sensor values
// uint32_t value_divide; // sensor values divide
// int8_t status; // sensor accuracy
// int update; // whether updata?
// int64_t time; // time is in nanosecond
// uint32_t reserved;
// }hwm_sensor_data;
// int data_updata[MAX_ANDROID_SENSOR_NUM+1];
// struct mutex lock;
// };
// ----------------------------------------------------------------------------
// struct dev_context {
// int polling_running;
// struct mutex lock;
// struct hwmsen_context* cxt[MAX_ANDROID_SENSOR_NUM+1];
// struct hwmsen_context { // sensor context
// atomic_t enable;
// atomic_t delay;
// uint32_t delayCountSet;
// uint32_t delayCount;
//
// struct hwmsen_object obj;
// struct hwmsen_object {
// void *self;
// int polling; // 上传数据方式:轮询还是中断
/ // 被 hwmsen 模块回调的函数,用于获得上报数据等,与传感器交互使用
// int (*sensor_operate)(void* self, uint32_t command, void* buff_in, int size_in,
// void* buff_out, int size_out, int* actualout);
// };
// };
// };
hwm_obj = hwmsen_alloc_object();
struct hwmdev_object *obj = kzalloc(sizeof(*obj), GFP_KERNEL);
obj->dc = &dev_cxt;
obj->active_data_sensor = 0;
obj->active_sensor = 0;
atomic_set(&obj->delay, 200); // 5Hz // set work queue delay time 200ms
atomic_set(&obj->wake, 0);
//////////////////////////////////////////////////////////////////////////
// 创建单线程工作队列
sensor_workqueue = create_singlethread_workqueue("sensor_polling");
INIT_WORK(&obj->report, hwmsen_work_func);
init_timer(&obj->timer);
obj->timer.expires = jiffies + atomic_read(&obj->delay)/(1000/HZ);
//////////////////////////////////////////////////////////////////////////
// 用于轮询
obj->timer.function = hwmsen_poll;
obj->timer.data = (unsigned long)obj;
/////////////////////////////////////////////////////////////////////////////////
// 轮询函数:是在 ioctl() 中打开定时器轮询的
/////////////////////////////////////////////////////////////////////////////////
hwmsen_poll(unsigned long data)
// 调用上面注册的工作队列处理函数
queue_work(sensor_workqueue, &obj->report);
hwmsen_work_func()
input_event(obj->idev, EV_SYN, SYN_CONFIG, 0);
// 设置时间戳
memset(&sensor_data, 0, sizeof(sensor_data));
time.tv_sec = time.tv_nsec = 0;
time = get_monotonic_coarse();
nt = time.tv_sec*1000000000LL+time.tv_nsec;
/////////////////////////////////////////////
// 遍历注册的传感器【 hwmsen_attach() 注册 】
for(idx = 0; idx < MAX_ANDROID_SENSOR_NUM; idx++)
// Interrupt sensor
///////////////////////////////////////////////////
// 如果查看的传感器是中断模式上报数据的,跳过,不需要轮询
// 因为传感感会在自己的中断函数内主动上报数据
if(cxt->obj.polling == 0)
if(obj_data.data_updata[idx] == 1)
event_type |= (1 << idx);
obj_data.data_updata[idx] = 0;
continue;
/////////////////////////////////////////////////////
// 对于非中断上报数据的传感器进行轮询上报数据
// 添加具体 sensor 数据的延时上报支持
//added to surpport set delay to specified sensor
if(cxt->delayCount > 0)
cxt->delayCount--;
if(0 == cxt->delayCount)
cxt->delayCount = cxt->delayCountSet;
else
continue;
//////////////////////////////////////////////////////////////////////////////////////////////
// 调用具体的传感器驱动函数获取数据
cxt->obj.sensor_operate(cxt->obj.self,SENSOR_GET_DATA, NULL, 0, &sensor_data, sizeof(hwm_sensor_data), &out_size);
///////////////////////////////////////////////////////////////////////////////////////////////
// 如果是光感、压力、距离或温度传感器,数据保存在 sensor_data.values[0]
if((idx == ID_LIGHT) ||(idx == ID_PRESSURE) ||(idx == ID_PROXIMITY) || (idx == ID_TEMPRERATURE))
// data changed, update the data
if(sensor_data.values[0] != obj_data.sensors_data[idx].values[0])
obj_data.sensors_data[idx].values[0] = sensor_data.values[0];
obj_data.sensors_data[idx].value_divide = sensor_data.value_divide;
obj_data.sensors_data[idx].status = sensor_data.status;
obj_data.sensors_data[idx].time = nt;
event_type |= (1 << idx);
else
// 获得其他传感器数据
// data changed, update the data
if((sensor_data.values[0] != obj_data.sensors_data[idx].values[0])
|| (sensor_data.values[1] != obj_data.sensors_data[idx].values[1])
|| (sensor_data.values[2] != obj_data.sensors_data[idx].values[2]))
if( 0 == sensor_data.values[0] && 0==sensor_data.values[1] && 0 == sensor_data.values[2])
continue;
obj_data.sensors_data[idx].values[0] = sensor_data.values[0];
obj_data.sensors_data[idx].values[1] = sensor_data.values[1];
obj_data.sensors_data[idx].values[2] = sensor_data.values[2];
obj_data.sensors_data[idx].value_divide = sensor_data.value_divide;
obj_data.sensors_data[idx].status = sensor_data.status;
obj_data.sensors_data[idx].time = nt;
event_type |= (1 << idx);
// 如果是再次使能,判断是不是第一次,先过滤掉第一个无效数据
if(enable_again == true)
。。。
///////////////////////////////////////////////////////////////////////////
// 如果数据有更新,通过 Input 更新数据
if(event_type != 0)
input_report_rel(obj->idev, EVENT_TYPE_SENSOR, event_type);
input_sync(obj->idev);//modified
//////////////////////////////////////////////////////////////////////////
// 如果是轮询模式,则重置定时器
if(obj->dc->polling_running == 1)
mod_timer(&obj->timer, jiffies + atomic_read(&obj->delay)/(1000/HZ));
// 分配输入设备
hwm_obj->idev = input_allocate_device();
// 设置输入上报事件类型
set_bit(EV_REL, hwm_obj->idev->evbit);
set_bit(EV_SYN, hwm_obj->idev->evbit);
input_set_capability(hwm_obj->idev, EV_REL, EVENT_TYPE_SENSOR);
// 注册输入设备
input_register_device(hwm_obj->idev)
// 注册杂项设备
hwm_obj->mdev.minor = MISC_DYNAMIC_MINOR;
hwm_obj->mdev.name = HWM_SENSOR_DEV_NAME;
hwm_obj->mdev.fops = &hwmsen_fops;
misc_register(&hwm_obj->mdev)
// 注册 sys 系统入口
hwmsen_create_attr(hwm_obj->mdev.this_device)
// 注册电源管理
atomic_set(&(hwm_obj->early_suspend), 0);
hwm_obj->early_drv.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING - 1,
hwm_obj->early_drv.suspend = hwmsen_early_suspend,
hwm_obj->early_drv.resume = hwmsen_late_resume,
register_early_suspend(&hwm_obj->early_drv);
// 自动检测加速度传感器
#if defined(MTK_AUTO_DETECT_ACCELEROMETER)
platform_driver_register(&gsensor_driver)
#endif
// 自动检测陀螺仪
#if defined(MTK_AUTO_DETECT_MAGNETOMETER)
platform_driver_register(&msensor_driver)
#endif
// 自动检测光感
#if defined(MTK_AUTO_DETECT_ALSPS)
platform_driver_register(&alsps_sensor_driver)
// 实现方式:上同
static struct platform_driver alsps_sensor_driver = {
.probe = alsps_sensor_probe,
.remove = hwmsen_alsps_sensor_remove,
.driver =
{
.name = "als_ps",
}
};
// 匹配后执行
static int alsps_sensor_probe(struct platform_device *pdev)
{
int i =0;
int err=0;
HWM_LOG(" als_ps sensor_probe +\n");
for(i = 0; i < MAX_CHOOSE_G_NUM; i++)
{
if(NULL != alsps_init_list[i])
{
////////////////////////////////////////////////
// 核心:调用所有传感器的初始化程序,返回第一个初始化成功的
err = alsps_init_list[i]->init();
if(0 == err)
{
strcpy(alsps_name,alsps_init_list[i]->name);
HWM_LOG(" alsps sensor %s probe ok\n", alsps_name);
break;
}
}
}
return 0;
}
#endif
*/
/* alps/ALPS_SW/TRUNK/MAIN/alps/kernel/drivers/hwmon/mt6516/hwmsen_dev.c
*
* (C) Copyright 2009
* MediaTek
*
* Sensor devices
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//add for fix resume issue
#include
#include
//add for fix resume issue end
#include
#define SENSOR_INVALID_VALUE -1
#define MAX_CHOOSE_G_NUM 5
#define MAX_CHOOSE_M_NUM 5
static void hwmsen_early_suspend(struct early_suspend *h);
static void hwmsen_late_resume(struct early_suspend *h);
static void update_workqueue_polling_rate(int newDelay);
static struct workqueue_struct * sensor_workqueue = NULL;
/******************************************************************************
* structure / enumeration / macro / definition
*****************************************************************************/
struct sensor_delay
{
int handle;
uint32_t delay;
};
struct hwmsen_context { /*sensor context*/
atomic_t enable;
atomic_t delay;
uint32_t delayCountSet;
uint32_t delayCount;
struct hwmsen_object obj;
};
#if defined(MTK_AUTO_DETECT_ACCELEROMETER)
static char gsensor_name[25];
static struct sensor_init_info* gsensor_init_list[MAX_CHOOSE_G_NUM]= {0}; //modified
#endif
#if defined(MTK_AUTO_DETECT_MAGNETOMETER)
static char msensor_name[25];
static struct sensor_init_info* msensor_init_list[MAX_CHOOSE_G_NUM]= {0}; //modified
#endif
#if defined(MTK_AUTO_DETECT_ALSPS)
static char alsps_name[25];
static struct sensor_init_info* alsps_init_list[MAX_CHOOSE_G_NUM]= {0}; //modified
#endif
/*----------------------------------------------------------------------------*/
struct dev_context {
int polling_running;
struct mutex lock;
struct hwmsen_context* cxt[MAX_ANDROID_SENSOR_NUM+1];
};
/*-------------Sensor daa-----------------------------------------------------*/
struct hwmsen_data{
hwm_sensor_data sensors_data[MAX_ANDROID_SENSOR_NUM+1];
int data_updata[MAX_ANDROID_SENSOR_NUM+1];
struct mutex lock;
};
/*----------------------------------------------------------------------------*/
typedef enum {
HWM_TRC_REPORT_NUM = 0x0001,
HWM_TRC_REPORT_EVT = 0x0002,
HWM_TRC_REPORT_INF = 0X0004,
} HWM_TRC;
/*----------------------------------------------------------------------------*/
#define C_MAX_OBJECT_NUM 1
struct hwmdev_object {
struct input_dev *idev;
struct miscdevice mdev;
struct dev_context *dc;
struct work_struct report;
atomic_t delay; /*polling period for reporting input event*/
atomic_t wake; /*user-space request to wake-up, used with stop*/
struct timer_list timer; /* polling timer */
atomic_t trace;
uint32_t active_sensor; // Active, but hwmsen don't need data sensor. Maybe other need it's data.
uint32_t active_data_sensor; // Active and hwmsen need data sensor.
//add for fix resume issue
struct early_suspend early_drv;
struct wake_lock read_data_wake_lock;
atomic_t early_suspend;
//add for fix resume end
};
static bool enable_again = false;
static struct hwmdev_object *hwm_obj = NULL;
/******************************************************************************
* static variables
*****************************************************************************/
static struct hwmsen_data obj_data ={
.lock =__MUTEX_INITIALIZER(obj_data.lock),
};
static struct dev_context dev_cxt = {
.lock = __MUTEX_INITIALIZER(dev_cxt.lock),
};
/*----------------------------------------------------------------------------*/
/******************************************************************************
* Local functions
*****************************************************************************/
static void hwmsen_work_func(struct work_struct *work)
{
//HWM_LOG("+++++++++++++++++++++++++hwmsen_work_func workqueue performed!+++++++++++++++++++++++++++++\n");
//struct hwmdev_object *obj = container_of(work, struct hwmdev_object, report);
struct hwmdev_object *obj = hwm_obj;
struct hwmsen_context *cxt = NULL;
int out_size;
hwm_sensor_data sensor_data;
uint32_t event_type = 0;
int64_t nt;
struct timespec time;
int err, idx;
//int trc = atomic_read(&obj->trace);
if (obj == NULL)
{
HWM_ERR("obj point is NULL!\n");
return;
}
if(atomic_read(&obj->wake))
{
input_event(obj->idev, EV_SYN, SYN_CONFIG, 0);
atomic_set(&obj->wake, 0);
return;
}
memset(&sensor_data, 0, sizeof(sensor_data));
time.tv_sec = time.tv_nsec = 0;
time = get_monotonic_coarse();
nt = time.tv_sec*1000000000LL+time.tv_nsec;
//mutex_lock(&obj_data.lock);
for(idx = 0; idx < MAX_ANDROID_SENSOR_NUM; idx++)
{
cxt = obj->dc->cxt[idx];
if((cxt == NULL) || (cxt->obj.sensor_operate == NULL)
|| !(obj->active_data_sensor&(0x01<obj.polling == 0)
{
if(obj_data.data_updata[idx] == 1)
{
mutex_lock(&obj_data.lock);
event_type |= (1 << idx);
obj_data.data_updata[idx] = 0;
mutex_unlock(&obj_data.lock);
}
continue;
}
//added to surpport set delay to specified sensor
if(cxt->delayCount > 0)
{
//HWM_LOG("sensor(%d) delayCount = %d\n",idx,cxt->delayCount);
cxt->delayCount--;
if(0 == cxt->delayCount)
{
cxt->delayCount = cxt->delayCountSet;
//HWM_LOG("sensor(%d) go to get data\n",idx);
}
else
{
//HWM_LOG("sensor(%d) wait for next work\n",idx);
continue;
}
}
err = cxt->obj.sensor_operate(cxt->obj.self,SENSOR_GET_DATA, NULL, 0,
&sensor_data, sizeof(hwm_sensor_data), &out_size);
if(err)
{
HWM_ERR("get data from sensor (%d) fails!!\n", idx);
continue;
}
else
{
if((idx == ID_LIGHT) ||(idx == ID_PRESSURE)
||(idx == ID_PROXIMITY) || (idx == ID_TEMPRERATURE))
{
// data changed, update the data
if(sensor_data.values[0] != obj_data.sensors_data[idx].values[0])
{
mutex_lock(&obj_data.lock);
obj_data.sensors_data[idx].values[0] = sensor_data.values[0];
obj_data.sensors_data[idx].value_divide = sensor_data.value_divide;
obj_data.sensors_data[idx].status = sensor_data.status;
obj_data.sensors_data[idx].time = nt;
event_type |= (1 << idx);
mutex_unlock(&obj_data.lock);
//HWM_LOG("get %d sensor, values: %d!\n", idx, sensor_data.values[0]);
}
}
else
{
// data changed, update the data
if((sensor_data.values[0] != obj_data.sensors_data[idx].values[0])
|| (sensor_data.values[1] != obj_data.sensors_data[idx].values[1])
|| (sensor_data.values[2] != obj_data.sensors_data[idx].values[2]))
{
if( 0 == sensor_data.values[0] && 0==sensor_data.values[1]
&& 0 == sensor_data.values[2])
{
continue;
}
mutex_lock(&obj_data.lock);
obj_data.sensors_data[idx].values[0] = sensor_data.values[0];
obj_data.sensors_data[idx].values[1] = sensor_data.values[1];
obj_data.sensors_data[idx].values[2] = sensor_data.values[2];
obj_data.sensors_data[idx].value_divide = sensor_data.value_divide;
obj_data.sensors_data[idx].status = sensor_data.status;
obj_data.sensors_data[idx].time = nt;
event_type |= (1 << idx);
mutex_unlock(&obj_data.lock);
//HWM_LOG("get %d sensor, values: %d, %d, %d!\n", idx,
//sensor_data.values[0], sensor_data.values[1], sensor_data.values[2]);
}
}
}
}
//
//mutex_unlock(&obj_data.lock);
if(enable_again == true)
{
event_type = obj->active_data_sensor;
enable_again = false;
//filter -1 value
for(idx = 0; idx <= MAX_ANDROID_SENSOR_NUM; idx++)
{
if(ID_ACCELEROMETER==idx || ID_MAGNETIC==idx || ID_ORIENTATION==idx
||ID_GYROSCOPE==idx || ID_TEMPRERATURE==idx
||ID_LINEAR_ACCELERATION==idx || ID_ROTATION_VECTOR==idx
||ID_GRAVITY==idx)
{
if(SENSOR_INVALID_VALUE == obj_data.sensors_data[idx].values[0] ||
SENSOR_INVALID_VALUE == obj_data.sensors_data[idx].values[1] ||
SENSOR_INVALID_VALUE == obj_data.sensors_data[idx].values[2])
{
event_type &= ~(1 << idx);
//HWM_LOG("idx=%d,obj->active_sensor after clear: %d\n",idx);
}
}
if(ID_PROXIMITY==idx || ID_LIGHT==idx || ID_PRESSURE==idx)
{
if(SENSOR_INVALID_VALUE == obj_data.sensors_data[idx].values[0])
{
event_type &= ~(1 << idx);
//HWM_LOG("idx=%d,obj->active_sensor after clear: %d\n",idx);
}
}
}
//HWM_LOG("event type after enable: %d\n", event_type);
}
if((event_type&(1 << ID_PROXIMITY))&& SENSOR_INVALID_VALUE == obj_data.sensors_data[ID_PROXIMITY].values[0])
{
event_type &= ~(1 << ID_PROXIMITY);
//HWM_LOG("remove ps event!!!!!!!!!!!\n");
}
if(event_type != 0)
{
input_report_rel(obj->idev, EVENT_TYPE_SENSOR, event_type);
input_sync(obj->idev);//modified
//HWM_LOG("event type: %d\n", event_type);
}
else
{
//HWM_LOG("no available sensor!!\n");
}
if(obj->dc->polling_running == 1)
{
mod_timer(&obj->timer, jiffies + atomic_read(&obj->delay)/(1000/HZ));
}
}
/******************************************************************************
* export functions
*****************************************************************************/
int hwmsen_get_interrupt_data(int sensor, hwm_sensor_data *data)
{
//HWM_LOG("++++++++++++++++++++++++++++hwmsen_get_interrupt_data function sensor = %d\n",sensor);
struct dev_context *mcxt = &dev_cxt;
struct hwmdev_object *obj = hwm_obj;
int64_t nt;
struct timespec time;
if((sensor > MAX_ANDROID_SENSOR_NUM) || (mcxt->cxt[sensor] == NULL)
|| (mcxt->cxt[sensor]->obj.polling != 0))
{
HWM_ERR("sensor %d!\n", sensor);
return -EINVAL;
}
else
{
time.tv_sec = time.tv_nsec = 0;
time = get_monotonic_coarse();
nt = time.tv_sec*1000000000LL+time.tv_nsec;
if((sensor == ID_LIGHT) ||(sensor == ID_PRESSURE)
||(sensor == ID_PROXIMITY) || (sensor == ID_TEMPRERATURE))
{
// data changed, update the data
if(data->values[0] != obj_data.sensors_data[sensor].values[0])
{
mutex_lock(&obj_data.lock);
obj_data.data_updata[sensor] = 1;
obj_data.sensors_data[sensor].values[0] = data->values[0];
obj_data.sensors_data[sensor].time = nt;
obj_data.sensors_data[sensor].value_divide = data->value_divide;
mutex_unlock(&obj_data.lock);
}
}
else
{
// data changed, update the data
if((data->values[0] != obj_data.sensors_data[sensor].values[0])
|| (data->values[1] != obj_data.sensors_data[sensor].values[1])
|| (data->values[2] != obj_data.sensors_data[sensor].values[2]))
{
mutex_lock(&obj_data.lock);
obj_data.sensors_data[sensor].values[0] = data->values[0];
obj_data.sensors_data[sensor].values[1] = data->values[1];
obj_data.sensors_data[sensor].values[2] = data->values[2];
obj_data.sensors_data[sensor].value_divide = data->value_divide;
obj_data.data_updata[sensor] = 1;
obj_data.sensors_data[sensor].time = nt;
mutex_unlock(&obj_data.lock);
}
}
if(obj->dc->polling_running == 1)
{
hwmsen_work_func(NULL);
}
return 0;
}
}
/*----------------------------------------------------------------------------*/
EXPORT_SYMBOL_GPL(hwmsen_get_interrupt_data);
/*----------------------------------------------------------------------------*/
static void hwmsen_poll(unsigned long data)
{
struct hwmdev_object *obj = (struct hwmdev_object *)data;
if(obj != NULL)
{
queue_work(sensor_workqueue, &obj->report);
}
}
/*----------------------------------------------------------------------------*/
static struct hwmdev_object *hwmsen_alloc_object(void)
{
struct hwmdev_object *obj = kzalloc(sizeof(*obj), GFP_KERNEL);
HWM_FUN(f);
if(!obj)
{
HWM_ERR("Alloc hwmsen object error!\n");
return NULL;
}
obj->dc = &dev_cxt;
obj->active_data_sensor = 0;
obj->active_sensor = 0;
atomic_set(&obj->delay, 200); /*5Hz*/// set work queue delay time 200ms
atomic_set(&obj->wake, 0);
sensor_workqueue = create_singlethread_workqueue("sensor_polling");
INIT_WORK(&obj->report, hwmsen_work_func);
init_timer(&obj->timer);
obj->timer.expires = jiffies + atomic_read(&obj->delay)/(1000/HZ);
obj->timer.function = hwmsen_poll;
obj->timer.data = (unsigned long)obj;
return obj;
}
/*Sensor device driver attach to hwmsen device------------------------------------------------*/
int hwmsen_attach(int sensor, struct hwmsen_object *obj)
{
struct dev_context *mcxt = &dev_cxt;
int err = 0;
HWM_FUN(f);
if((mcxt == NULL) || (sensor > MAX_ANDROID_SENSOR_NUM))
{
err = -EINVAL;
goto err_exit;
}
mutex_lock(&mcxt->lock);
if(mcxt->cxt[sensor] != NULL)
{
err = -EEXIST;
goto err_exit;
}
else
{
mcxt->cxt[sensor] = kzalloc(sizeof(struct hwmsen_context), GFP_KERNEL);
if(mcxt->cxt[sensor] == NULL)
{
err = -EPERM;
goto err_exit;
}
atomic_set(&mcxt->cxt[sensor]->enable, 0);
memcpy(&mcxt->cxt[sensor]->obj, obj, sizeof(*obj));
// add for android2.3 set sensors default polling delay time is 200ms
atomic_set(&mcxt->cxt[sensor]->delay, 200);
}
err_exit:
mutex_unlock(&mcxt->lock);
return err;
}
/*----------------------------------------------------------------------------*/
EXPORT_SYMBOL_GPL(hwmsen_attach);
/*----------------------------------------------------------------------------*/
int hwmsen_detach(int sensor)
{
int err = 0;
struct dev_context *mcxt = &dev_cxt;
HWM_FUN(f);
if ((sensor > MAX_ANDROID_SENSOR_NUM) || (mcxt->cxt[sensor] == NULL))
{
err = -EINVAL;
goto err_exit;
}
mutex_lock(&mcxt->lock);
kfree(mcxt->cxt[sensor]);
mcxt->cxt[sensor] = NULL;
err_exit:
mutex_unlock(&mcxt->lock);
return 0;
}
/*----------------------------------------------------------------------------*/
EXPORT_SYMBOL_GPL(hwmsen_detach);
/*----------------------------------------------------------------------------*/
static int hwmsen_enable(struct hwmdev_object *obj, int sensor, int enable)
{
struct hwmsen_context *cxt = NULL;
int err = 0;
uint32_t sensor_type;
sensor_type = 1 << sensor;
if(!obj)
{
HWM_ERR("hwmdev obj pointer is NULL!\n");
return -EINVAL;
}
else if(obj->dc->cxt[sensor] == NULL)
{
HWM_ERR("the sensor (%d) is not attached!!\n", sensor);
return -ENODEV;
}
mutex_lock(&obj->dc->lock);
cxt = obj->dc->cxt[sensor];
if(enable == 1)
{
//{@for mt6582 blocking issue work around
if(sensor == 7){
HWM_LOG("P-sensor disable LDO low power\n");
pmic_ldo_suspend_enable(0);
}
//@}
enable_again = true;
obj->active_data_sensor |= sensor_type;
if((obj->active_sensor & sensor_type) == 0) // no no-data active
{
if (cxt->obj.sensor_operate(cxt->obj.self, SENSOR_ENABLE, &enable,sizeof(int), NULL, 0, NULL) != 0)
{
if (cxt->obj.sensor_operate(cxt->obj.self, SENSOR_ENABLE, &enable,sizeof(int), NULL, 0, NULL) != 0)
{
if (cxt->obj.sensor_operate(cxt->obj.self, SENSOR_ENABLE, &enable,sizeof(int), NULL, 0, NULL) != 0)
{
HWM_ERR("activate sensor(%d) 3 times err = %d\n", sensor, err);
err = -EINVAL;
goto exit;
}
}
}
atomic_set(&cxt->enable, 1);
}
// Need to complete the interrupt sensor work
if((0 == obj->dc->polling_running) && (obj->active_data_sensor != 0))
{
obj->dc->polling_running = 1;
//obj->timer.expires = jiffies + atomic_read(&obj->delay)/(1000/HZ);
//add_timer(&obj->timer);
mod_timer(&obj->timer, jiffies + atomic_read(&obj->delay)/(1000/HZ));
}
}
else
{
//{@for mt6582 blocking issue work around
if(sensor == 7){
HWM_LOG("P-sensor enable LDO low power\n");
pmic_ldo_suspend_enable(1);
}
//@}
obj->active_data_sensor &= ~sensor_type;
if((obj->active_sensor & sensor_type) == 0) // no no-data active
{
if(cxt->obj.sensor_operate(cxt->obj.self, SENSOR_ENABLE, &enable,sizeof(int), NULL, 0, NULL) != 0)
{
HWM_ERR("deactiva sensor(%d) err = %d\n", sensor, err);
err = -EINVAL;
goto exit;
}
atomic_set(&cxt->enable, 0);
update_workqueue_polling_rate(200);// re-update workqueue polling rate
}
if((1 == obj->dc->polling_running) && (obj->active_data_sensor == 0))
{
obj->dc->polling_running = 0;
del_timer_sync(&obj->timer);
cancel_work_sync(&obj->report);
}
obj_data.sensors_data[sensor].values[0] = SENSOR_INVALID_VALUE;
obj_data.sensors_data[sensor].values[1] = SENSOR_INVALID_VALUE;
obj_data.sensors_data[sensor].values[2] = SENSOR_INVALID_VALUE;
}
HWM_LOG("sensor(%d), flag(%d)\n", sensor, enable);
exit:
mutex_unlock(&obj->dc->lock);
return err;
}
/*-------------no data sensor enable/disable--------------------------------------*/
static int hwmsen_enable_nodata(struct hwmdev_object *obj, int sensor, int enable)
{
struct hwmsen_context *cxt = NULL;
int err = 0;
uint32_t sensor_type;
HWM_FUN(f);
sensor_type = 1 << sensor;
if(NULL == obj)
{
HWM_ERR("hwmdev obj pointer is NULL!\n");
return -EINVAL;
}
else if(obj->dc->cxt[sensor] == NULL)
{
HWM_ERR("the sensor (%d) is not attached!!\n", sensor);
return -ENODEV;
}
mutex_lock(&obj->dc->lock);
cxt = obj->dc->cxt[sensor];
if(enable == 1)
{
obj->active_sensor |= sensor_type;
if((obj->active_data_sensor & sensor_type) == 0) // no data active
{
if(cxt->obj.sensor_operate(cxt->obj.self, SENSOR_ENABLE, &enable, sizeof(int), NULL, 0, NULL) != 0)
{
HWM_ERR("activate sensor(%d) err = %d\n", sensor, err);
err = -EINVAL;
goto exit;
}
atomic_set(&cxt->enable, 1);
}
}
else
{
obj->active_sensor &= ~sensor_type;
if((obj->active_data_sensor & sensor_type) == 0) // no data active
{
if(cxt->obj.sensor_operate(cxt->obj.self, SENSOR_ENABLE, &enable,sizeof(int), NULL, 0, NULL) != 0)
{
HWM_ERR("Deactivate sensor(%d) err = %d\n", sensor, err);
err = -EINVAL;
goto exit;
}
atomic_set(&cxt->enable, 0);
}
}
exit:
mutex_unlock(&obj->dc->lock);
return err;
}
/*------------set delay--------------------------------------------------------*/
static int hwmsen_set_delay(int delay, int handle )
{
int err = 0;
struct hwmsen_context *cxt = NULL;
cxt = hwm_obj->dc->cxt[handle];
if(NULL == cxt ||(cxt->obj.sensor_operate == NULL))
{
HWM_ERR("have no this sensor %d or operator point is null!\r\n", handle);
}
else if(atomic_read(&cxt->enable) != 0)
{
if(cxt->obj.sensor_operate(cxt->obj.self, SENSOR_DELAY, &delay,sizeof(int), NULL, 0, NULL) != 0)
{
HWM_ERR("%d sensor's sensor_operate function error %d!\r\n",handle,err);
return err;
}
//record sensor delay
atomic_set(&cxt->delay, delay);
}
return err;
}
/*----------------------------------------------------------------------------*/
static int hwmsen_wakeup(struct hwmdev_object *obj)
{
HWM_FUN(f);
if(obj == NULL)
{
HWM_ERR("null pointer!!\n");
return -EINVAL;
}
input_event(obj->idev, EV_SYN, SYN_CONFIG, 0);
return 0;
}
/*----------------------------------------------------------------------------*/
static ssize_t hwmsen_show_hwmdev(struct device* dev,
struct device_attribute *attr, char *buf)
{
//struct hwmdev_object *devobj = (struct hwmdev_object*)dev_get_drvdata(dev);
int len = 0;
printk("sensor test: hwmsen_show_hwmdev function!\n");
/*
if (!devobj || !devobj->dc) {
HWM_ERR("null pointer: %p, %p", devobj, (!devobj) ? (NULL) : (devobj->dc));
return 0;
}
for (idx = 0; idx < C_MAX_HWMSEN_NUM; idx++)
len += snprintf(buf+len, PAGE_SIZE-len, " %d", idx);
len += snprintf(buf+len, PAGE_SIZE-len, "\n");
for (idx = 0; idx < C_MAX_HWMSEN_NUM; idx++)
len += snprintf(buf+len, PAGE_SIZE-len, " %d", atomic_read(&devobj->dc->cxt[idx].enable));
len += snprintf(buf+len, PAGE_SIZE-len, "\n");
*/
return len;
}
/*----------------------------------------------------------------------------*/
static ssize_t hwmsen_store_active(struct device* dev, struct device_attribute *attr,
const char *buf, size_t count)
{
/*
printk("sensor test: hwmsen_store_active function!\n");
struct hwmdev_object *devobj = (struct hwmdev_object*)dev_get_drvdata(dev);
int sensor, enable, err, idx;
if (!devobj || !devobj->dc) {
HWM_ERR("null pointer!!\n");
return count;
}
if (!strncmp(buf, "all-start", 9)) {
for (idx = 0; idx < C_MAX_HWMSEN_NUM; idx++)
hwmsen_enable(devobj, idx, 1);
} else if (!strncmp(buf, "all-stop", 8)) {
for (idx = 0; idx < C_MAX_HWMSEN_NUM; idx++)
hwmsen_enable(devobj, idx, 0);
} else if (2 == sscanf(buf, "%d %d", &sensor, &enable)) {
if ((err = hwmsen_enable(devobj, sensor, enable)))
HWM_ERR("sensor enable failed: %d\n", err);
}
*/
return count;
}
/*----------------------------------------------------------------------------*/
static ssize_t hwmsen_show_delay(struct device* dev,
struct device_attribute *attr, char *buf)
{
/*
struct hwmdev_object *devobj = (struct hwmdev_object*)dev_get_drvdata(dev);
printk("sensor test: hwmsen_show_delay function!\n");
if (!devobj || !devobj->dc) {
HWM_ERR("null pointer!!\n");
return 0;
}
return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&devobj->delay));
*/
return 0;
}
/*----------------------------------------------------------------------------*/
static ssize_t hwmsen_store_delay(struct device* dev, struct device_attribute *attr,
const char *buf, size_t count)
{
/*
struct hwmdev_object *devobj = (struct hwmdev_object*)dev_get_drvdata(dev);
int delay;
printk("sensor test: hwmsen_show_delay function!\n");
if (!devobj || !devobj->dc) {
HWM_ERR("null pointer!!\n");
return count;
}
if (1 != sscanf(buf, "%d", &delay)) {
HWM_ERR("invalid format!!\n");
return count;
}
atomic_set(&devobj->delay, delay);
*/
return count;
}
/*----------------------------------------------------------------------------*/
static ssize_t hwmsen_show_wake(struct device* dev,
struct device_attribute *attr, char *buf)
{
/*
printk("sensor test: hwmsen_show_wake function!\n");
struct hwmdev_object *devobj = (struct hwmdev_object*)dev_get_drvdata(dev);
if (!devobj || !devobj->dc) {
HWM_ERR("null pointer!!\n");
return 0;
}
return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&devobj->wake));
*/
return 0;
}
/*----------------------------------------------------------------------------*/
static ssize_t hwmsen_store_wake(struct device* dev, struct device_attribute *attr,
const char *buf, size_t count)
{
/*
struct hwmdev_object *devobj = (struct hwmdev_object*)dev_get_drvdata(dev);
int wake, err;
printk("sensor test: hwmsen_store_wake function!\n");
if (!devobj || !devobj->dc) {
HWM_ERR("null pointer!!\n");
return count;
}
if (1 != sscanf(buf, "%d", &wake)) {
HWM_ERR("invalid format!!\n");
return count;
}
if ((err = hwmsen_wakeup(devobj))) {
HWM_ERR("wakeup sensor fail, %d\n", err);
return count;
}
*/
return count;
}
/*----------------------------------------------------------------------------*/
static ssize_t hwmsen_show_trace(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct hwmdev_object *obj = i2c_get_clientdata(client);
HWM_FUN(f);
return snprintf(buf, PAGE_SIZE, "0x%08X\n", atomic_read(&obj->trace));
}
/*----------------------------------------------------------------------------*/
static ssize_t hwmsen_store_trace(struct device* dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct hwmdev_object *obj = i2c_get_clientdata(client);
int trc;
HWM_FUN(f);
if (1 == sscanf(buf, "0x%x\n", &trc))
{
atomic_set(&obj->trace, trc);
}
else
{
HWM_ERR("set trace level fail!!\n");
}
return count;
}
/*----------------------------------------------------------------------------*/
DEVICE_ATTR(hwmdev, S_IWUSR | S_IRUGO, hwmsen_show_hwmdev, NULL);
DEVICE_ATTR(active, S_IWUSR | S_IRUGO, hwmsen_show_hwmdev, hwmsen_store_active);
DEVICE_ATTR(delay, S_IWUSR | S_IRUGO, hwmsen_show_delay, hwmsen_store_delay);
DEVICE_ATTR(wake, S_IWUSR | S_IRUGO, hwmsen_show_wake, hwmsen_store_wake);
DEVICE_ATTR(trace, S_IWUSR | S_IRUGO, hwmsen_show_trace, hwmsen_store_trace);
/*----------------------------------------------------------------------------*/
static struct device_attribute *hwmsen_attr_list[] =
{
&dev_attr_hwmdev,
&dev_attr_active,
&dev_attr_delay,
&dev_attr_wake,
&dev_attr_trace,
};
/*----------------------------------------------------------------------------*/
static int hwmsen_create_attr(struct device *dev)
{
int idx, err = 0;
int num = (int)(sizeof(hwmsen_attr_list)/sizeof(hwmsen_attr_list[0]));
HWM_FUN();
if(!dev)
{
return -EINVAL;
}
for(idx = 0; idx < num; idx++)
{
if((err = device_create_file(dev, hwmsen_attr_list[idx])))
{
HWM_ERR("device_create_file (%s) = %d\n", hwmsen_attr_list[idx]->attr.name, err);
break;
}
}
return err;
}
/*----------------------------------------------------------------------------*/
static int hwmsen_delete_attr(struct device *dev)
{
int idx ,err = 0;
int num = (int)(sizeof(hwmsen_attr_list)/sizeof(hwmsen_attr_list[0]));
HWM_FUN(f);
if (!dev)
{
return -EINVAL;
}
for (idx = 0; idx < num; idx++)
{
device_remove_file(dev, hwmsen_attr_list[idx]);
}
return err;
}
/*----------------------------------------------------------------*/
static int init_static_data(void)
{
int i = 0;
// memset(&obj_data, 0, sizeof(struct hwmsen_data));
// obj_data.lock = __MUTEX_INITIALIZER(obj_data.lock);
for(i=0; i < MAX_ANDROID_SENSOR_NUM; i++)
{
dev_cxt.cxt[i] = NULL;
memset(&obj_data.sensors_data[i], SENSOR_INVALID_VALUE, sizeof(hwm_sensor_data));
obj_data.sensors_data[i].sensor = i;
}
return 0;
}
/*----------------------------------------------------------------*/
static int hwmsen_open(struct inode *node , struct file *fp)
{
HWM_FUN(f);
//struct file_private* data = kzalloc(sizeof(struct file_private), GFP_KERNEL);
// fp->private_data = data;
fp->private_data = NULL;
return nonseekable_open(node,fp);
}
/*----------------------------------------------------------------------------*/
static int hwmsen_release(struct inode *node, struct file *fp)
{
HWM_FUN(f);
kfree(fp->private_data);
fp->private_data = NULL;
return 0;
}
/*----------------------------------------------------------------------------*/
static void update_workqueue_polling_rate(int newDelay)
{
atomic_t delaytemp;
int i=0;
int idx=0;
struct hwmsen_context *cxt = NULL;
struct hwmdev_object *obj = hwm_obj;
HWM_FUN(f);
atomic_set(&delaytemp, 200);//used to finding fastest sensor polling rate
for(i = 0; i < MAX_ANDROID_SENSOR_NUM; i++)
{
if(hwm_obj->active_data_sensor & 1< atomic_read(&(hwm_obj->dc->cxt[i]->delay)))
{
atomic_set(&delaytemp, atomic_read(&(hwm_obj->dc->cxt[i]->delay)));// work queue polling delay base time
}
}
}
//use the fastest sensor polling delay as work queue polling delay base time
if(atomic_read(&delaytemp) > newDelay)
{
atomic_set(&hwm_obj->delay, newDelay);// work queue polling delay base time
HWM_LOG("set new workqueue base time=%d\n",atomic_read(&hwm_obj->delay));
}
else
{
atomic_set(&hwm_obj->delay, atomic_read(&delaytemp));
HWM_LOG("set old fastest sensor delay as workqueue base time=%d\n",atomic_read(&hwm_obj->delay));
}
//upadate all sensors delayCountSet
for(idx = 0; idx < MAX_ANDROID_SENSOR_NUM; idx++)
{
cxt = obj->dc->cxt[idx];
if((cxt == NULL) || (cxt->obj.sensor_operate == NULL)
|| !(obj->active_data_sensor&(0x01<delay))
{
cxt->delayCount = cxt->delayCountSet = 0;
HWM_LOG("%s,set delayCountSet=0 delay =%d handle=%d\r\n",__func__, atomic_read(&cxt->delay), idx);
}
if(atomic_read(&cxt->delay) <= atomic_read(&hwm_obj->delay))
{
cxt->delayCount = cxt->delayCountSet = 0;
HWM_LOG("%s,set delayCountSet=0 delay =%d handle=%d\r\n",__func__, atomic_read(&cxt->delay), idx);
}
else
{
i= atomic_read(&cxt->delay)/atomic_read(&hwm_obj->delay);
cxt->delayCount = cxt->delayCountSet = i;
HWM_LOG("%s:set delayCountSet=%d delay =%d handle=%d\r\n",__func__, i, atomic_read(&cxt->delay), idx);
#if 0
switch(i)
{
case 3:
// 200/60 ;60/20
cxt->delayCount = cxt->delayCountSet = 3;
HWM_LOG("%s:set delayCountSet=3 delay =%d handle=%d\r\n",__func__,atomic_read(&cxt->delay), idx);
break;
case 10:
// 200/20
cxt->delayCount = cxt->delayCountSet = 10;
HWM_LOG("%s:set delayCountSet=10 delay =%d handle=%d\r\n",__func__, atomic_read(&cxt->delay), idx);
break;
}
#endif
}
}
}
//static int hwmsen_ioctl(struct inode *node, struct file *fp,
// unsigned int cmd, unsigned long arg)
static long hwmsen_unlocked_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
//HWM_LOG("IO parament %d!\r\n", cmd);
void __user *argp = (void __user*)arg;
uint32_t flag;
struct sensor_delay delayPara;
hwm_trans_data hwm_sensors_data;
int i = 0;
atomic_t delaytemp;
atomic_set(&delaytemp, 200);//used to finding fastest sensor polling rate
//int delaytemp=200;//used to finding fastest sensor polling rate
if(!hwm_obj)
{
HWM_ERR("null pointer!!\n");
return -EINVAL;
}
switch(cmd)
{
case HWM_IO_SET_DELAY:
// android2.3 sensor system has 4 sample delay 0ms 20ms 60ms 200ms
if(copy_from_user(&delayPara, argp, sizeof(delayPara)))
{
HWM_ERR("copy_from_user fail!!\n");
return -EFAULT;
}
HWM_LOG("ioctl delay handle=%d,delay =%d\n",delayPara.handle,delayPara.delay);
hwmsen_set_delay(delayPara.delay,delayPara.handle);//modified for android2.3
update_workqueue_polling_rate(delayPara.delay);
break;
case HWM_IO_SET_WAKE:
hwmsen_wakeup(hwm_obj);
break;
case HWM_IO_ENABLE_SENSOR:
if(copy_from_user(&flag, argp, sizeof(flag)))
{
HWM_ERR("copy_from_user fail!!\n");
return -EFAULT;
}
hwmsen_enable(hwm_obj, flag, 1);
break;
case HWM_IO_DISABLE_SENSOR:
if(copy_from_user(&flag, argp, sizeof(flag)))
{
HWM_ERR("copy_from_user fail!!\n");
return -EFAULT;
}
hwmsen_enable(hwm_obj, flag, 0);
break;
case HWM_IO_GET_SENSORS_DATA:
if(copy_from_user(&hwm_sensors_data, argp, sizeof(hwm_sensors_data)))
{
HWM_ERR("copy_from_user fail!!\n");
return -EFAULT;
}
mutex_lock(&obj_data.lock);
memcpy(hwm_sensors_data.data, &(obj_data.sensors_data),sizeof(hwm_sensor_data) * MAX_ANDROID_SENSOR_NUM);
for(i = 0; i < MAX_ANDROID_SENSOR_NUM; i++)
{
if(hwm_sensors_data.date_type & 1<idev = input_allocate_device();
if (!hwm_obj->idev)
{
err = -ENOMEM;
HWM_ERR("unable to allocate input device!\n");
goto exit_alloc_input_dev_failed;
}
set_bit(EV_REL, hwm_obj->idev->evbit);
set_bit(EV_SYN, hwm_obj->idev->evbit);
input_set_capability(hwm_obj->idev, EV_REL, EVENT_TYPE_SENSOR);
hwm_obj->idev->name = HWM_INPUTDEV_NAME;
if((err = input_register_device(hwm_obj->idev)))
{
HWM_ERR("unable to register input device!\n");
goto exit_input_register_device_failed;
}
input_set_drvdata(hwm_obj->idev, hwm_obj);
hwm_obj->mdev.minor = MISC_DYNAMIC_MINOR;
hwm_obj->mdev.name = HWM_SENSOR_DEV_NAME;
hwm_obj->mdev.fops = &hwmsen_fops;
if((err = misc_register(&hwm_obj->mdev)))
{
HWM_ERR("unable to register sensor device!!\n");
goto exit_misc_register_failed;
}
dev_set_drvdata(hwm_obj->mdev.this_device, hwm_obj);
if(hwmsen_create_attr(hwm_obj->mdev.this_device) != 0)
{
HWM_ERR("unable to create attributes!!\n");
goto exit_hwmsen_create_attr_failed;
}
// add for fix resume bug
atomic_set(&(hwm_obj->early_suspend), 0);
hwm_obj->early_drv.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING - 1,
hwm_obj->early_drv.suspend = hwmsen_early_suspend,
hwm_obj->early_drv.resume = hwmsen_late_resume,
register_early_suspend(&hwm_obj->early_drv);
wake_lock_init(&(hwm_obj->read_data_wake_lock),WAKE_LOCK_SUSPEND,"read_data_wake_lock");
// add for fix resume bug end
return 0;
exit_hwmsen_create_attr_failed:
exit_misc_register_failed:
// exit_get_hwmsen_info_failed:
exit_input_register_device_failed:
input_free_device(hwm_obj->idev);
exit_alloc_input_dev_failed:
kfree(hwm_obj);
exit_alloc_data_failed:
return err;
}
/*----------------------------------------------------------------------------*/
static int hwmsen_remove(struct platform_device *pdev)
{
HWM_FUN(f);
input_unregister_device(hwm_obj->idev);
hwmsen_delete_attr(hwm_obj->mdev.this_device);
misc_deregister(&hwm_obj->mdev);
kfree(hwm_obj);
return 0;
}
static void hwmsen_early_suspend(struct early_suspend *h)
{
//HWM_FUN(f);
atomic_set(&(hwm_obj->early_suspend), 1);
HWM_LOG(" hwmsen_early_suspend ok------->hwm_obj->early_suspend=%d \n",atomic_read(&hwm_obj->early_suspend));
return ;
}
/*----------------------------------------------------------------------------*/
static void hwmsen_late_resume(struct early_suspend *h)
{
//HWM_FUN(f);
atomic_set(&(hwm_obj->early_suspend), 0);
HWM_LOG(" hwmsen_late_resume ok------->hwm_obj->early_suspend=%d \n",atomic_read(&hwm_obj->early_suspend));
return ;
}
/*----------------------------------------------------------------------------*/
static int hwmsen_suspend(struct platform_device *dev, pm_message_t state)
{
//HWM_FUN(f);
return 0;
}
/*----------------------------------------------------------------------------*/
static int hwmsen_resume(struct platform_device *dev)
{
//HWM_FUN(f);
return 0;
}
/*----------------------------------------------------------------------------*/
static struct platform_driver hwmsen_driver =
{
.probe = hwmsen_probe,
.remove = hwmsen_remove,
.suspend = hwmsen_suspend,
.resume = hwmsen_resume,
.driver =
{
.name = HWM_SENSOR_DEV_NAME,
// .owner = THIS_MODULE,
}
};
/*----------------------------------------------------------------------------*/
#if defined(MTK_AUTO_DETECT_MAGNETOMETER)
int hwmsen_msensor_remove(struct platform_device *pdev)
{
int err =0;
int i=0;
for(i = 0; i < MAX_CHOOSE_G_NUM; i++)
{
if(0 == strcmp(msensor_name,msensor_init_list[i]->name))
{
if(NULL == msensor_init_list[i]->uninit)
{
HWM_LOG(" hwmsen_msensor_remove null pointer \n");
return -1;
}
msensor_init_list[i]->uninit();
}
}
return 0;
}
static int msensor_probe(struct platform_device *pdev)
{
int i =0;
int err=0;
HWM_LOG(" msensor_probe +\n");
for(i = 0; i < MAX_CHOOSE_G_NUM; i++)
{
if(NULL != msensor_init_list[i])
{
err = msensor_init_list[i]->init();
if(0 == err)
{
strcpy(msensor_name,msensor_init_list[i]->name);
HWM_LOG(" msensor %s probe ok\n", msensor_name);
break;
}
}
}
return 0;
}
static struct platform_driver msensor_driver = {
.probe = msensor_probe,
.remove = hwmsen_msensor_remove,
.driver =
{
.name = "msensor",
// .owner = THIS_MODULE,
}
};
int hwmsen_msensor_add(struct sensor_init_info* obj)
{
int err=0;
int i =0;
HWM_FUN(f);
for(i =0; i < MAX_CHOOSE_G_NUM; i++ )
{
if(NULL == msensor_init_list[i])
{
msensor_init_list[i] = kzalloc(sizeof(struct sensor_init_info), GFP_KERNEL);
if(NULL == msensor_init_list[i])
{
HWM_ERR("kzalloc error");
return -1;
}
obj->platform_diver_addr = &msensor_driver;
msensor_init_list[i] = obj;
break;
}
}
return err;
}
EXPORT_SYMBOL_GPL(hwmsen_msensor_add);
#endif
#if defined(MTK_AUTO_DETECT_ACCELEROMETER)//
int hwmsen_gsensor_remove(struct platform_device *pdev)
{
int i=0;
for(i = 0; i < MAX_CHOOSE_G_NUM; i++)
{
if(0 == strcmp(gsensor_name,gsensor_init_list[i]->name))
{
if(NULL == gsensor_init_list[i]->uninit)
{
HWM_LOG(" hwmsen_gsensor_remove null pointer +\n");
return -1;
}
gsensor_init_list[i]->uninit();
}
}
return 0;
}
static int gsensor_probe(struct platform_device *pdev)
{
int i =0;
int err=0;
HWM_LOG(" gsensor_probe +\n");
//
/*
for(i = 0; i < MAX_CHOOSE_G_NUM; i++)
{
HWM_LOG(" gsensor_init_list[i]=%d\n",gsensor_init_list[i]);
}
*/
//
for(i = 0; i < MAX_CHOOSE_G_NUM; i++)
{
HWM_LOG(" i=%d\n",i);
if(0 != gsensor_init_list[i])
{
HWM_LOG(" !!!!!!!!\n");
err = gsensor_init_list[i]->init();
if(0 == err)
{
strcpy(gsensor_name,gsensor_init_list[i]->name);
HWM_LOG(" gsensor %s probe ok\n", gsensor_name);
break;
}
}
}
if(i == MAX_CHOOSE_G_NUM)
{
HWM_LOG(" gsensor probe fail\n");
}
return 0;
}
static struct platform_driver gsensor_driver = {
.probe = gsensor_probe,
.remove = hwmsen_gsensor_remove,
.driver =
{
.name = "gsensor",
// .owner = THIS_MODULE,
}
};
int hwmsen_gsensor_add(struct sensor_init_info* obj)
{
int err=0;
int i =0;
HWM_FUN(f);
for(i =0; i < MAX_CHOOSE_G_NUM; i++ )
{
if(NULL == gsensor_init_list[i])
{
gsensor_init_list[i] = kzalloc(sizeof(struct sensor_init_info), GFP_KERNEL);
if(NULL == gsensor_init_list[i])
{
HWM_ERR("kzalloc error");
return -1;
}
obj->platform_diver_addr = &gsensor_driver;
gsensor_init_list[i] = obj;
break;
}
}
return err;
}
EXPORT_SYMBOL_GPL(hwmsen_gsensor_add);
#endif
#if defined(MTK_AUTO_DETECT_ALSPS)
int hwmsen_alsps_sensor_remove(struct platform_device *pdev)
{
int err =0;
int i=0;
for(i = 0; i < MAX_CHOOSE_G_NUM; i++)
{
if(0 == strcmp(alsps_name,alsps_init_list[i]->name))
{
if(NULL == alsps_init_list[i]->uninit)
{
HWM_LOG(" hwmsen_alsps_sensor_remove null pointer \n");
return -1;
}
alsps_init_list[i]->uninit();
}
}
return 0;
}
static int alsps_sensor_probe(struct platform_device *pdev)
{
int i =0;
int err=0;
HWM_LOG(" als_ps sensor_probe +\n");
for(i = 0; i < MAX_CHOOSE_G_NUM; i++)
{
if(NULL != alsps_init_list[i])
{
err = alsps_init_list[i]->init();
if(0 == err)
{
strcpy(alsps_name,alsps_init_list[i]->name);
HWM_LOG(" alsps sensor %s probe ok\n", alsps_name);
break;
}
}
}
return 0;
}
static struct platform_driver alsps_sensor_driver = {
.probe = alsps_sensor_probe,
.remove = hwmsen_alsps_sensor_remove,
.driver =
{
.name = "als_ps",
}
};
int hwmsen_alsps_sensor_add(struct sensor_init_info* obj)
{
int err=0;
int i =0;
HWM_FUN(f);
for(i =0; i < MAX_CHOOSE_G_NUM; i++ )
{
if(NULL == alsps_init_list[i])
{
alsps_init_list[i] = kzalloc(sizeof(struct sensor_init_info), GFP_KERNEL);
if(NULL == alsps_init_list[i])
{
HWM_ERR("kzalloc error");
return -1;
}
obj->platform_diver_addr = &alsps_sensor_driver;
alsps_init_list[i] = obj;
break;
}
}
return err;
}
EXPORT_SYMBOL_GPL(hwmsen_alsps_sensor_add);
#endif
/*----------------------------------------------------------------------------*/
static int __init hwmsen_init(void)
{
HWM_FUN(f);
if(platform_driver_register(&hwmsen_driver))
{
HWM_ERR("failed to register sensor driver");
return -ENODEV;
}
#if defined(MTK_AUTO_DETECT_ACCELEROMETER)
if(platform_driver_register(&gsensor_driver))
{
HWM_ERR("failed to register gensor driver");
return -ENODEV;
}
#endif
#if defined(MTK_AUTO_DETECT_MAGNETOMETER)
if(platform_driver_register(&msensor_driver))
{
HWM_ERR("failed to register mensor driver");
return -ENODEV;
}
#endif
#if defined(MTK_AUTO_DETECT_ALSPS)
if(platform_driver_register(&alsps_sensor_driver))
{
HWM_ERR("failed to register alsps_sensor_driver driver");
return -ENODEV;
}
#endif
return 0;
}
/*----------------------------------------------------------------------------*/
static void __exit hwmsen_exit(void)
{
platform_driver_unregister(&hwmsen_driver);
}
/*----------------------------------------------------------------------------*/
module_init(hwmsen_init);
module_exit(hwmsen_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("sensor device driver");
MODULE_AUTHOR("Chunlei Wang