device_init_wakeup()

理解Linux设备唤醒机制与设备模型
本文深入探讨了Linux设备模型中用于控制唤醒事件的can_wakeup和should_wakeup两个核心概念,解释了如何通过device_init_wakeup()函数进行初始化,并详细介绍了设备驱动在实现Linux电源管理时的角色。


static inline int device_init_wakeup(struct device *dev, bool val)
{
    device_set_wakeup_capable(dev, val);   //设置设备能不能被唤醒
    device_set_wakeup_enable(dev, val);     //设置设备使不使用唤醒;
    return 0;

}

// 设备模型中的 所有设备 都有两个标志来控制 唤醒事件(可使得设备或系统退出低功耗状态)。

static inline void device_set_wakeup_capable(struct device *dev, bool capable)
{
    dev->power. can_wakeup = capable;
}


static inline int device_set_wakeup_enable(struct device *dev, bool enable)
{
    dev->power.should_wakeup = enable;
    return 0;
}



要认识device_init_wakeup(),首先需要知道两个概念:can_wakeup和should_wakeup。这两个家伙从哪里来的?看struct device结构体,里面有一个成员struct dev_pm_info power,来看一看struct dev_pm_info,来自include/linux/pm.h文件:

  1. 265 struct dev_pm_info {    
  2. 266     pm_message_t            power_state;    
  3. 267     unsigned                can_wakeup:1;    
  4. 268 #ifdef  CONFIG_PM    
  5. 269         unsigned                should_wakeup:1;    
  6. 270     pm_message_t            prev_state;    
  7. 271     void                    * saved_state;    
  8. 272     struct device           * pm_parent;    
  9. 273     struct list_head        entry;    
  10. 274 #endif    
  11. 275 };    


 

这些都是电源管理部分的核心数据结构,显然,我们没有必要深入研究,只是需要知道,can_wakeup为1时 表明一个设备可以被唤醒,设备驱动为了支持Linux中的电源管理,有责任调用device_init_wakeup()来初始化can_wakeup。而should_wakeup则是在设备的 电源状态发生变化时 被device_may_wakeup()用来测试,测试它该不该变化

因此,can_wakeup表明的是一种能力,should_wakeup表明的是有了这种能力以后去不去做某件事。













static int bq25713_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct device *dev = &client->dev; struct bq25713_device *charger; struct device_node *charger_np; int ret = 0; u32 i = 0; int manufacture_id = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -EIO; charger = devm_kzalloc(&client->dev, sizeof(*charger), GFP_KERNEL); if (!charger) return -EINVAL; charger->client = client; charger->dev = dev; charger->battery_min_temp = INT_MIN; charger->battery_safe_temp = 45; if (device_property_read_u32(dev, "battery_min_temp", &charger->battery_min_temp)) { dev_warn(dev, "battery_min_temp not specified, using default :no minimum temperature\n"); } charger->battery_min_temp *= 10; if (device_property_read_u32(dev, "battery_safe_temp", &charger->battery_safe_temp)) { dev_warn(dev, "battery_safe_temp not specified, using default :45 ℃\n"); } charger->battery_safe_temp *= 10; printk("===== snbc ===== battery_min_temp : %d , battery_safe_temp : %d", charger->battery_min_temp, charger->battery_safe_temp); charger_np = of_find_compatible_node(NULL, NULL, "ti,bq25713"); if (charger_np) { charger->regmap = devm_regmap_init_i2c(client, &bq25713_regmap_config); if (IS_ERR(charger->regmap)) { dev_err(&client->dev, "Failed to initialize regmap\n"); return -EINVAL; } for (i = 0; i < ARRAY_SIZE(bq25713b_reg_fields); i++) { const struct reg_field *reg_fields = bq25713b_reg_fields; charger->rmap_fields[i] = devm_regmap_field_alloc(dev, charger->regmap, reg_fields[i]); if (IS_ERR(charger->rmap_fields[i])) { dev_err(dev, "cannot allocate regmap field\n"); return PTR_ERR(charger->rmap_fields[i]); } } } i2c_set_clientdata(client, charger); /*read chip id. Confirm whether to support the chip*/ charger->chip_id = bq25713_field_read(charger, DEVICE_ID); manufacture_id = bq25713_field_read(charger, MANUFACTURE_ID); DBG("chip_id = 0x%x, manufacture = 0x%x", charger->chip_id, manufacture_id); if (charger->chip_id < 0) { dev_err(dev, "BQ25713 rong, check dc 24V \n"); bq25713_parse_dt(charger); ret = bq25713_power_supply_init(charger); if (ret) { goto Err; } bq25713_DC24V_monitor(charger); bq25713_charger = charger; return 0; } if (!dev->platform_data) { ret = bq25713_fw_probe(charger); if (ret < 0) { dev_err(dev, "Cannot read device properties.\n"); return ret; } } else { return -ENODEV; } ret = bq25713_hw_init(charger); if (ret < 0) { dev_err(dev, "Cannot initialize the chip.\n"); return ret; } bq25713_parse_dt(charger); bq25713_init_sysfs(charger); ret = bq25713_power_supply_init(charger); if (ret) { goto Err; } bq25713_set_otg_enable(charger, 0); ret = bq25713_irq_init(charger); if (ret) { goto Err; } device_init_wakeup(dev, 1); bq25713_charger_monitor(charger); bq25713_notifier_register(charger); bq25713_charger = charger; DBG("bq25713 init successful!\n"); return 0; Err: DBG("bq25713 init failed!!!\n"); power_supply_unregister(charger->supply_charger); return ret; }每一行代码详细解释
07-03
static int bq25713_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct device *dev = &client->dev; struct bq25713_device *charger; struct device_node *charger_np; int ret = 0; u32 i = 0; int manufacture_id = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -EIO; charger = devm_kzalloc(&client->dev, sizeof(*charger), GFP_KERNEL); if (!charger) return -EINVAL; charger->client = client; charger->dev = dev; charger->battery_min_temp = INT_MIN; charger->battery_safe_temp = 45; if (device_property_read_u32(dev, "battery_min_temp", &charger->battery_min_temp)) { dev_warn(dev, "battery_min_temp not specified, using default :no minimum temperature\n"); } charger->battery_min_temp *= 10; if (device_property_read_u32(dev, "battery_safe_temp", &charger->battery_safe_temp)) { dev_warn(dev, "battery_safe_temp not specified, using default :45 ℃\n"); } charger->battery_safe_temp *= 10; printk("===== snbc ===== battery_min_temp : %d , battery_safe_temp : %d", charger->battery_min_temp, charger->battery_safe_temp); charger_np = of_find_compatible_node(NULL, NULL, "ti,bq25713"); if (charger_np) { charger->regmap = devm_regmap_init_i2c(client, &bq25713_regmap_config); if (IS_ERR(charger->regmap)) { dev_err(&client->dev, "Failed to initialize regmap\n"); return -EINVAL; } for (i = 0; i < ARRAY_SIZE(bq25713b_reg_fields); i++) { const struct reg_field *reg_fields = bq25713b_reg_fields; charger->rmap_fields[i] = devm_regmap_field_alloc(dev, charger->regmap, reg_fields[i]); if (IS_ERR(charger->rmap_fields[i])) { dev_err(dev, "cannot allocate regmap field\n"); return PTR_ERR(charger->rmap_fields[i]); } } } i2c_set_clientdata(client, charger); /*read chip id. Confirm whether to support the chip*/ charger->chip_id = bq25713_field_read(charger, DEVICE_ID); manufacture_id = bq25713_field_read(charger, MANUFACTURE_ID); DBG("chip_id = 0x%x, manufacture = 0x%x", charger->chip_id, manufacture_id); if (charger->chip_id < 0) { dev_err(dev, "BQ25713 rong, check dc 24V \n"); bq25713_parse_dt(charger); ret = bq25713_power_supply_init(charger); if (ret) { goto Err; } bq25713_DC24V_monitor(charger); bq25713_charger = charger; return 0; } if (!dev->platform_data) { ret = bq25713_fw_probe(charger); if (ret < 0) { dev_err(dev, "Cannot read device properties.\n"); return ret; } } else { return -ENODEV; } ret = bq25713_hw_init(charger); if (ret < 0) { dev_err(dev, "Cannot initialize the chip.\n"); return ret; } bq25713_parse_dt(charger); bq25713_init_sysfs(charger); ret = bq25713_power_supply_init(charger); if (ret) { goto Err; } bq25713_set_otg_enable(charger, 0); ret = bq25713_irq_init(charger); if (ret) { goto Err; } device_init_wakeup(dev, 1); bq25713_charger_monitor(charger); bq25713_notifier_register(charger); bq25713_charger = charger; DBG("bq25713 init successful!\n"); return 0; Err: DBG(“bq25713 init failed!!!\n”); power_supply_unregister(charger->supply_charger); return ret; }每一行代码注释
07-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值