Regulator:矫正器,调整器,实际上就是一个电源芯片。比如jz2440上的LCD背光就是由下图所示的电源芯片供电的,操作EN引脚即可使能该芯片。
概念:
Regulator : 电源芯片, 比如电压转换芯片
Consumer : 消费者,使用电源的部件, Regulator是给Consumer供电的
machine : 单板,上面焊接有Regulator和Consumer
Constraints : 约束, 比如某个电源管理芯片输出的电压范围
Supply : 提供电源的部件, Regulator就是一个Supply; Regulator A可以给Regulator B供电, 那么Regulator B的Supply就是A
Regulator系统的框架如下图所示,分为图中标号的三部分。
所以Regulator系统的驱动程序可以分为三个部分:
写驱动程序:
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.c详解:
/* 参考: drivers/regulator/tps6105x-regulator.c */
#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);
gpbcon = ioremap(0x56000010, 8); //为什么要映射?直接操作这个地址不行吗?
gpbdat = gpbcon+1;
*gpbcon &= ~(3); /* GPB0设置为输出引脚 */
*gpbcon |= 1;
/* 分配/设置/注册 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",
}
};
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");
Machine详解:
/* 参考: arch\arm\mach-omap2\board-2430sdp.c
*/
#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的电源引脚名称 ,一个consumer可能有多个电源*/
#endif
static struct regulator_consumer_supply myregulator_supplies[] = {
REGULATOR_SUPPLY("VCC", "mylcd"),
};
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 = 1,
.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_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, ®ulator_list);
如下图所示:
Consumer里面如果想使用regulator的话,只需要执行regulator_get函数就好,执行该函数后就会遍历regulator_list链表中的设备,如果能找到对应的regulator_map,说明就找到了这个regulator设备。
Consumer_lcd_4.3.c中添加的核心函数:
myregulator = regulator_get(pdev->dev, "VCC");
regulator_enable(myregulator); //使能背光电源。但是不明白这个函数最终是否调用到了register_driver下的ops的myregular_enable函数?
regulator_disable(myregulator); //禁止背光电源