闲来无事分析分析 L/P sensor JSA01212 驱动代码:
首先是module_init(psals_jsa1212_init);
-
static int __init psals_jsa1212_init(void)
-
{
-
int ret;
-
-
SENSOR_DBG(DBG_LEVEL2, "%s", DRIVER_NAME);
-
-
#ifdef CONFIG_JSA1212_MANUAL_DEVICE
-
register_i2c_device(3, 0x44, DRIVER_NAME); -----------------注册成I2C设备,挂载在I2C总线3上地址0x44
-
#endif
-
-
ret = i2c_add_driver(&jsa1212_driver); -----------------在I2C上添加jsa1212的driver
-
if (ret < 0)
-
printk(KERN_ERR "Fail to register jsa1212 driver\n");
-
-
return ret;
-
}
其次是看jsa1212_driver中的probe函数
-
static int sensor_probe(struct i2c_client *client,
-
const struct i2c_device_id *devid)
-
{
-
int ret = 0;
-
-
SENSOR_DBG(DBG_LEVEL3, "i2c device:%s", devid->name);
-
-
if (!i2c_check_functionality(client->adapter, -------------------匹配上何时的I2C适配器
-
I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK)) {
-
dev_err(&client->dev, "client not i2c capable\n");
-
return -ENODEV;
-
}
-
-
sensor_data_init(client, &jsa1212_data); ---------------------初始化sensor 平台数据初始化
-
-
ret = sensor_input_init(&jsa1212_data); ---------------------注册成input设备
-
if (ret < 0) {
-
dev_err(&client->dev, "input init %d\n", ret);
-
goto out;
-
}
-
-
ret = sensor_get_data_init(&jsa1212_data); ------------------------设置gpio中断,请求中断线程
-
if (ret) {
-
dev_err(&client->dev, "sensor_get_data_init\n");
-
goto get_data;
-
}
-
-
ret = sysfs_create_group(&client->dev.kobj,
-
&sensor_default_attribute_group); ---------创建sys文件接口
-
if (ret) {
-
dev_err(&client->dev, "sysfs create group\n");
-
ret = sensor_init(&jsa1212_data); --------------------初始化寄存器的值
-
if (ret) {
-
dev_err(&client->dev, "sensor_init\n");
-
goto init;
-
}
-
-
return 0;
-
init:
-
sysfs_remove_group(&jsa1212_data.client->dev.kobj,
-
&sensor_default_attribute_group);
-
sys_init:
-
free_irq(jsa1212_data.irq, &jsa1212_data);
-
gpio_free(jsa1212_data.gpio_int);
-
get_data:
-
input_unregister_device(jsa1212_data.input_als);
-
input_unregister_device(jsa1212_data.input_ps);
-
out:
-
return ret;
-
}
sensor_data_init
(client
, &jsa1212_data
);
-
static int sensor_data_init(struct i2c_client *client,
-
struct sensor_data *data)
-
{
-
int ret = 0;
-
-
data->client = client; -----------------指定I2c适配器
-
mutex_init(&data->lock); ------------------上锁保证drvier data结构体中的值不变
-
data->state = 0;
-
data->interval = PS_WORK_INTERVAL;
-
data->ps_threshold = PS_NEAR_FAR_THRESHOLD; ----------------给定距离阀值
-
-
data->gpio_int = acpi_get_gpio_by_index(&client->dev, 0, NULL); 还需要研究学习下acpi~~~~
-
if (data->gpio_int < 0) {
-
dev_warn(&client->dev, "Fail to get gpio pin by ACPI\n");
-
data->gpio_int = INT_GPIO;
-
}
-
SENSOR_DBG(DBG_LEVEL3, "gpios:%d", data->gpio_int);
-
-
i2c_set_clientdata(client, data);
-
return ret;
-
}
sensor_get_data_init
(&jsa1212_data
);
-
static int sensor_get_data_init(struct sensor_data *data)
-
{
-
int ret = 0;
-
-
SENSOR_DBG(DBG_LEVEL1, "%s", data->client->name);
-
-
ret = gpio_request(data->gpio_int, DRIVER_NAME);
-
if (ret < 0) {
-
dev_err(&data->client->dev, "Err: request gpio %d\n",
-
data->gpio_int);
-
goto out;
-
}
-
-
gpio_direction_input(data->gpio_int);
-
data->irq = gpio_to_irq(data->gpio_int);
-
//irq_set_status_flags(data->irq, IRQ_NOAUTOEN);
-
ret = request_threaded_irq(data->irq, NULL, sensor_interrupt_handler,
-
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, DRIVER_NAME, data); ---------------请求中断线程,当下降沿出发中断处理函数sensor_interrupt_handle,有距离改变gpio会产生高低位变化,从而产生硬中断,软件将要处理
-
if (ret < 0) {
-
dev_err(&data->client->dev,
-
"Fail to request irq:%d ret=%d\n", data->irq, ret);
-
gpio_free(data->gpio_int);
-
return ret;
-
}
-
-
INIT_DELAYED_WORK(&data->work_ps, sensor_poll_work); -----------------初始化工作队列sensor_poll_work
-
out:
-
return ret;
-
}
sensor_interrupt_handlerstatic irqreturn_t sensor_interrupt_handler(int irq, void *pri)
-
static irqreturn_t sensor_interrupt_handler(int irq, void *pri)
-
{
-
int ret;
-
u8 status;
-
struct sensor_data *data = (struct sensor_data *)pri; -------得到平台数据
-
-
SENSOR_DBG(DBG_LEVEL1, "%s", data->client->name);
-
-
mutex_lock(&data->lock); -------平台数据上锁
-
-
ret = sensor_read(data, REG_INTERRUPT, 1, &status); -------读取中断寄存器,用来判断是L传感器还是P传感器
-
if (ret < 0)
-
goto out;
-
-
if (status & PS_FLAG) { ------如果是P传感器
-
u8 val;
-
int delay;
-
-
SENSOR_DBG(DBG_LEVEL3, "PS irq:%02x", status);
-
-
ret = sensor_read(data, REG_PROX_DATA, 1, &val); ---------读取当前测量距离
-
if (ret < 0)
-
goto out;
-
if (val > data->ps_threshold) { -----------如果当前距离大于设置的阀值距离
-
SENSOR_DBG(DBG_LEVEL3, "PS near:%02x", val);
-
-
input_report_abs(data->input_ps, ABS_X, 0); -------------报点,没有物体接近
-
input_sync(data->input_ps);
-
-
/*change threshold to avoid interrupt and
-
schedule delaywork to poll near event*/
-
ret = sensor_write(data, REG_PROX_HT, 0xff); -------------并且把阀值的高8位设置成0xFF
-
if (ret < 0)
-
goto out;
-
-
delay = msecs_to_jiffies(data->interval); ---------------得到平台默认的delay时间
-
schedule_delayed_work(&data->work_ps, delay); ---------------调度工作队列开始执行
-
} else { ----------------如果当前距离小于设置
-
SENSOR_DBG(DBG_LEVEL3, "Why here PS far:%02x", val);
-
-
input_report_abs(data->input_ps, ABS_X, 1); ----------------报点,有物体接近
-
input_sync(data->input_ps);
-
sensor_write(data, REG_PROX_HT, data->ps_threshold);
-
}
-
}
-
-
if (status & ALS_FLAG) {
-
u8 raw[2];
-
int val, low, high;
-
-
SENSOR_DBG(DBG_LEVEL3, "ALS irq:%02x", status);
-
-
ret = sensor_read(data, REG_ALSIR_DT1, 2, raw);
-
if (ret < 0)
-
goto out;
-
val = raw[0] + ((raw[1] & 0xf) << 8);
-
-
low = val * 98 /100;
-
high = val * 102 /100;
-
if (high == val)
-
high += 1;
-
-
ret = sensor_write(data, REG_ALSIR_TH1, low & 0xff);
-
if (ret < 0)
-
goto out;
-
ret = sensor_write(data, REG_ALSIR_TH2,
-
((low >> 8) & 0xf) | ((high & 0xf) << 4));
-
if (ret < 0)
-
goto out;
-
ret = sensor_write(data, REG_ALSIR_TH3, high >> 4);
-
if (ret < 0)
-
goto out;
-
-
SENSOR_DBG(DBG_LEVEL2, "ALS data:%08x", val);
-
input_report_abs(data->input_als, ABS_X, val);
-
input_sync(data->input_als);
-
-
}
-
-
/*clear both ps and als flag bit7, bit3*/
-
ret = sensor_write(data, REG_INTERRUPT, status & 0x77); ---------------清空中断位,等待下次中断的到来
-
out:
-
mutex_unlock(&data->lock);
-
ret = IRQ_HANDLED;
-
return ret;
-
}
static void sensor_poll_work(struct work_struct *work)
-
static void sensor_poll_work(struct work_struct *work)
-
{
-
int ret;
-
int delay;
-
u8 val;
-
struct sensor_data *data = container_of(to_delayed_work(work), ----------得到平台数据
-
struct sensor_data, work_ps);
-
-
SENSOR_DBG(DBG_LEVEL1, "%s", data->client->name);
-
-
mutex_lock(&data->lock);
-
-
if ((data->state & PS_STATE_FLAG) != PS_ENABLE)
-
goto out;
-
-
/*exit when get far event*/
-
ret = sensor_read(data, REG_PROX_DATA, 1, &val); ------------------重新得距离数据
-
if (ret < 0)
-
goto out;
-
if (val <= data->ps_threshold) { ------------------如果距离小于阀值
-
SENSOR_DBG(DBG_LEVEL2, "PS far %02x", val);
-
-
input_report_abs(data->input_ps, ABS_X, 1); -----------------上报数据
-
input_sync(data->input_ps);
-
-
sensor_write(data, REG_PROX_HT, data->ps_threshold);
-
goto out;
-
}
-
-
delay = msecs_to_jiffies(data->interval); -------------否则重新设置delay,继续循环工作队列
-
schedule_delayed_work(&data->work_ps, delay);
-
out:
-
mutex_unlock(&data->lock);
-
}
这个driver的流程大概就是:等待中断出发->中断到来判断距离与阀值的大小->如果大于阀值(从寄存器读出来的值越大距离越近),调度wakequeue开始循环读取距离值->如果距离值小于阀值,才会报点,并且退出工作队列,如果依然距离大于阀值,会一直循环调度工作队列。
我的总结:其实简单的说就是 enable这个driver后,gipo高低电平变化产生中断,如果距离太近将会出发工作队列,知道距离再次大于阀值,才会退出工作队列,继续等待中断,否则程序会一直调用工作队列。
这里学到一点代码的log级别的代码,我觉得不错,记录下:
-
static unsigned int debug_level = 0;
-
#define DBG_LEVEL1 1
-
#define DBG_LEVEL2 2
-
#define DBG_LEVEL3 3
-
#define DBG_LEVEL4 4
-
#define SENSOR_DBG(level, fmt, ...) \
-
do { \
-
if (level <= debug_level) \
-
printk(KERN_DEBUG "[%d]%s " \
-
fmt "\n", \
-
__LINE__, __func__, \
-
##__VA_ARGS__); \
-
} while (0)
-
-
#else
-
#define SENSOR_DBG(level, ...)
-
#endif
在添加一个写debug_level的sys接口,对于debug很有帮助。
-
#ifdef CONFIG_JSA1212_DEBUG
-
static ssize_t sensor_debug_show(struct device *dev,
-
struct device_attribute *attr, char *buf)
-
{
-
return sprintf(buf, "%d\n", debug_level);
-
}
-
-
static ssize_t sensor_debug_store(struct device *dev,
-
struct device_attribute *attr, const char *buf, size_t count)
-
{
-
unsigned long val;
-
-
if (kstrtoul(buf, 0, &val))
-
return -EINVAL;
-
-
debug_level = val;
-
return count;
-
}
-
-
static DEVICE_ATTR(debug, S_IRUGO|S_IWUSR, sensor_debug_show,
-
sensor_debug_store);
-
#endif
对于大牛来说这个简单几百行的代码肯定是小儿科了,可怜我自诩为kernel team 却一个driver也没有写过的人,惭愧啊啊
阅读(3079) | 评论(0) | 转发(0) |