在上上篇文章中,我们梳理过流程,休眠前后和驱动打交道主要就这两个函数:
a. 通知notifier:
在冻结APP之前,使用pm_notifier_call_chain(PM_SUSPEND_PREPARE)来通知驱动程序
在重启APP之后,使用pm_notifier_call_chain(PM_POST_SUSPEND)来通知驱动程序
如果驱动程序有事情在上述时机要处理,可以使用register_pm_notifier注册一个notifier。
int pm_notifier_call_chain(unsigned long val)
{
int ret = blocking_notifier_call_chain(&pm_chain_head, val, NULL);
return notifier_to_errno(ret);
}
int register_pm_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&pm_chain_head, nb);
}
先看看结构体
struct notifier_block {
notifier_fn_t notifier_call;
struct notifier_block __rcu *next;
int priority;
};
这里面有一个nofifi
示例代码:
//定义一个notifier_block结构体,并给其notifier_call函数赋值
static struct notifier_block lcd_pm_notif_block = {
.notifier_call = lcd_suspend_notifier,
};
static int lcd_suspend_notifier(struct notifier_block *nb,
unsigned long event,
void *dummy)
{
switch (event) {
//休眠时会走到这里
case PM_SUSPEND_PREPARE:
printk("lcd suspend notifiler test: PM_SUSPEND_PREPARE\n");
return NOTIFY_OK;
//唤醒后会走这里
case PM_POST_SUSPEND:
printk("lcd suspend notifiler test: PM_POST_SUSPEND\n");
return NOTIFY_OK;
default:
return NOTIFY_DONE;
}
}
驱动程序的冻结方法应该是在冻结应用进程之后,因为app有可能还在使用驱动,方法1pm_notifier_call_chain(PM_SUSPEND_PREPARE)是在冻结应用之前调用的。所以一般是使用方法2,如下:
方法2:通过平台框架来写suspend和resume函数
通过前面介绍,让设备进入休眠会走入一下流程
对于该设备,调用它的dev->pm_domain->ops->suspend 或
dev->type->pm->suspend 或
dev->class->pm->suspend 或
dev->bus->pm->suspend 或
dev->driver->pm->suspend
dev即
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
};
struct device_driver {
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
const struct of_device_id *of_match_table;
const struct acpi_device_id *acpi_match_table;
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 attribute_group **groups;
const struct dev_pm_ops *pm; //pm结构体
struct driver_private *p;
};
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);
...
};
static struct platform_device lcd_dev = {
.name = "mylcd",
.id = -1,
.dev = {
.release = lcd_release,
},
};
struct platform_driver lcd_drv = {
.probe = lcd_probe,
.remove = lcd_remove,
.driver = {
.name = "mylcd",
.pm = &lcd_pm,
}
};
//定义结构体的suspend和resume
static struct dev_pm_ops lcd_pm = {
.suspend = lcd_suspend,
.resume = lcd_resume,
};
static int lcd_init(void)
{
/* 电源管理 */
register_pm_notifier(&lcd_pm_notif_block);
platform_device_register(&lcd_dev);//注册平台设备
platform_driver_register(&lcd_drv);//注册平台driver
...
}
static int lcd_suspend(struct device *dev)
{
lcd_regs->lcdcon1 &= ~(1<<0); /* 关闭LCD本身 */
*gpbdat &= ~1; /* 关闭背光 */
return 0;
}
static int lcd_resume(struct device *dev)
{
lcd_regs->lcdcon1 |= (1<<0); /* 使能LCD控制器 */
lcd_regs->lcdcon5 |= (1<<3); /* 使能LCD本身 */
*gpbdat |= 1; /* 输出高电平, 使能背光 */
return 0;
}