Chinaunix首页 | 论坛 | 博客
  • 博客访问: 179606
  • 博文数量: 27
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 618
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-15 09:12
文章分类
文章存档

2014年(17)

2013年(10)

我的朋友

分类: Android平台

2014-06-01 23:01:16

闲来无事分析分析 L/P sensor JSA01212 驱动代码:

首先是module_init(psals_jsa1212_init);

点击(此处)折叠或打开

  1. static int __init psals_jsa1212_init(void)
  2. {
  3.         int ret;

  4.         SENSOR_DBG(DBG_LEVEL2, "%s", DRIVER_NAME);

  5. #ifdef CONFIG_JSA1212_MANUAL_DEVICE
  6.         register_i2c_device(3, 0x44, DRIVER_NAME);        -----------------注册成I2C设备,挂载在I2C总线3上地址0x44
  7. #endif

  8.         ret = i2c_add_driver(&jsa1212_driver);           -----------------在I2C上添加jsa1212的driver
  9.         if (ret < 0)
  10.                 printk(KERN_ERR "Fail to register jsa1212 driver\n");

  11.         return ret;
  12. }
其次是看jsa1212_driver中的probe函数

点击(此处)折叠或打开

  1. static int sensor_probe(struct i2c_client *client,
  2.                         const struct i2c_device_id *devid)
  3. {
  4.         int ret = 0;

  5.         SENSOR_DBG(DBG_LEVEL3, "i2c device:%s", devid->name);

  6.         if (!i2c_check_functionality(client->adapter,                    -------------------匹配上何时的I2C适配器
  7.                 I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK)) {
  8.                 dev_err(&client->dev, "client not i2c capable\n");
  9.                 return -ENODEV;
  10.         }

  11.         sensor_data_init(client, &jsa1212_data);                         ---------------------初始化sensor 平台数据初始化

  12.         ret = sensor_input_init(&jsa1212_data);                          ---------------------注册成input设备
  13.         if (ret < 0) {
  14.                 dev_err(&client->dev, "input init %d\n", ret);
  15.                 goto out;
  16.         }

  17.         ret = sensor_get_data_init(&jsa1212_data);                        ------------------------设置gpio中断,请求中断线程
  18.         if (ret) {
  19.                 dev_err(&client->dev, "sensor_get_data_init\n");
  20.                 goto get_data;
  21.         }

  22.         ret = sysfs_create_group(&client->dev.kobj,
  23.                                         &sensor_default_attribute_group);             ---------创建sys文件接口
  24.         if (ret) {
  25.                 dev_err(&client->dev, "sysfs create group\n");
  26.         ret = sensor_init(&jsa1212_data);                              --------------------初始化寄存器的值
  27.         if (ret) {
  28.                 dev_err(&client->dev, "sensor_init\n");
  29.                 goto init;
  30.         }

  31.         return 0;
  32. init:
  33.         sysfs_remove_group(&jsa1212_data.client->dev.kobj,
  34.                                         &sensor_default_attribute_group);
  35. sys_init:
  36.         free_irq(jsa1212_data.irq, &jsa1212_data);
  37.         gpio_free(jsa1212_data.gpio_int);
  38. get_data:
  39.         input_unregister_device(jsa1212_data.input_als);
  40.         input_unregister_device(jsa1212_data.input_ps);
  41. out:
  42.         return ret;
  43. }
sensor_data_init(client, &jsa1212_data);

点击(此处)折叠或打开

  1. static int sensor_data_init(struct i2c_client *client,
  2.                         struct sensor_data *data)
  3. {
  4.         int ret = 0;

  5.         data->client = client;                    -----------------指定I2c适配器
  6.         mutex_init(&data->lock);                  ------------------上锁保证drvier data结构体中的值不变
  7.         data->state = 0;
  8.         data->interval = PS_WORK_INTERVAL;
  9.         data->ps_threshold = PS_NEAR_FAR_THRESHOLD;             ----------------给定距离阀值

  10.         data->gpio_int = acpi_get_gpio_by_index(&client->dev, 0, NULL);       还需要研究学习下acpi~~~~
  11.         if (data->gpio_int < 0) {
  12.                 dev_warn(&client->dev, "Fail to get gpio pin by ACPI\n");
  13.                 data->gpio_int = INT_GPIO;
  14.         }
  15.         SENSOR_DBG(DBG_LEVEL3, "gpios:%d", data->gpio_int);

  16.         i2c_set_clientdata(client, data);                            
  17.         return ret;
  18. }

sensor_get_data_init(&jsa1212_data);

点击(此处)折叠或打开

  1. static int sensor_get_data_init(struct sensor_data *data)
  2. {
  3.         int ret = 0;

  4.         SENSOR_DBG(DBG_LEVEL1, "%s", data->client->name);

  5.         ret = gpio_request(data->gpio_int, DRIVER_NAME);      
  6.         if (ret < 0) {
  7.                 dev_err(&data->client->dev, "Err: request gpio %d\n",
  8.                                                 data->gpio_int);
  9.                 goto out;
  10.         }

  11.         gpio_direction_input(data->gpio_int);
  12.         data->irq = gpio_to_irq(data->gpio_int);
  13.         //irq_set_status_flags(data->irq, IRQ_NOAUTOEN);
  14.         ret = request_threaded_irq(data->irq, NULL, sensor_interrupt_handler,
  15.                         IRQF_TRIGGER_FALLING | IRQF_ONESHOT, DRIVER_NAME, data);    ---------------请求中断线程,当下降沿出发中断处理函数sensor_interrupt_handle,有距离改变gpio会产生高低位变化,从而产生硬中断,软件将要处理
  16.         if (ret < 0) {
  17.                 dev_err(&data->client->dev,
  18.                         "Fail to request irq:%d ret=%d\n", data->irq, ret);
  19.                 gpio_free(data->gpio_int);
  20.                 return ret;
  21.         }

  22.         INIT_DELAYED_WORK(&data->work_ps, sensor_poll_work);                     -----------------初始化工作队列sensor_poll_work
  23. out:
  24.         return ret;
  25. }
sensor_interrupt_handlerstatic irqreturn_t sensor_interrupt_handler(int irq, void *pri)

点击(此处)折叠或打开

  1. static irqreturn_t sensor_interrupt_handler(int irq, void *pri)
  2. {
  3.         int ret;
  4.         u8 status;
  5.         struct sensor_data *data = (struct sensor_data *)pri;              -------得到平台数据

  6.         SENSOR_DBG(DBG_LEVEL1, "%s", data->client->name);

  7.         mutex_lock(&data->lock);                                           -------平台数据上锁

  8.         ret = sensor_read(data, REG_INTERRUPT, 1, &status);                -------读取中断寄存器,用来判断是L传感器还是P传感器
  9.         if (ret < 0)
  10.                 goto out;

  11.         if (status & PS_FLAG) {                         ------如果是P传感器
  12.                 u8 val;
  13.                 int delay;

  14.                 SENSOR_DBG(DBG_LEVEL3, "PS irq:%02x", status);

  15.                 ret = sensor_read(data, REG_PROX_DATA, 1, &val);          ---------读取当前测量距离
  16.                 if (ret < 0)
  17.                         goto out;
  18.                 if (val > data->ps_threshold) {                            -----------如果当前距离大于设置的阀值距离
  19.                         SENSOR_DBG(DBG_LEVEL3, "PS near:%02x", val);

  20.                         input_report_abs(data->input_ps, ABS_X, 0);        -------------报点,没有物体接近
  21.                         input_sync(data->input_ps);

  22.                         /*change threshold to avoid interrupt and
  23.                         schedule delaywork to poll near event*/
  24.                         ret = sensor_write(data, REG_PROX_HT, 0xff);        -------------并且把阀值的高8位设置成0xFF
  25.                         if (ret < 0)
  26.                                 goto out;

  27.                         delay = msecs_to_jiffies(data->interval);           ---------------得到平台默认的delay时间
  28.                         schedule_delayed_work(&data->work_ps, delay);       ---------------调度工作队列开始执行
  29.                 } else {                                                    ----------------如果当前距离小于设置
  30.                         SENSOR_DBG(DBG_LEVEL3, "Why here PS far:%02x", val);

  31.                         input_report_abs(data->input_ps, ABS_X, 1);         ----------------报点,有物体接近
  32.                         input_sync(data->input_ps);                     
  33.                         sensor_write(data, REG_PROX_HT, data->ps_threshold);
  34.                 }
  35.         }

  36.         if (status & ALS_FLAG) {
  37.                 u8 raw[2];
  38.                 int val, low, high;

  39.                 SENSOR_DBG(DBG_LEVEL3, "ALS irq:%02x", status);

  40.                 ret = sensor_read(data, REG_ALSIR_DT1, 2, raw);
  41.                 if (ret < 0)
  42.                         goto out;
  43.                 val = raw[0] + ((raw[1] & 0xf) << 8);

  44.                 low = val * 98 /100;
  45.                 high = val * 102 /100;
  46.                 if (high == val)
  47.                         high += 1;

  48.                 ret = sensor_write(data, REG_ALSIR_TH1, low & 0xff);
  49.                 if (ret < 0)
  50.                         goto out;
  51.                 ret = sensor_write(data, REG_ALSIR_TH2,
  52.                                 ((low >> 8) & 0xf) | ((high & 0xf) << 4));
  53.                 if (ret < 0)
  54.                         goto out;
  55.                 ret = sensor_write(data, REG_ALSIR_TH3, high >> 4);
  56.                 if (ret < 0)
  57.                         goto out;

  58.                 SENSOR_DBG(DBG_LEVEL2, "ALS data:%08x", val);
  59.                 input_report_abs(data->input_als, ABS_X, val);
  60.                 input_sync(data->input_als);

  61.         }

  62.         /*clear both ps and als flag bit7, bit3*/
  63.         ret = sensor_write(data, REG_INTERRUPT, status & 0x77);      ---------------清空中断位,等待下次中断的到来
  64. out:
  65.         mutex_unlock(&data->lock);
  66.         ret = IRQ_HANDLED;
  67.         return ret;
  68. }
static void sensor_poll_work(struct work_struct *work)

点击(此处)折叠或打开

  1. static void sensor_poll_work(struct work_struct *work)
  2. {
  3.         int ret;
  4.         int delay;
  5.         u8 val;
  6.         struct sensor_data *data = container_of(to_delayed_work(work),      ----------得到平台数据
  7.                                         struct sensor_data, work_ps);

  8.         SENSOR_DBG(DBG_LEVEL1, "%s", data->client->name);

  9.         mutex_lock(&data->lock);

  10.         if ((data->state & PS_STATE_FLAG) != PS_ENABLE)
  11.                 goto out;

  12.         /*exit when get far event*/
  13.         ret = sensor_read(data, REG_PROX_DATA, 1, &val);              ------------------重新得距离数据
  14.         if (ret < 0)
  15.                 goto out;
  16.         if (val <= data->ps_threshold) {                              ------------------如果距离小于阀值
  17.                 SENSOR_DBG(DBG_LEVEL2, "PS far %02x", val);

  18.                 input_report_abs(data->input_ps, ABS_X, 1);            -----------------上报数据
  19.                 input_sync(data->input_ps);

  20.                 sensor_write(data, REG_PROX_HT, data->ps_threshold);
  21.                 goto out;
  22.         }

  23.         delay = msecs_to_jiffies(data->interval);                       -------------否则重新设置delay,继续循环工作队列
  24.         schedule_delayed_work(&data->work_ps, delay);
  25. out:
  26.         mutex_unlock(&data->lock);
  27. }

这个driver的流程大概就是:等待中断出发->中断到来判断距离与阀值的大小->如果大于阀值(从寄存器读出来的值越大距离越近),调度wakequeue开始循环读取距离值->如果距离值小于阀值,才会报点,并且退出工作队列,如果依然距离大于阀值,会一直循环调度工作队列。

我的总结:其实简单的说就是 enable这个driver后,gipo高低电平变化产生中断,如果距离太近将会出发工作队列,知道距离再次大于阀值,才会退出工作队列,继续等待中断,否则程序会一直调用工作队列。

这里学到一点代码的log级别的代码,我觉得不错,记录下:

点击(此处)折叠或打开

  1. static unsigned int debug_level = 0;
  2. #define DBG_LEVEL1 1
  3. #define DBG_LEVEL2 2
  4. #define DBG_LEVEL3 3
  5. #define DBG_LEVEL4 4
  6. #define SENSOR_DBG(level, fmt, ...) \
  7. do { \
  8.         if (level <= debug_level) \
  9.                 printk(KERN_DEBUG "[%d]%s " \
  10.                          fmt "\n", \
  11.                         __LINE__, __func__, \
  12.                         ##__VA_ARGS__); \
  13. } while (0)

  14. #else
  15. #define SENSOR_DBG(level, ...)
  16. #endif

在添加一个写debug_level的sys接口,对于debug很有帮助。

点击(此处)折叠或打开

  1. #ifdef CONFIG_JSA1212_DEBUG
  2. static ssize_t sensor_debug_show(struct device *dev,
  3.                 struct device_attribute *attr, char *buf)
  4. {
  5.         return sprintf(buf, "%d\n", debug_level);
  6. }

  7. static ssize_t sensor_debug_store(struct device *dev,
  8.         struct device_attribute *attr, const char *buf, size_t count)
  9. {
  10.         unsigned long val;

  11.         if (kstrtoul(buf, 0, &val))
  12.                 return -EINVAL;

  13.         debug_level = val;
  14.         return count;
  15. }

  16. static DEVICE_ATTR(debug, S_IRUGO|S_IWUSR, sensor_debug_show,
  17.                 sensor_debug_store);
  18. #endif

对于大牛来说这个简单几百行的代码肯定是小儿科了,可怜我自诩为kernel team 却一个driver也没有写过的人,惭愧啊啊

阅读(3079) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~