APDS990X 是AVAGO的L和P集成的传感器芯片
设备挂在I2C设备上所以开始使用 I2C_add_driver函数注册一个I2C设备
static struct apds990x_chip *apds990x_alloc_dev(void) 初始化一个mutex锁,初始化L&P的一个工作队列的头(其实就是一个节点)
mutex_init(&chip->mutex);
init_waitqueue_head(&chip->ps_workq_head);
init_waitqueue_head(&chip->als_wordq_head);
INIT_LIST_HEAD(&chip->als_list);
INIT_LIST_HEAD(&chip->ps_list);
取得平台初始化数据连接I2C 适配器
chip->client = client;
chip->pdata = client->dev.platform_data;
i2c_set_clientdata(client, chip);
读取chip的型号
static int apds990x_detect(struct apds990x_chip *chip)
根据chip的型号初始化数据,配置寄存器,设置chip状态
apds990x_init_params(chip);
apds990x_configure(chip);
apds990x_set_arate(chip, APDS_LUX_DEFAULT_RATE);
apds990x_switch(chip, APDS_POWER_DOWN);
创建文件节点
sysfs_create_group(&chip->client->dev.kobj, apds990x_attribute_group);
定义P/L 的设备号 名称 给上层的接口函数
chip->ps_dev.minor = MISC_DYNAMIC_MINOR;
chip->ps_dev.name = "apds990x_psensor";
chip->ps_dev.fops = &ps_fops;
chip->als_dev.minor = MISC_DYNAMIC_MINOR;
chip->als_dev.name = "apds990x_lsensor";
chip->als_dev.fops = &als_fops;
注册成misc设备
misc_register(&chip->ps_dev);
misc_register(&chip->als_dev);
注册中断线程处理函数
static int apds990x_setup_irq(struct apds990x_chip *chip)
request_threaded_irq(client->irq, NULL,apds990x_irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "apds990x", chip);
打开中断
enable_irq_wake(client->irq);
这两行是要取得下次中断上报饿数据(算是初始化下吧,可能会丢弃第一次报的值)
apds990x_force_a_refresh(chip);
apds990x_force_p_refresh(chip);
工作流程如下:
当硬件检测到有L/P有变化后,出发中断,执行中断函数,apds990x_irq,中断函数中判断是L的中断还是P的中断,然后执行
if (status & APDS990X_ST_AINT)
als_handle_irq(chip);
if (status & APDS990X_ST_PINT)
ps_handle_irq(chip);
读出来值,设置状态,唤醒队列头(其实就是一个结构体)
set_bit(ALS_DATA_READY, &client->status);
wake_up(&chip->als_wordq_head);
在poll函数中,将实现
poll_wait(filep, &chip->ps_workq_head, wait); -------------------->当上层poll这个文件节点时候,程序会等待到这里读(是否阻塞需要看mask值),知道工作队列头被wake_up了
if (test_bit(PS_DATA_READY, &client->status))
mask |= (POLLIN | POLLRDNORM);
上层会open文件节点,然后poll这个fd,如果发现有改变,返回了,就要执行read函数了,
read把数据拷贝到user区域,然后清除一些状态
if (chip->alsps_switch & APDS_ALS_ENABLE) {
lux = min(chip->lux, APDS_ALS_MAX_LUX);
clear_bit(ALS_DATA_READY, &client->status);
if (copy_to_user(buffer, &lux, sizeof(lux)))
ret = -EFAULT;
ret = sizeof(lux);
}
这样就完成了一次完整的数据发送。
上层的sensor的代码存放在
hardware/intel/sensors
阅读(3060) | 评论(1) | 转发(1) |