一.alsps的初始化函數和重要結構體
epl2182_init //
Epl2182.c (kernel-3.10\drivers\misc\mediatek\alsps\epl2182-new)
struct alsps_hw *hw = get_cust_alsps_hw(); //得到配置和硬件信息
i2c_register_board_info(hw->i2c_num, &i2c_EPL2182, 1); //注冊I2C信息
list_add_tail(&devinfo->list, &__i2c_board_list); //加入到__i2c_board_list鏈表中
alsps_driver_add(&epl2182_init_info); // alsps_local_init函數加入
alsps_init_list[i] = obj; //加入到alsps_init_list[i] 數組中,以備后面用
alsps_local_init //這個函數在alsps核心調用,下面有分析
get_cust_alsps_hw(); //得到配置和硬件信息
epl2182_power(hw, 1); //上電
//mtk專門的上電函數(pmic.c),很多模塊都在用,if(hw->power_id != POWER_NONE_MACRO) 會進行上電操作,這里只是一個賦值操作power_on = on;
hwPowerOn(hw->power_id, hw->power_vol, "EPL2182")
i2c_add_driver(&epl2182_i2c_driver) //I2C注冊driver
i2c_driver 結構體:
static struct i2c_driver epl2182_i2c_driver =
{
.probe = epl2182_i2c_probe,
.remove = epl2182_i2c_remove,
.detect = epl2182_i2c_detect,
.suspend = epl2182_i2c_suspend,
.resume = epl2182_i2c_resume,
.id_table = epl2182_i2c_id,
.driver = {
.name = EPL2182_DEV_NAME,
},
};
二.I2C的alsps的probe函數
通過i2c_driver 與adapter的匹配調用epl2182_i2c_probe
epl2182_i2c_probe
epl2182_get_addr(obj->hw, &obj->addr); //得到I2C的地址
INIT_WORK(&obj->eint_work, epl2182_eint_work); //初始化中斷工作任務
epld = g_epl2182_ptr; //得到epl2182私有數據
elan_epl2182_I2C_Read(epld->client,REG_16,R_TWO_BYTE,0x02,read_data); //i2c的讀函數,讀channel1,ps的數據
elan_epl2182_I2C_Read(epld->client,REG_13,R_SINGLE_BYTE,0x01,read_data); //讀取到PS的中斷狀態,0或者1
ps_report_interrupt_data
ps_data_report(cxt->idev,value,3);
input_report_rel(dev, EVENT_TYPE_PS_VALUE, (value+1)); //輸入子系統上報數據
input_report_rel(dev, EVENT_TYPE_PS_STATUS, status);
input_sync(dev);
INIT_WORK(&obj->data_work, epl2182_check_ps_data); //也是上報數據
elan_epl2182_I2C_Write(client,REG_0,W_SINGLE_BYTE,0x02, EPL_S_SENSING_MODE); //把光照轉換到電壓的時間
elan_epl2182_I2C_Write(client,REG_9,W_SINGLE_BYTE,0x02,EPL_INT_DISABLE); //把中斷清零
epl2182_init_client
if(obj->hw->polling_mode_ps == 0) //這里是中斷模式
epl2182_setup_eint(client) //
g_epl2182_ptr = obj; //后面有用到epl2182的屬性
hw8k_init_device
epl2182_i2c_client=client; //后面有用到
misc_register(&epl2182_device) //注冊混雜設備
als_ctl.open_report_data= als_open_report_data; //als_control的賦值
als_ctl.enable_nodata = als_enable_nodata;
als_ctl.set_delay = als_set_delay;
混雜設備結構體:
static struct miscdevice epl2182_device =
{
.minor = MISC_DYNAMIC_MINOR,
.name = "als_ps",
.fops = &epl2182_fops,
};
static struct file_operations epl2182_fops =
{
.owner = THIS_MODULE,
.open = epl2182_open,
.release = epl2182_release,
.unlocked_ioctl = epl2182_unlocked_ioctl,
};
三.alsps核心
在alsps.c中是alsp的上層部分,在epl2182_init之后調用
static struct platform_driver alsps_driver =
{
.probe = alsps_probe,
.remove = alsps_remove,
.suspend = alsps_suspend,
.resume = alsps_resume,
.driver =
{
.name = ALSPS_PL_DEV_NAME,
#ifdef CONFIG_OF
.of_match_table = alsps_of_match,
#endif
}
}; //平台driver結構體
alsps_init
platform_driver_register(&alsps_driver) //注冊平台驅動,在mt_devs.c中有平台device:platform_device alsps_sensor
alsps_probe //匹配后調用它
alsps_context_alloc_object
alsps_context *obj = kzalloc(sizeof(*obj), GFP_KERNEL); //分配alsps_context 結構體,保存了很多屬性

初始化obj結構體,比如work的初始化:
als_work_func,ps_work_func;定時器初始化,執行函數:als_poll,ps_poll分別執行schedule_work(&obj->report_als); schedule_work(&obj->report_ps);
alsps_real_driver_init //初始化實際的alsps
alsps_real_driver_init //
alsps_init_list[i]->init(); //這就是具體alsps驅動注冊的init函數,在這里調用了
alsps_factory_device_init //is_use_common_factory被設置為true,就會進行misc_register(&alsps_factory_device),這里不用。
alsps_input_init //輸入子系統的初始化,注冊
input_allocate_device
input_register_device
四.應用讀取sensor數據:
als_store_active 和 ps_store_active啟動sensor,然后上報數據,PS一般用中斷,als一般用輪詢!
五.Light sensor level和value的設置
[DESCRIPTION]Light sensor level和value的設置
[PLATFORM]
MT6575 MT6577 MT6589
[SOLUTION]
Als_level是從sensor讀到的raw data, als_value是由als_level轉換為上報android的值,以
ltr559為例:在cust_alsps.c中 :

該值要客制化,請聯系sensor vender提供。
由於結構限制或者傳感器本身原因,工廠模式下檢測到ic出來的值變化不夠明顯,可檢測的范圍小等。導致自動背光效果不明顯。
[SOLUTION]
硬件上沒有方法改動的話,建議合理的修改,cust_alsps.c中的.level和.value這2個數組的值,driver里處理數據的原理:
從driver里傳感器IC寄存器出來的數據是level值,根據此level值參照上述2個數組的對應關系,由level數組的下標取到.value數組的下標對應的值,然后上報value值給工廠模式和上層看到。
所以需要您調cust_alsps.c里的那2個數組,如果是被遮擋而引起變化范圍變小的話,應該是寄存器出來的level變小了,所以建議把cust-als.c里的level也相應的減小,value不變,則應該有所改善。多試幾組減小.level的情況。
另外如果需要更細膩的背光等級,可以適當的把這2個數組加大,取值更連續一些。(這個映射還與android的value(LUX)--->255級背光的映射有關,也不是連續的)
請參考 frameworks\base\core\res\res\values\config.xml
六.兼容
當遇到兩個sensor同一個i2c地址,只啟用一個的時候,可以在注冊的時候該一個地址,然后在probe中改回來就可以了。
通過工程模式可以看到sensor的raw 打他,通過工廠測試模式可以看到所有senso人上報的數值。
七.工程測試模式中sensor的讀取數據流程
1.輸入*987*0#進行測試,一般用於產線的測試
epl2182_unlocked_ioctl : 用的是poll(ps)
2.*#*#3646633#*#*這樣是可以讀到sensor的原始數據,可以調試sensor是否有遮擋
epl2182_unlocked_ioctl 用的是poll
八.把ps改成輪詢方式
現在的機制是:
1. PS單獨開啟的時候用中斷;
2.單獨ALS是輪詢
3.PS與ALS一起開啟的時候在als_get_data中輪詢ALS,如果是中斷模式還要輪詢PS,因為輪詢als的時候ps不會產生中斷
把PS也改下輪詢:
因為poll的時候會互相干擾,產生競爭,導致數據閃動,需要信號量來控制
als_get_data
mutex_lock(&epl2182_poll_mutex);...............mutex_unlock(&epl2182_poll_mutex);
ps_get_data
mutex_lock(&epl2182_poll_mutex);
...............
mutex_unlock(&epl2182_poll_mutex);
PS在打電話的時候不能休眠:加睡眠鎖
目前的driver架構是對於沒有使用中斷模式的距離傳感器(cust_alsps.c
.ps_polling=1)
在驅動的i2c_probe里初始化一個wake lock,在Operate函數的ENABLE分支,如果是
enable的話就wake_lock(your_lock),disable的話就wake_unlock(your_lock)