linux驱动程序之电源管理之新版linux系统设备架构中关于电源管理方式的变更

2023-06-19  

新版linux系统设备架构中关于电源管理方式的变更 based on linux-2.6.32

 

一、设备模型各数据结构中电源管理的部分

  linux的设备模型通过诸多结构体来联合描述,如struct device,struct device_type,struct class, struct device_driver,struct bus_type等。

@kernel/include/linux/devices.h中有这几中结构体的定义,这里只列出和PM有关的项,其余查看源码:      

struct device{    

...    

struct dev_pm_info power;     

...   

}      

 

struct device_type {    

...    

int (*uevent)(struct device *dev, struct kobj_uevent_env *env);    

char *(*devnode)(struct device *dev, mode_t *mode);    

void (*release)(struct device *dev);       

const struct dev_pm_ops *pm;   

};      

 

struct class {    

...    

void (*class_release)(struct class *class);   

void (*dev_release)(struct device *dev);       

int (*suspend)(struct device *dev, pm_message_t state);    

int (*resume)(struct device *dev);       

const struct dev_pm_ops *pm;    

...   

};

    

struct device_driver {    

...    

int (*probe) (struct device *dev);    

int (*remove) (struct device *dev);    

void (*shutdown) (struct device *dev);    

int (*suspend) (struct device *dev, pm_message_t state);    

int (*resume) (struct device *dev);       

const struct dev_pm_ops *pm;    

...   

};

     

struct bus_type {    

...    

int (*match)(struct device *dev, struct device_driver *drv);    

int (*uevent)(struct device *dev, struct kobj_uevent_env *env);    

int (*probe)(struct device *dev);    

int (*remove)(struct device *dev);    

void (*shutdown)(struct device *dev);       

int (*suspend)(struct device *dev, pm_message_t state);    

int (*resume)(struct device *dev);

const struct dev_pm_ops *pm;    

...   

};      

以上可以看出和电源管理相关的两个结构体是struct dev_pm_info和struct dev_pm_ops,他们定义于文件   @kernel/include/linux/pm.h      

struct dev_pm_info {    

pm_message_t  power_state;    

unsigned int  can_wakeup:1;    

unsigned int  should_wakeup:1;    

enum dpm_state  status;  /* Owned by the PM core - 表示该设备当前的PM状态*/   

#ifdef CONFIG_PM_SLEEP    

struct list_head entry;  /* 链接到dpm_list全局链表中的连接体 */   

#endif   

#ifdef CONFIG_PM_RUNTIME   // undef    

struct timer_list suspend_timer;    

unsigned long  timer_expires;    

struct work_struct work;    

wait_queue_head_t wait_queue;    

spinlock_t  lock;    

atomic_t  usage_count;    

atomic_t  child_count;    

unsigned int  disable_depth:3;    

unsigned int  ignore_children:1;    

unsigned int  idle_notification:1;    

unsigned int  request_pending:1;    

unsigned int  deferred_resume:1;   

enum rpm_request request;    

enum rpm_status  runtime_status;   

int   runtime_error;   

#endif   

};   

  

struct dev_pm_ops {    

int (*prepare)(struct device *dev);    

void (*complete)(struct device *dev);   

int (*suspend)(struct device *dev);    

int (*resume)(struct device *dev);    

int (*freeze)(struct device *dev);    

int (*thaw)(struct device *dev);    

int (*poweroff)(struct device *dev);    

int (*restore)(struct device *dev);    

int (*suspend_noirq)(struct device *dev);    

int (*resume_noirq)(struct device *dev);    

int (*freeze_noirq)(struct device *dev);    

int (*thaw_noirq)(struct device *dev);    

int (*poweroff_noirq)(struct device *dev);    

int (*restore_noirq)(struct device *dev);    

int (*runtime_suspend)(struct device *dev);    

int (*runtime_resume)(struct device *dev);    

int (*runtime_idle)(struct device *dev);

  };

 

 

二、device中的dev_pm_info结构体

  device结构体中的power项用来将该设备纳入电源管理的范围,记录电源管理的一些信息。   在注册设备的时候调用函数device_add()来向sysfs系统添加power接口和注册进电源管理系统,代码片段如下:   

...   

error = dpm_sysfs_add(dev);  @kernel/drivers/base/power/sysfs.c   

if (error)    

goto DPMError;   

device_pm_add(dev);      @kernel/drivers/base/power/main.c   

...   

其中dpm_sysfs_add()函数用来向sysfs文件系统中添加相应设备的power接口文件,如注册mt6516_tpd paltform device的时候,会在sysfs中出现如下目录和文件:   

#pwd   

/sys/devices/platform/mt6516-tpd   

#cd mt6516-tpd   

#ls -l   

-rw-r--r-- root     root         4096 2010-01-02 06:35 uevent   

-r--r--r-- root     root         4096 2010-01-02 06:39 modalias   

lrwxrwxrwx root     root              2010-01-02 06:39 subsystem -> ../../../bus/platform   

drwxr-xr-x root     root              2010-01-02 06:35 power   

lrwxrwxrwx root     root              2010-01-02 06:39 driver -> ../../../bus/platform/drivers/mt6516-tpd   

#cd power   

#ls -l   

-rw-r--r-- root     root         4096 2010-01-02 06:39 wakeup      

 

源码片段:   

static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);

static struct attribute * power_attrs[] = {    

&dev_attr_wakeup.attr,    

NULL,   

};   

 

static struct attribute_group pm_attr_group = {    

.name = "power",  // attribute_group结构体的name域不为NULL的话,都会已name建立一个属性目录的    

.attrs = power_attrs,   

};      

 

int dpm_sysfs_add(struct device * dev)   {    

return sysfs_create_group(&dev->kobj, &pm_attr_group); //在当前device的kobject结构体对应的目录下建立   

}      

其中的device_pm_add()函数会将该设备插入到电源管理的核心链表dpm_list中统一管理。   

值得一提的是,在函数device_initialize()会调用函数device_pm_init()来初始化该device结构体的power域:   

dev->power.status = DPM_ON;

     

void device_pm_add(struct device *dev)   {    

...    

mutex_lock(&dpm_list_mtx);    

if (dev->parent) {     

if (dev->parent->power.status >= DPM_SUSPENDING)       // 如果某设备处于DPM_SUSPENDING极其之后的状态,此时不允许以该设备为父设备注册子设备      

dev_warn(dev, "parent %s should not be sleeping/n", dev_name(dev->parent));    

}

else if (transition_started) { // transition_started全局变量包含在PM transition期间不允许注册设备     

/*     

* We refuse to register parentless devices while a PM     

* transition is in progress in order to avoid leaving them     

* unhandled down the road     

*/     

dev_WARN(dev, "Parentless device registered during a PM transaction/n");    

}       

list_add_tail(&dev->power.entry, &dpm_list); // 将device结构体通过power.entry项链接进dpm_list    

mutex_unlock(&dpm_list_mtx);   

}      

 

void device_pm_remove(struct device *dev)   {    

...    

mutex_lock(&dpm_list_mtx);    

list_del_init(&dev->power.entry);    

mutex_unlock(&dpm_list_mtx);    

pm_runtime_remove(dev);   

}

 

  举例说明:      

我们熟知的platform bus在系统中也是作为一种设备注册进了系统,在sysfs文件系统中的位置是:   /sys/devices/platform。使用函数device_register(&platform_bus)进行注册,调用device_add()函数,   

注册ok之后,也会出现目录/sys/devices/platform/power。最后也会将其添加进dpm_list中。      

i2c控制器外设代表的设备是注册在platform总线上的,也就是说它的父设备是platform。   

最终在platform_device_add()中会调用函数device_add()函数来添加设备,最终也会在mt6516-i2c.0/   mt6516-i2c.1/mt6516-i2c.2中出现一个power目录,同时这3个platform设备会依靠   platform_device.dev.power.entry连接件链接到电源管理核心链表dpm_list中。   

/sys/devices/platform/mt6516-i2c.2/power   

  

每一个i2c控制器都会在系统中至少注册成一个适配器(adapter),该结构体将会间接提供给i2c设备的驱动来使用,以避免直接使用i2c控制器结构体。

这个适配器没有对应的driver,在错综复杂的i2c架构中,相对于只起到了一个承上启下的作用,上接i2c控制器的结构体及driver,下接i2c设备的结构体i2c_client和特点的driver。

adapter.dev.parent为i2c控制器对应的device,所以就会出现名为i2c-0/1/2的设备kobject,只是该设备的bus总线和device_type是:   adap->dev.bus = &i2c_bus_type;   

adap->dev.type = &i2c_adapter_type;   

然后调用函数device_register(&adap->dev);来注册这个device,所以在对应的i2c-0/1/2目录下也会出现power目录。   /sys/devices/platform/mt6516-i2c.2/i2c-2/power      

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。