JZ_4775 电池驱动 (二)

来源:互联网 发布:linux shell的expect 编辑:程序博客网 时间:2024/05/18 13:24
上一节我们看了设备驱动的设备驱动设备注册过程,对于它的注册过程就不多讲了,和上一节的注册过程一样,这一节我们来看看电池的驱动模块的执行过程;
static struct platform_driver jz_battery_driver = {
 .probe =jz_battery_probe ,
 .remove = __devexit_p( jz_battery_remove ),
 .driver = {
  .name = "jz4775-battery",
  .owner = THIS_MODULE,
 },
 .suspend = jz_battery_suspend ,
 .resume = jz_battery_resume ,
};
下面我们就来看看探测函数 jz_battery_probe的具体内容,具体做了些什么准备工作,
static int __devinit jz_battery_probe (struct platform_device *pdev)
{
 int ret = 0;
 struct jz_battery_platform_data *pdata = pdev->dev.parent->platform_data;
 struct jz_battery *bat;
 struct power_supply *battery;
 struct proc_dir_entry *root;
 struct proc_dir_entry *res;
 if (!pdata) {
  dev_err(&pdev->dev, "No platform_data supplied\n");
  return -ENXIO;
 }
 bat = kzalloc(sizeof(*bat), GFP_KERNEL);    // 申请内存空间
 if (!bat) {
  dev_err(&pdev->dev, "Failed to allocate driver structre\n");
  return -ENOMEM;
 }
 bat->cell = mfd_get_cell(pdev);
 bat->ucharger = regulator_get(&pdev->dev, "ucharger");
 if (!bat->ucharger) {
  pr_info("Missing regulator ucharger\n");
 }
 bat->irq = platform_get_irq(pdev, 0);            // 获得平台对应的中断号
 if (bat->irq < 0) {
  ret = bat->irq;
  dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
  goto err_free;
 }
 bat->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);      // 获得平台对应资源
 if (!bat->mem) {
  ret = -ENOENT;
  dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
  goto err_free;
 }
 bat->mem = request_mem_region(bat->mem->start, resource_size(bat->mem), pdev->name);     // 申请内存块资源
 if (!bat->mem) {
  ret = -EBUSY;
  dev_err(&pdev->dev, "Failed to request mmio memory region\n");
  goto err_free;
 }
 bat->base = ioremap_nocache(bat->mem->start, resource_size(bat->mem));        // IO资源空间映射
 if (!bat->base) {
  ret = -EBUSY;
  dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
  goto err_release_mem_region;
 }
 get_slop_cut();
// 初始化电池结构体
 battery = &bat->battery;
 battery->name = "battery";
 battery->type = POWER_SUPPLY_TYPE_BATTERY;
 battery->properties = jz_battery_properties;
 battery->num_properties = ARRAY_SIZE(jz_battery_properties);
 battery->get_property = jz_battery_get_property ;          //获取电池的基本属性
 battery->external_power_changed = jz_battery_external_power_changed ;
 battery->use_for_apm = 1;
 bat->pdata = pdata;
 bat->pdev = pdev;

#ifdef CONFIG_HAS_EARLYSUSPEND 
 bat->early_suspend.suspend = jz_battery_early_suspend ;
 bat->early_suspend.resume = jz_battery_late_resume ;
 bat->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
 register_early_suspend(&bat->early_suspend);
#endif 
           // 锁机制的初始化
 init_completion(&bat->read_completion);   
 mutex_init(&bat->lock);      
// 初始化延时队列
 INIT_DELAYED_WORK(&bat->work, jz_battery_work );
 INIT_DELAYED_WORK(&bat->init_work, jz_battery_init_work );
 INIT_DELAYED_WORK(&bat->resume_work, jz_battery_resume_work );
 wake_lock_init(&bat->work_wake_lock, WAKE_LOCK_SUSPEND, "jz_battery");
// 申请中断
 ret = request_irq(bat->irq, adc_irq_handler, 0, pdev->name, bat);        // 下半部唤醒所有等待队列
 if (ret) {
  dev_err(&pdev->dev, "Failed to request irq %d\n", ret);
  goto err_iounmap;
 }
 disable_irq(bat->irq);
// 注册充电电池设备
 ret = power_supply_register(&pdev->dev, &bat->battery);
 if (ret) {
  dev_err(&pdev->dev, "Power supply battery register failed.\n");
  goto err_iounmap;
 }
 platform_set_drvdata(pdev, bat);
 if (pdata->info.usb_chg_current) {
  bat->usb_charge_time = pdata->info.battery_max_cpt * 36 / pdata->info.usb_chg_current;
 }
 if (bat->usb_charge_time < 90)
  bat->usb_charge_time = 90;
// 获取电压值
 bat->voltage = get_adc_voltage (bat);
 bat->next_scan_time = 15;
 /* init_work init function is only called once,
  * 5 seconds delay waiting Charger Device registration
  */
 schedule_delayed_work(&bat->init_work, 5 * HZ);       // 调度任务
// 创建文件节点
 root = proc_mkdir("power_supply", 0);     // 创建目录
 res = create_proc_entry("capacity", 0200, root);   // 创建文件节点
 if (res) {
  res->write_proc = proc_set_capacity ;    // 写函数
  res->data = bat;
 }
 res = create_proc_entry("status", 0444, root);    // 创建文件节点
 if (res) {
  res->read_proc = proc_read_status ;    // 读函数
  res->data = bat;
 }
// 打印电池的基本信息
 pr_info(LOG_TAG "discharging max voltage is %d\n", jz_cv_discharging[100]);
 pr_info(LOG_TAG "discharging min voltage is %d\n", jz_cv_discharging[0]);
 pr_info(LOG_TAG "charging max voltage is %d\n", jz_cv_charging[100]);
 pr_info(LOG_TAG "charging min voltage is %d\n", jz_cv_charging[0]);
 pr_info(LOG_TAG "battery_max_cpt is %d\n", pdata->info.battery_max_cpt);
 pr_info(LOG_TAG "usb_chg_current is %d\n", pdata->info.usb_chg_current);
 pr_info(LOG_TAG "sleep_current is %d\n", pdata->info.sleep_current);
 pr_info(LOG_TAG "registers over!\n"); 
 return 0;
// 注销退出
err_iounmap: 
#ifndef CONFIG_SLPT 
 wake_lock_destroy(&bat->work_wake_lock);    //工作队列唤醒锁
#endif 
 platform_set_drvdata(pdev, NULL);        // 清除平台数据
 iounmap(bat->base);                             // 取消IO映射空间
err_release_mem_region: 
 release_mem_region(bat->mem->start, resource_size(bat->mem));     // 注销内存映射空间
err_free: 
 if (bat->ucharger)
  regulator_put(bat->ucharger);      
 kfree(bat);          //释放电池结构体数据
 return ret;
}

之前我也读过该函数接口,所以在介绍它的执行过程之前我们先来看看几个函数接口,为我们介绍它的执行过程做准备工作。
static void jz_battery_early_suspend (struct early_suspend *early_suspend)
{
#ifndef CONFIG_SLPT
 struct jz_battery *bat;
 pr_info(LOG_TAG "%s\n", __FUNCTION__);
 bat = container_of(early_suspend, struct jz_battery, early_suspend);     // 获得结构体的地址
 jz_battery_set_resume_time (bat);       // 设置睡眠唤醒时间
#endif
}
有该接口的具体实现,我们很容易看明白其实它只做了一件事,那就是调用唤醒时间函数jz_battery_set_resume_time,我们再来具体看看它的具体内容,如下:
static void jz_battery_set_resume_time (struct jz_battery *bat)   //设置定时器的定时时间
{
 struct timespec alarm_time;
 unsigned long interval = 60 * 60;
 getnstimeofday (&alarm_time);             //获取当前时间
 printk(LOG_TAG "time now is %ld\n",alarm_time.tv_sec);         // 打印当前时间
 // 根据显示的容量来设置时间值
 if (bat->pdata->info.sleep_current == 0){
  interval = 60 * 60;
 } else if (bat->capacity_show > 10) {
  interval = ((bat->capacity_show - 10) *  bat->pdata->info.battery_max_cpt * 36) / (bat->pdata->info.sleep_current);
 } else if (bat->capacity_show > 3) {
  interval = ((bat->capacity_show - 3) * bat->pdata->info.battery_max_cpt * 36) / (bat->pdata->info.sleep_current);
 } else if (bat->capacity_show > 1){
  interval = ((bat->capacity_show - 1) * bat->pdata->info.battery_max_cpt * 36) / (bat->pdata->info.sleep_current);
 } else if (bat->capacity_show == 1){
  interval = (bat->pdata->info.battery_max_cpt * 36) / bat->pdata->info.sleep_current;
 }
 if (interval == 0)
  interval = 60 * 60;
 alarm_time.tv_sec += interval;    //  定时时间值        
 printk(LOG_TAG "set resume time %ld(delta %ld, %ldh %ldm %lds)\n", alarm_time.tv_sec, interval, interval/3600, 
            (interval/60)%60, interval%60);      // 打印定时器时间
 alarm_start_range (&alarm, timespec_to_ktime(alarm_time), timespec_to_ktime(alarm_time));    // 设置时间
}
通过查看jz_battery_late_resume函数的具体执行内容,可以知道其实它只是在进行空执行,所以这里我们就不把它列出来分析了,如果特别想了解它,可以自己查看代码,代码在 driver/power/jz4775-battery-lut.c中。

准备工作做得差不多了,我们来看看它的执行过程,看看它到底是怎样工作的,根据调度函数schedule_delayed_work(&bat->init_work, 5 * HZ) 我们可以知道,它将调度初始化工作队列也就是 jz_battery_init_work函数。
static void jz_battery_init_work (struct work_struct *work) 
{
 struct delayed_work *delayed_work = container_of(work, struct delayed_work, work);
 struct jz_battery *bat = container_of(delayed_work, struct jz_battery, init_work);
 pr_info(LOG_TAG "%s\n", __FUNCTION__);
 if (bat->get_pmu_status == NULL) {
  pr_err(LOG_TAG "Changer device not yet registered !\n");
  return;
 }
 bat->status = get_status (bat);    // 获取当前电池状态
 bat->voltage = get_adc_voltage (bat);      // 获取电池电压值
 // 根据电池的状态来设置它的显示值
 if (bat->status != POWER_SUPPLY_STATUS_FULL) {
  bat->capacity_real = lookup_capacity (is_charging (bat->status), bat->voltage);     // 获得当前电压的百分比
  bat->capacity_show = bat->capacity_real;
 } else
  bat->capacity_real = bat->capacity_show = 100;
 pr_info(LOG_TAG "%s, cap real: %d, cap show: %d, volt: %dmV\n",  status2str(bat->status), bat->capacity_real,
 bat->capacity_show, bat->voltage); 
 power_supply_changed (&bat->battery);          //告诉Android 端,电池电量发生改变
 cancel_delayed_work_sync(&bat->work);
 schedule_delayed_work(&bat->work, 20 * HZ);            //调度到工作队列去工作
#ifndef CONFIG_SLPT 
 alarm_init(&alarm, ANDROID_ALARM_RTC_WAKEUP, wake_up_fun);         // 0
#endif 
 bat->pmu_work_enable(bat->pmu_interface);
 external_cb_en = 1;
}

下面我们分别来看看这几被调用的函数:

static int get_status (struct jz_battery *bat)    // 获取当前电池的状态
{
 int status;
 status = bat->get_pmu_status(bat->pmu_interface, STATUS);
 if ((status == POWER_SUPPLY_STATUS_CHARGING) && force_full  && (bat->capacity_real > 85)) {     // force_full = 0
  pr_info(LOG_TAG "Force FULL\n");
  return POWER_SUPPLY_STATUS_FULL;
 }
 if (status == POWER_SUPPLY_STATUS_FULL)
      force_full = 1;
 return status;      // 返回当前电池的状态
}

===================================================================

static int get_adc_voltage (struct jz_battery *bat)    // 对读出的电压值进行校正处理
{
 unsigned int current_value[12], final_value = 0;
 unsigned int value_sum = 0;
 unsigned int max_value, min_value;
 unsigned int i,j = 0, temp;
 unsigned int max_index = 0, min_index = 0;
 unsigned int real_voltage = 0;
 current_value[0] = get_adc_value (bat);        // 读取电压值
// 对读出的电压值进行处理
 value_sum = max_value = min_value = current_value[0];
 for (i = 1; i < 12; i++) {
  current_value[i] = get_adc_value(bat);
  value_sum += current_value[i];
  if (max_value < current_value[i]) {
   max_value = current_value[i];
   max_index = i;
  }
  if (min_value > current_value[i]) {
   min_value = current_value[i];
   min_index = i;
  }
 }
 value_sum -= (max_value + min_value);
 final_value = value_sum / 10;    // 获取平均电压值
 for (i = 0; i < 12; i++) {
  if (i == min_index)
   continue;
  if (i == max_index)
   continue;
  temp = abs (current_value[i] - final_value);    // 计算绝对值
  if (temp > 4) {
   j++;
   value_sum -= current_value[i];   // 去掉浮动大于4的值
  }
 }
 if (j < 10) {
  final_value = value_sum / (10 - j);    // 计算剩余的电压值得平均值
 }
// 校正处理
 real_voltage = final_value * 1200 / 4096;
 real_voltage *= 4;
 if ((slop == 0) && (cut == 0)) {
  pr_info(LOG_TAG "ADC voltage is %dmV\n",real_voltage);
 } else {
  unsigned int origin_voltage;
  origin_voltage = real_voltage;
  real_voltage = (final_value * slop + cut) / 10000;
  real_voltage *= 4;
  pr_info(LOG_TAG "ADC voltage is %d(%d)mV\n", real_voltage, origin_voltage);
 }
 return real_voltage;   // 返回校正后的电压值
}

static unsigned intget_adc_value (struct jz_battery *bat)     // 获取电压值
{
 unsigned long tmp;
 unsigned int value;
 mutex_lock(&bat->lock);
 INIT_COMPLETION(bat->read_completion);
 bat->cell->enable(bat->pdev);
 enable_irq(bat->irq);
 tmp = wait_for_completion_interruptible_timeout( &bat->read_completion, HZ);      // tmp = 1 执行成功;tmp = 0 执行失败(超时)。
 if (tmp > 0) {
  value = readw(bat->base) & 0xfff;    // 获取端口电压值  
 } else {
  value = tmp ? tmp : -ETIMEDOUT;
 }
 disable_irq(bat->irq);
 bat->cell->disable(bat->pdev);
 mutex_unlock(&bat->lock);
 return value;    // 返回获得的实际电压值
}

=================================================================
static intlookup_capacity (int charging, int volt)
{
 int i;
 const int *cv;
 if (charging)        // 判断是否正在充电,根据判断结果获取电池曲线
  cv = jz_cv_charging ;        // 获得充电曲线的地址
 else
  cv = jz_cv_discharging ;    // 获得放电曲线的地址
 for (i = 100; i > 0; --i) {
  if (volt >= cv[i])
   return i;      // 根据当前电压返回当前电量百分比
 }
 return 0;
}

电池曲线分充电曲线和放电曲线,充电曲线相比同一百分比下的放电曲线的容量可能要高点,具体的数据需要靠对电池曲线的获取,获取的方法有手动获取的方法,当然也可以通过软件自动获取。
const int __attribute__((weak)) jz_cv_discharging [101] = {     //放电曲线
  3408, /* 0% */
  3424,
  3448,
  3472,
  3496,
  3516,
  3536,
  3556,
  3576,
  3596,
  3616,
  3624,
  3632,
  3640,
  3644,
  3652,
  3656,
  3664,
  3668,
  3672,
  3676,
  3680,
  3682,
  3684,
  3688,
  3692,
  3694,
  3696,
  3700,
  3704,
  3708,
  3712,
  3716,
  3720,
  3728,
  3732,
  3736,
  3740,
  3742,
  3744,
  3748,
  3756,
  3760,
  3764,
  3768,
  3772,
  3776,
  3780,
  3784,
  3788,
  3792,
  3796,
  3800,
  3804,
  3808,
  3812,
  3816,
  3820,
  3828,
  3832,
  3836,
  3844,
  3852,
  3860,
  3868,
  3872,
  3880,
  3884,
  3888,
  3892,
  3900,
  3904,
  3910,
  3916,
  3920,
  3928,
  3936,
  3944,
  3952,
  3960,
  3968,
  3976,
  3984,
  3988,
  3996,
  4000,
  4008,
  4012,
  4020,
  4028,
  4040,
  4052,
  4058,
  4064,
  4076,
  4088,
  4096,
  4100,
  4104,
  4112,
  4120 /* 100% */
};

const int __attribute__((weak)) jz_cv_charging [101] = {         // 充电曲线
  3680, /* 0% */
  3804,
  3820,
  3824,
  3826,
  3828,
  3832,
  3838,
  3840,
  3842,
  3844, /* 10% */
  3847,
  3850,
  3854,
  3857,
  3860,
  3863,
  3866,
  3869,
  3872,
  3875, /* 20% */
  3878,
  3881,
  3885,
  3888,
  3892,
  3895,
  3898,
  3901,
  3905,
  3908, /* 30% */
  3910,
  3912,
  3914,
  3916,
  3918,
  3920,
  3922,
  3924,
  3926,
  3928, /* 40% */
  3929,
  3930,
  3932,
  3933,
  3934,
  3935,
  3937,
  3938,
  3939,
  3940, /* 50% */
  3941,
  3942,
  3943,
  3944,
  3945,
  3946,
  3947,
  3948,
  3949,
  3950, /* 60% */
  3952,
  3954,
  3956,
  3959,
  3962,
  3966,
  3970,
  3973,
  3976,
  3980, /* 70% */
  3985,
  3990,
  3995,
  4000,
  4005,
  4010,
  4015,
  4020,
  4025,
  4030, /* 80% */
  4036,
  4042,
  4048,
  4055,
  4062,
  4069,
  4076,
  4073,
  4080,
  4088, /* 90% */
  4089,
  4090,
  4091,
  4092,
  4093,
  4094,
  4096,
  4098,
  4190,
  4200 /* 100% */
};

==========================================================

static int is_charging (int status)
{
 switch (status) {
 case POWER_SUPPLY_STATUS_CHARGING:
 case POWER_SUPPLY_STATUS_FULL:      
 return 1; 
 default:
 return 0;
 }
}

根据函数的调度的顺序,我们从 jz_battery_init_work函数中的调度函数可以看出下一步将跳转到jz_battery_work函数去执行,我们再去看看它的具体实现;
static void jz_battery_work (struct work_struct *work)
{
 struct jz_battery *bat = container_of(work, struct jz_battery, work.work);
 int old_status = bat->status;
 pr_info(LOG_TAG "%s\n", __FUNCTION__);
 bat->status = get_status (bat);
 if (old_status != bat->status)       // 比较之前状态和当期状态是否一致
 pr_info(LOG_TAG "old_status: %s\n", status2str (old_status));
 bat->voltage = get_adc_voltage (bat);       // 获得校正后的电压值
 bat->capacity_real = lookup_capacity (is_charging (bat->status), bat->voltage);      // 获得容量值
 switch (bat->status) {          // 设置电池在不同的状态下的调度时间
 case POWER_SUPPLY_STATUS_CHARGING:             jz_battery_capacity_rising (bat);      break;   
 case POWER_SUPPLY_STATUS_FULL:                        jz_battery_capacity_full (bat);          break; 
 case POWER_SUPPLY_STATUS_DISCHARGING:
 case POWER_SUPPLY_STATUS_NOT_CHARGING:     jz_battery_capacity_falling (bat);    break;
 case POWER_SUPPLY_STATUS_UNKNOWN:             bat->next_scan_time = 60;            break;
 }
 pr_info(LOG_TAG "%s, cap real: %d, cap show: %d, volt: %dmV, next %ds\n", status2str(bat->status), bat->capacity_real,
   bat->capacity_show, bat->voltage, bat->next_scan_time);
#ifdef CONFIG_SLPT                    //编译测试时代码未编译
 slpt_set_battery_low_voltage(low_battery_voltage);
 slpt_set_battery_voltage(bat->voltage, bat->capacity_show);
 SLPT_SET_KEY(SLPT_K_LOW_BATTERY_WARN_VOL, low_battery_warn_voltage);
#endif
 power_supply_changed (&bat->battery);        //上报当前电池状态
 schedule_delayed_work (&bat->work, bat->next_scan_time * HZ);      // 根据设置的调度时间值,循环调度工作队列
}
再来简单看下几个陌生的函数接口,看看它们的具体实现。
static const char *status2str (int status)     // 返回当前状态的指针
{
 switch (status) {
 case POWER_SUPPLY_STATUS_CHARGING:
  return "CHARGING";
 case POWER_SUPPLY_STATUS_DISCHARGING:
  return "DISCHARGING";
 case POWER_SUPPLY_STATUS_NOT_CHARGING:
  return "NOT_CHARGING";
 case POWER_SUPPLY_STATUS_FULL:
  return "FULL";
 default:
  return "UNKNOWN";
 }
}

=======================================================================
static voidjz_battery_capacity_rising (struct jz_battery *bat)    //设置电池在充电时的下一次执行工作队列的延时时间
{
 bat->next_scan_time = 40;
//根据当前显示的容量百分比设置执行工作队列的延时时间
 if (bat->capacity_show >= 100) {
  bat->next_scan_time = 60;
  bat->capacity_show = 99;
  return;
 } else if (bat->capacity_show == 99) {
  bat->next_scan_time = 60;
  return;
 }
 if (bat->capacity_real > bat->capacity_show + 5)
  bat->next_scan_time = 30;
 if (bat->capacity_real > bat->capacity_show + 10)
  bat->next_scan_time = 15;
 if (bat->capacity_real > bat->capacity_show)
  if (bat->capacity_show != 100)
   bat->capacity_show++;           // 设置显示的容量百分比自增

==============================================================================
static voidjz_battery_capacity_full (struct jz_battery *bat)           // 设置显示的容量百分比和下次调度工作队列的延时时间
{          // 根据当前的容量百分比重新设置容量百分比和延时调度时间
 if (bat->capacity_show >= 99) {
  bat->capacity_show = 100;
  bat->status = POWER_SUPPLY_STATUS_FULL;
  bat->next_scan_time = 5 * 60;
 } else {
  bat->next_scan_time = 45;
  bat->capacity_show++;        // 设置显示的容量百分比自增
 }
}

==============================================================================
static void jz_battery_capacity_falling (struct jz_battery *bat)      // 设置显示的容量百分比和下次调度工作队列的延时时间
{          // 重新设置容量百分比和调度延迟时间
 if (bat->capacity_show >= 90) {
  bat->next_scan_time = 120;
 } else if (bat->capacity_show >= 15 ) {
  bat->next_scan_time = 60;
 } else if (bat->capacity_show >= 8){
  bat->next_scan_time = 30;
 } else {
  bat->next_scan_time = 10;
 }
 if (bat->capacity_real < bat->capacity_show - 10)
  bat->next_scan_time = 10;
 if (bat->capacity_real < bat->capacity_show)
  if (bat->capacity_show != 0)
   bat->capacity_show--;      //放电时电量自减
}

当电池充电时进入电池工作队列后,就会进入循环工作,只有外部条件出发时才会执行其他的函数,下面我们再来看看驱动的卸载函数。
static int __devexit jz_battery_remove (struct platform_device *pdev)    //卸载退出函数接口
{
 struct jz_battery *bat = platform_get_drvdata(pdev);
 //注销工作队列和唤醒工作队列
 cancel_delayed_work_sync (&bat->work);
 cancel_delayed_work_sync (&bat->resume_work);
#ifndef CONFIG_SLPT
 wake_lock_destroy (&bat->work_wake_lock);   //销毁工作队列唤醒锁
#endif
 power_supply_unregister (&bat->battery);   // 注销充电电池的注册

 free_irq (bat->irq, bat);     // 释放中断号

 iounmap (bat->base);      // 取消IO空间映射
 release_mem_region (bat->mem->start, resource_size(bat->mem));    // 注销内存空间
 kfree (bat);       //释放电池信息

 return 0;
}

下面我们来看睡眠函数具体做了些什么工作,先看看它的代码;
static int jz_battery_suspend (struct platform_device *pdev, pm_message_t state)    // 取消唤醒队列和工作队列并保存当前进入睡眠时间
{
 struct jz_battery *bat = platform_get_drvdata(pdev);
 struct timeval battery_time;     // 微秒级
 pr_info(LOG_TAG "%s\n", __FUNCTION__);
 // 打印当期电池信息
 bat->status = get_status (bat);
 pr_info(LOG_TAG "%s, cap real: %d, cap show: %d, volt: %dmV\n",  status2str (bat->status), bat->capacity_real, 
   bat->capacity_show, bat->voltage);
 // 注销工作队列和唤醒队列
 cancel_delayed_work_sync (&bat->resume_work);
 cancel_delayed_work_sync (&bat->work);
//获得当前时间并设置打印出来
 do_gettimeofday (&battery_time);    
 bat->suspend_time = battery_time.tv_sec;    // seconds   保存当前时间
 pr_info(LOG_TAG "suspend_time is %ld\n", battery_time.tv_sec);
 external_cb_en = 0;

 return 0;
}

最后一个就是唤醒函数了,我们来追踪下它的执行过程;
static int jz_battery_resume (struct platform_device *pdev)   // 调度到唤醒工作对了中去执行
{
 struct jz_battery *bat = platform_get_drvdata(pdev);

 cancel_delayed_work (&bat->resume_work);    //取消唤醒工作队列
 wake_lock (&bat->work_wake_lock);       // 设置唤醒锁
#ifdef CONFIG_SLPT    // true  编译测试结构为真
 schedule_delayed_work (&bat->resume_work, 0 * HZ);    //执行唤醒工作队列
#else 
 schedule_delayed_work(&bat->resume_work, 1 * HZ);
#endif 
 return 0;
}

紧接着看看唤醒工作函数,看看它的具体的代码;
static void jz_battery_resume_work(struct work_struct *work)
{
 struct delayed_work *delayed_work = container_of(work, struct delayed_work, work);
 struct jz_battery *bat = container_of (delayed_work, struct jz_battery, resume_work);
 struct timeval battery_time;
 unsigned long time_delta;
 pr_info(LOG_TAG "%s\n", __FUNCTION__);

 bat->status = get_status (bat);          // 获得当前状态
#ifdef CONFIG_SLPT    // true
 bat->voltage = slpt_get_battery_voltage ();
 if (bat->voltage <= low_battery_voltage && bat->status != POWER_SUPPLY_STATUS_CHARGING) {
  pr_info(LOG_TAG "SLPT: low capacity(%dmV), shutting down...\n", bat->voltage);
  bat->capacity_show = bat->capacity_real = 0;
  power_supply_changed (&bat->battery);     // 上报电池信息
  while (1)
   msleep(1000);      // 延时1 second
 }
#else
 bat->voltage = get_adc_voltage (bat);
#endif

/*
 * TODO: to create a table for SLPT capacity lookup specifically
 */
 bat->capacity_real = lookup_capacity (is_charging (bat->status), bat->voltage);     // 获得电池容量百分比

 do_gettimeofday (&battery_time);        // 获得当前时间
 bat->resume_time = battery_time.tv_sec;    // 单位second    保存当前时间
 pr_info(LOG_TAG "resume_time is %ld\n", battery_time.tv_sec);
 time_delta = bat->resume_time - bat->suspend_time;      // 总共睡眠时间长
 pr_info(LOG_TAG "time_delta is %ld, %ldh %ldm %lds\n", time_delta,  time_delta/3600,
 (time_delta/60)%60, time_delta%60); 

 bat->next_scan_time = 15;
 // 根据当前状态设置实际电压百分比和延时调度工作队列的时间
 if (bat->status == POWER_SUPPLY_STATUS_FULL ) {
  bat->capacity_show = bat->capacity_real = 100;
 } else if (bat->status == POWER_SUPPLY_STATUS_CHARGING) { 
  if ((bat->capacity_real > bat->capacity_show) && (time_delta > 10 * 60)) { 
   bat->capacity_show = bat->capacity_real;
  } else
   jz_battery_capacity_rising (bat);

 } else { /* DISCHARGING || NOT_CHARGING */

  if ((bat->capacity_real < bat->capacity_show) && (time_delta > 10 * 60)) {
   bat->capacity_show = bat->capacity_real;
  } else
   jz_battery_capacity_falling (bat);
 }
 // 上报电池信息并打印显示信息
 power_supply_changed (&bat->battery);  
 pr_info(LOG_TAG "%s, cap real: %d, cap show: %d, volt: %dmV, next %ds\n",
   status2str (bat->status), bat->capacity_real,  bat->capacity_show, bat->voltage, bat->next_scan_time); 

 schedule_delayed_work (&bat->work, bat->next_scan_time * HZ);    // 调度执行到工作队列

 external_cb_en = 1;

#ifndef CONFIG_SLPT    // false
 jz_battery_set_resume_time(bat);
#endif
 wake_unlock (&bat->work_wake_lock);     // 解锁工作队列唤醒锁
}
    通过本函数的具体实现很容易看明白它最后又去调度工作队列了,又开始进入工作队列的循环中去进行工作了。看到这里基本的驱动代码也就看完了,如果感兴趣去可以再去看看细节部分的代码的具体的实现机制,在这里我就介绍到这里!
0 0
原创粉丝点击