Skip to main content
 首页 » 操作系统

Linux regulator系统知识点1

2022年07月19日172lori

1. 概念:
Regulator : 电源芯片, 比如电压转换芯片
Consumer : 消费者,使用电源的部件, Regulator是给Consumer供电的
machine : 单板,上面焊接有Regulator和Consumer
Constraints : 约束, 比如某个电源管理芯片输出的电压范围
Supply : 提供电源的部件, Regulator就是一个Supply; Regulator A可以给Regulator B供电, 那么Regulator B的Supply就是A

2. 写驱动程序:

(1). regulator驱动:
注册一个platform_driver: 在它的probe函数里分配、设置、注册一个regulator
"设置"里要做的事情: 实现regulator的操作, 比如enable, disable, set_voltage
(2). machine(单板)驱动:
注册一个platform_device: 在它的私有数据里指定regulator和consume的对应关系(这个电源芯片给哪一个部件供电)
指定约束条件(比如电压范围)
(3). consumer使用此电源的设备驱动:
使用即可: regulator_get, regulator_enable, regulator_disable, regulator_set_voltage....
注: 这只是没有使用设备树的情况下是这样的,其实就是以平台设备模型注册一个regulator,然后consumer去使用。

3. 不使用设备树的regulator_register流程分析:

    // 分配regulator_dev 
    rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); 
 
    /* set regulator constraints */ 
    set_machine_constraints 
    add_regulator_attributes 
     
    /* add consumers devices */ 
    set_consumer_device_supply 
        在regulator_map_list链表里生成一项regulator_map: 它里面有dev_name(consumer的名字),supply(cosumer的电源引脚名字) 
 
    // 把regulator_dev放入regulator_list 
    list_add(&rdev->list, &regulator_list);        

4. 使用设备树的regulator_register()和regulator_get()流程分析:

regulator_register(const struct regulator_desc *, const struct regulator_config *) //drivers/regulator/core.c 
    先自行各种检查,然后构造一个struct regulator_dev,从设备树中获取它的各种属性 
    regulator_of_get_init_data //drivers/regulator/of_regulator.c 
        of_get_regulation_constraints //drivers/regulator/of_regulator.c 通过设备树构造init_data,和约束 
            若设备树中指定了“regulator-initial-mode”且regulator_desc.of_map_mode()存在,则调用它 
    初始化rdev->consumer_list,rdev->list,rdev->notifier,指定rdev->disable_work=regulator_disable_work 
    如果init_data->regulator_init()存在则调用 
    判断是不是gpio控制的regulator,如果是就调用regulator_ena_gpio_request() 
    使rdev->dev.class = &regulator_class,此时sysfs下会有"regulator"文件夹,其下有regulator_dev_attrs中列出的文件。 
    自动递增设置&rdev->dev的name为"regulator.%lu" "regulator"下的"regulator.%lu"下才会有regulator_dev_attrs中列出的文件了。 
    set_machine_constraints 
    device_register(&rdev->dev) //注册到设备模型 
    dev_set_drvdata(&rdev->dev, rdev); 
    rdev_init_debugfs(rdev); 
 

使用设备树的regulator_get()流程分析:
struct regulator *regulator_get(struct device *dev, const char *id) //drivers/regulator/core.c, arg2为consumer的电源引脚 regulator_dev_lookup //drivers/regulator/core.c 使用devname与全局链表regulator_map_list中的每一项struct regulator_map->dev_name进行匹配,并返回匹配的struct regulator_dev结构体。 regulator_resolve_supply 还要和rdev->supply_name的名字逐个比较 create_regulator 根据struct regulator_dev创建一个struct regulator并返回

5.驱动示例代码

/* 文件名:machine.c 作为一个regulator平台设备模型的设备端。  
 * 参考: arch\arm\mach-omap2\board-2430sdp.c 
 * 这里只是注册一个单板的所有regulator的平台设备端,目前这类文件应该被设备树给替代了 
 */ 
 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/err.h> 
#include <linux/platform_device.h> 
#include <linux/regulator/driver.h> 
#include <linux/mfd/core.h> 
 
/* 分配/设置/注册regulator_init_data */ 
 
#if 0 
 regulator_consumer_supply: 
 const char *dev_name;     /* consumer的名字 */ 
 const char *supply;     /* consumer的电源引脚名称 */ 
 
#endif 
 
static struct regulator_consumer_supply myregulator_supplies[] = { 
    REGULATOR_SUPPLY("VCC", "mylcd"), /*此regulator是对设备"mylcd"上的"VCC"引脚供电的*/ 
}; 
 
 
static struct regulator_init_data myregulator_init_data = { 
    .constraints = { 
        .min_uV            = 12000000, 
        .max_uV            = 12000000, 
        .valid_modes_mask    = REGULATOR_MODE_NORMAL, 
        .valid_ops_mask        = REGULATOR_CHANGE_STATUS, 
    }, 
    .num_consumer_supplies    = ARRAY_SIZE(myregulator_supplies), 
    .consumer_supplies    = myregulator_supplies, 
}; 
 
static void myregulator_release(struct device * dev) 
{ 
} 
 
static struct platform_device myregulator_dev = { 
    .name         = "myregulator",  /* 平台设备设备端名字*/ 
    .id       = -1, 
    .dev = {  
        .release       = myregulator_release,  
        .platform_data = &myregulator_init_data, 
    }, 
}; 
 
/*使用设备树后就不再需要注册平台设备端了*/ 
static int myregulator_machine_init(void) 
{ 
    platform_device_register(&myregulator_dev); 
    return 0; 
} 
 
static void myregulator_machine_exit(void) 
{ 
    platform_device_unregister(&myregulator_dev); 
} 
 
module_init(myregulator_machine_init); 
module_exit(myregulator_machine_exit); 
 
MODULE_LICENSE("GPL v2");
/* 文件名:regulator.c 作为一个regulator平台设备模型的驱动端。  
 * 参考: drivers/regulator/tps6105x-regulator.c  
 * 其实machine.c充当的是平台设备的设备端,将单板上的所有regulator写在了一起,目前已被设备树替代。 
 * regulator.c充当的是平台设备的驱动端,每个regulator都可能有一个平台设备驱动端。 
 */ 
 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/err.h> 
#include <linux/platform_device.h> 
#include <linux/regulator/driver.h> 
#include <linux/mfd/core.h> 
 
static volatile unsigned long *gpbcon; 
static volatile unsigned long *gpbdat; 
 
static int myregulator_enable(struct regulator_dev *rdev) 
{ 
    *gpbdat |= 1;     /* 输出高电平 */ 
    return 0; 
} 
 
static int myregulator_disable(struct regulator_dev *rdev) 
{ 
    *gpbdat &= ~1;     /* 输出低电平 */ 
    return 0; 
} 
 
static int myregulator_is_enabled(struct regulator_dev *rdev) 
{ 
    if (*gpbdat & 1) 
        return 1; 
    else 
        return 0; 
} 
 
 
static struct regulator_ops myregulator_ops = { 
    .enable        = myregulator_enable, 
    .disable    = myregulator_disable, 
    .is_enabled    = myregulator_is_enabled, 
}; 
 
 
static struct regulator_desc myregulator_desc = { 
    .name        = "myregulator", 
    .ops        = &myregulator_ops, 
    .type        = REGULATOR_VOLTAGE, 
    .id        = 0, 
    .owner        = THIS_MODULE, 
    .n_voltages    = 1, /*只提供一种电压值得*/ 
}; 
 
static struct regulator_dev *myregulator_dev; 
static int myregulator_probe(struct platform_device *pdev) 
{ 
    struct regulator_init_data *init_data = dev_get_platdata(&pdev->dev); /*可以在platform_driver初始化的时候对dev赋值*//* 分配/设置/注册 regulator */ 
    myregulator_dev = regulator_register(&myregulator_desc, 
                         &pdev->dev, 
                         init_data, NULL, 
                         NULL); 
 
    if (IS_ERR(myregulator_dev)) { 
        printk("regulator_register error!\n"); 
        return -EIO; 
    } 
 
    return 0; 
} 
 
static int myregulator_remove(struct platform_device *pdev) 
{ 
    regulator_unregister(myregulator_dev); 
    return 0; 
} 
 
struct platform_driver myregulator_drv = { 
    .probe        = myregulator_probe, 
    .remove        = myregulator_remove, 
    .driver        = { 
        .name    = "myregulator",  /* 驱动上面regulator平台设备的设备端 */ 
    } 
}; 
 
static int myregulator_init(void) 
{ 
    platform_driver_register(&myregulator_drv); 
    return 0; 
} 
 
static void myregulator_exit(void) 
{ 
    platform_driver_unregister(&myregulator_drv); 
} 
 
module_init(myregulator_init); 
module_exit(myregulator_exit); 
 
MODULE_LICENSE("GPL v2");
/* 文件名:consumer_lcd.c 作为一个consumer驱动 
 *  
 */ 
static int mylcd_open(struct fb_info *info, int user) 
{ 
    pm_runtime_get_sync(&lcd_dev.dev); 
    return 0; 
} 
static int mylcd_release(struct fb_info *info, int user) 
{ 
    pm_runtime_mark_last_busy(&lcd_dev.dev); 
    pm_runtime_put_sync_autosuspend(&lcd_dev.dev); 
    return 0; 
} 
 
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; 
    } 
} 
 
static struct notifier_block lcd_pm_notif_block = { 
    .notifier_call = lcd_suspend_notifier, 
}; 
 
static void lcd_release(struct device * dev) 
{ 
} 
 
static struct platform_device lcd_dev = { /* regulator匹配1 */ 
    .name         = "mylcd", 
    .id       = -1, 
    .dev = {  
        .release = lcd_release,  
    }, 
}; 
 
static struct regulator *myregulator; 
 
static int lcd_probe(struct platform_device *pdev) 
{ 
    myregulator = regulator_get(pdev->dev, "VCC"); /* regulator 匹配2 */ 
    if (IS_ERR(myregulator)) { 
        printk("regulator_get error!\n"); 
        return -EIO; 
    } 
    regulator_enable(myregulator); /*没有它会报unblance regulator disable of myregulator*/ 
 
    pm_runtime_set_active(&pdev->dev); 
    pm_runtime_use_autosuspend(&pdev->dev); 
    pm_runtime_enable(&pdev->dev); 
    return 0; 
} 
static int lcd_remove(struct platform_device *pdev) 
{ 
    regulator_put(myregulator); 
    pm_runtime_disable(&pdev->dev); 
    return 0; 
} 
static int lcd_suspend(struct device *dev) 
{ 
    int i; 
    unsigned long *dest = &lcd_regs_backup; 
    unsigned long *src  = lcd_regs; 
     
    for (i = 0; i < sizeof(lcd_regs_backup)/sizeof(unsigned long); i++) 
    { 
        dest[i] = src[i]; 
    } 
     
    lcd_regs->lcdcon1 &= ~(1<<0); /* 关闭LCD本身 */ 
    //*gpbdat &= ~1;     /* 关闭背光 */ 
    regulator_disable(myregulator); 
    return 0; 
} 
 
static int lcd_resume(struct device *dev) 
{ 
    int i; 
    unsigned long *dest = lcd_regs; 
    unsigned long *src  = &lcd_regs_backup; 
 
    struct clk *clk = clk_get(NULL, "lcd"); 
    clk_enable(clk); 
    clk_put(clk); 
 
    for (i = 0; i < sizeof(lcd_regs_backup)/sizeof(unsigned long); i++) 
    { 
        dest[i] = src[i]; 
    } 
 
    regulator_enable(myregulator); 
    return 0; 
} 
 
static struct dev_pm_ops lcd_pm = { 
    .suspend = lcd_suspend, 
    .resume  = lcd_resume,     
    .runtime_suspend = lcd_suspend, 
    .runtime_resume  = lcd_resume,     
}; 
 
struct platform_driver lcd_drv = { 
    .probe        = lcd_probe, 
    .remove        = lcd_remove, 
    .driver        = { 
        .name    = "mylcd", 
        .pm     = &lcd_pm, 
    } 
}; 
 
 
static int lcd_init(void) 
{     
    /* 电源管理 */ 
    register_pm_notifier(&lcd_pm_notif_block); 
 
    platform_device_register(&lcd_dev); 
    platform_driver_register(&lcd_drv); 
     
    return 0; 
} 
 
static void lcd_exit(void) 
{     
    unregister_pm_notifier(&lcd_pm_notif_block); 
    platform_device_unregister(&lcd_dev); 
    platform_driver_unregister(&lcd_drv); 
} 
 
module_init(lcd_init); 
module_exit(lcd_exit); 
 
MODULE_LICENSE("GPL");

本文参考链接:https://www.cnblogs.com/hellokitty2/p/9975711.html