电源调节器框架与帧缓冲驱动详解
1. 电源调节器框架
电源调节器框架为需要根据工作模式调整电源供应的设备提供了多种控制和状态管理功能。
1.1 电压控制与状态
内核提供了
regulator_set_voltage
函数来设置电压范围:
int regulator_set_voltage(regulator, min_uV, max_uV);
其中,
min_uV
和
max_uV
分别是可接受的最小和最大电压(单位为微伏)。若在调节器禁用时调用此函数,会更改电压配置,待调节器下次启用时物理设置电压。
可通过
regulator_get_voltage
函数获取配置的输出电压:
int regulator_get_voltage(regulator);
示例代码如下:
printk (KERN_INFO "Regulator Voltage = %d\n", regulator_get_voltage(reg));
1.2 电流限制控制与状态
与电压控制类似,可使用
regulator_set_current_limit
函数设置电流限制范围:
int regulator_set_current_limit(regulator, min_uA, max_uA);
min_uA
和
max_uA
分别是可接受的最小和最大电流限制(单位为微安)。
使用
regulator_get_current_limit
函数获取配置的电流限制:
int regulator_get_current_limit(regulator);
1.3 操作模式控制与状态
为实现高效电源管理,一些设备可在工作状态改变时更改电源的操作模式。可通过以下函数请求更改调节器的操作模式:
int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
int regulator_set_mode(struct regulator *regulator, unsigned int mode);
unsigned int regulator_get_mode(struct regulator *regulator);
regulator_set_mode
为直接模式,适用于设备了解调节器且不与其他设备共享的情况;
regulator_set_optimum_mode
为间接模式,内核会进行一些后台工作以确定最适合请求电流的操作模式。
1.4 调节器绑定
消费者节点可使用以下绑定引用其一个或多个电源/调节器:
<name>-supply: phandle to the regulator node
<name>
应具有足够的意义,以便驱动程序在请求调节器时能轻松引用,且必须与
regulator_get()
函数的
*id
参数匹配。
示例代码如下:
twl_reg1: regulator@0 {
[...]
};
twl_reg2: regulator@1 {
[...]
};
mmc: mmc@0x0 {
[...]
vmmc-supply = <&twl_reg1>;
vmmcaux-supply = <&twl_reg2>;
};
消费者代码示例:
struct regulator *main_regulator;
struct regulator *aux_regulator;
int ret;
main_regulator = devm_regulator_get(dev, "vmmc");
if (!IS_ERR(io_regulator)) {
regulator_set_voltage(main_regulator,
MMC_VOLTAGE_DIGITAL,
MMC_VOLTAGE_DIGITAL);
ret = regulator_enable(io_regulator);
}
aux_regulator = devm_regulator_get(dev, "vmmcaux");
2. 帧缓冲驱动
帧缓冲驱动是Linux下最简单的图形驱动形式,通过字符设备暴露视频卡功能,用户空间可通过
/dev/fbX
条目访问。
2.1 帧缓冲驱动的数据结构
帧缓冲驱动主要依赖四个数据结构,均定义在
include/linux/fb.h
中:
-
fb_var_screeninfo
:保存视频卡的可变属性,如分辨率深度等。
struct fb_var_screeninfo {
__u32 xres; /* visible resolution */
__u32 yres;
__u32 xres_virtual; /* virtual resolution */
__u32 yres_virtual;
__u32 xoffset; /* offset from virtual to visible resolution */
__u32 yoffset;
__u32 bits_per_pixel; /* # of bits needed to hold a pixel */
[...]
__u32 pixclock; /* pixel clock in ps (pico seconds) */
__u32 left_margin; /* time from sync to picture */
__u32 right_margin; /* time from picture to sync */
__u32 upper_margin; /* time from sync to picture */
__u32 lower_margin;
__u32 hsync_len; /* length of horizontal sync */
__u32 vsync_len; /* length of vertical sync */
__u32 rotate; /* angle we rotate counter clockwise */
};
-
fb_fix_screeninfo:保存视频卡的固定属性,如帧缓冲内存的起始地址等。
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
/* (physical address) */
__u32 smem_len;/* Length of frame buffer mem */
__u32 type; /* see FB_TYPE_* */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /* see FB_VISUAL_* */
__u16 xpanstep; /* zero if no hardware panning */
__u16 ypanstep; /* zero if no hardware panning */
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* length of a line in bytes */
unsigned long mmio_start; /* Start of Memory Mapped I/O
*(physical address)
*/
__u32 mmio_len; /* Length of Memory Mapped I/O */
__u32 accel; /* Indicate to driver which */
/* specific chip/card we have */
__u16 capabilities; /* see FB_CAP_* */
};
-
fb_cmap:指定颜色映射,用于存储用户定义的颜色。
struct fb_cmap {
__u32 start; /* First entry */
__u32 len; /* Number of entries */
__u16 *red; /* Red values */
__u16 *green; /* Green values */
__u16 *blue; /* Blue values */
__u16 *transp; /* Transparency. Discussed later on */
};
-
fb_info:表示帧缓冲本身,是帧缓冲驱动的主要数据结构。
struct fb_info {
[...]
struct fb_var_screeninfo var; /* Variable screen information.
Discussed earlier. */
struct fb_fix_screeninfo fix; /* Fixed screen information. */
struct fb_cmap cmap; /* Color map. */
struct fb_ops *fbops; /* Driver operations.*/
char __iomem *screen_base; /* Frame buffer's
virtual address */
unsigned long screen_size; /* Frame buffer's size */
[...]
struct device *device; /* This is the parent */
struct device *dev; /* This is this fb device */
#ifdef CONFIG_FB_BACKLIGHT
/* assigned backlight device */
/* set before framebuffer registration,
remove after unregister */
struct backlight_device *bl_dev;
/* Backlight level curve */
struct mutex bl_curve_mutex;
u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
[...]
void *par; /* Pointer to private memory */
};
使用
framebuffer_alloc
函数动态分配
fb_info
结构:
struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
使用
framebuffer_release
函数释放:
void framebuffer_release(struct fb_info *info)
使用
register_framebuffer
函数注册帧缓冲:
int register_framebuffer(struct fb_info *fb_info)
使用
unregister_framebuffer
函数注销:
int unregister_framebuffer(struct fb_info *fb_info)
2.2 设备方法
fb_info
结构中的
fbops
字段是
fb_ops
结构的实例,包含一系列对帧缓冲设备进行操作的函数:
struct fb_ops {
/* open/release and usage marking */
struct module *owner;
int (*fb_open)(struct fb_info *info, int user);
int (*fb_release)(struct fb_info *info, int user);
/* For framebuffers with strange nonlinear layouts or that do not
* work with normal memory mapped access
*/
ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
size_t count, loff_t *ppos);
ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos);
/* checks var and eventually tweaks it to something supported,
* DO NOT MODIFY PAR */
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info
*info);
/* set the video mode according to info->var */
int (*fb_set_par)(struct fb_info *info);
/* set color register */
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info);
/* set color registers in batch */
int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
/* blank display */
int (*fb_blank)(int blank_mode, struct fb_info *info);
/* pan display */
int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info
*info);
/* Draws a rectangle */
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect
*rect);
/* Copy data from area to another */
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea
*region);
/* Draws a image to the display */
void (*fb_imageblit) (struct fb_info *info, const struct fb_image
*image);
/* Draws cursor */
int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
/* wait for blit idle, optional */
int (*fb_sync)(struct fb_info *info);
/* perform fb specific ioctl (optional) */
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
unsigned long arg);
/* Handle 32bit compat ioctl (optional) */
int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
unsigned long arg);
/* perform fb specific mmap */
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
/* get capability given var */
void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
struct fb_var_screeninfo *var);
/* teardown any resources to do with this framebuffer */
void (*fb_destroy)(struct fb_info *info);
[...]
};
fb_ops
与
file_operations
结构不同,
fb_ops
提供底层操作的抽象,而
file_operations
用于上层系统调用接口。内核在
drivers/video/fbdev/core/fbmem.c
中实现帧缓冲文件操作,内部调用
fb_ops
中定义的方法。
帧缓冲设备支持
include/uapi/linux/fb.h
中定义的一些
ioctl
命令,用户程序可使用这些命令操作硬件。
fb_ops.fb_ioctl
在给定的
ioctl
命令内核未知时执行。
2.3 驱动方法
驱动方法包括
probe()
和
remove()
函数。首先设置
fb_ops
结构:
static struct fb_ops myfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = myfb_check_var,
.fb_set_par = myfb_set_par,
.fb_setcolreg = myfb_setcolreg,
.fb_fillrect = cfb_fillrect, /* Those three hooks are */
.fb_copyarea = cfb_copyarea, /* non accelerated and */
.fb_imageblit = cfb_imageblit, /* are provided by kernel */
.fb_blank = myfb_blank,
};
probe()
函数负责初始化硬件、创建
fb_info
结构并注册:
static int myfb_probe(struct platform_device *pdev)
{
struct fb_info *info;
struct resource *res;
[...]
dev_info(&pdev->dev, "My framebuffer driver\n");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
/* use request_mem_region(), ioremap() and so on */
[...]
pwr = regulator_get(&pdev->dev, "lcd");
info = framebuffer_alloc(sizeof(
struct my_private_struct), &pdev->dev);
if (!info)
return -ENOMEM;
/* Device init and default info value*/
[...]
info->fbops = &myfb_ops;
/* Clock setup, using devm_clk_get() and so on */
[...]
/* DMA setup using dma_alloc_coherent() and so on*/
[...]
ret = register_framebuffer(info);
hardware_enable_controller(my_private_struct);
return 0;
}
remove()
函数释放
probe()
中获取的资源:
static int myfb_remove(struct platform_device *pdev)
{
/* iounmap() memory and release_mem_region() */
[...]
/* Reverse DMA, dma_free_*();*/
[...]
hardware_disable_controller(fbi);
/* first unregister, */
unregister_framebuffer(info);
/* and then free the memory */
framebuffer_release(info);
return 0;
}
2.4 详细的fb_ops钩子
fb_ops->fb_check_var
钩子负责检查帧缓冲参数:
int (*fb_check_var)(struct fb_var_screeninfo *var,
struct fb_info *info);
示例代码如下:
static int myfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres;
if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres;
if ((var->bits_per_pixel != 32) &&
(var->bits_per_pixel != 24) &&
(var->bits_per_pixel != 16) &&
(var->bits_per_pixel != 12) &&
(var->bits_per_pixel != 8))
var->bits_per_pixel = 16;
switch (var->bits_per_pixel) {
case 8:
/* Adjust red*/
var->red.length = 3;
var->red.offset = 5;
var->red.msb_right = 0;
/*adjust green*/
var->green.length = 3;
var->green.offset = 2;
var->green.msb_right = 0;
/* adjust blue */
var->blue.length = 2;
var->blue.offset = 0;
var->blue.msb_right = 0;
/* Adjust transparency */
var->transp.length = 0;
var->transp.offset = 0;
var->transp.msb_right = 0;
break;
case 16:
// 后续代码可根据实际情况补充
总结
本文详细介绍了电源调节器框架和帧缓冲驱动的相关知识。电源调节器框架提供了电压、电流限制和操作模式的控制与状态管理功能,以及调节器绑定的方法。帧缓冲驱动依赖于多个数据结构,通过
fb_ops
结构实现对帧缓冲设备的操作,驱动方法包括
probe()
和
remove()
函数。这些知识对于开发相关的硬件驱动和进行电源管理、图形显示等操作具有重要意义。
流程图
graph TD
A[电源调节器框架] --> B[电压控制与状态]
A --> C[电流限制控制与状态]
A --> D[操作模式控制与状态]
A --> E[调节器绑定]
F[帧缓冲驱动] --> G[驱动数据结构]
F --> H[设备方法]
F --> I[驱动方法]
F --> J[详细的fb_ops钩子]
表格
| 功能 | 相关函数 |
|---|---|
| 电压控制 |
regulator_set_voltage
、
regulator_get_voltage
|
| 电流限制控制 |
regulator_set_current_limit
、
regulator_get_current_limit
|
| 操作模式控制 |
regulator_set_optimum_mode
、
regulator_set_mode
、
regulator_get_mode
|
| 帧缓冲分配与释放 |
framebuffer_alloc
、
framebuffer_release
|
| 帧缓冲注册与注销 |
register_framebuffer
、
unregister_framebuffer
|
电源调节器框架与帧缓冲驱动详解
3. 电源调节器框架操作总结
电源调节器框架的各项操作可以总结为以下表格,方便快速查阅:
| 操作类型 | 函数名称 | 功能描述 | 参数说明 |
| ---- | ---- | ---- | ---- |
| 电压控制 |
regulator_set_voltage
| 设置电压范围 |
regulator
:调节器对象;
min_uV
:最小电压(微伏);
max_uV
:最大电压(微伏) |
| |
regulator_get_voltage
| 获取配置的输出电压 |
regulator
:调节器对象 |
| 电流限制控制 |
regulator_set_current_limit
| 设置电流限制范围 |
regulator
:调节器对象;
min_uA
:最小电流限制(微安);
max_uA
:最大电流限制(微安) |
| |
regulator_get_current_limit
| 获取配置的电流限制 |
regulator
:调节器对象 |
| 操作模式控制 |
regulator_set_optimum_mode
| 间接模式设置最佳操作模式 |
regulator
:调节器对象;
load_uA
:请求的电流 |
| |
regulator_set_mode
| 直接模式设置操作模式 |
regulator
:调节器对象;
mode
:操作模式 |
| |
regulator_get_mode
| 获取操作模式 |
regulator
:调节器对象 |
4. 帧缓冲驱动操作流程
帧缓冲驱动的操作流程可以用以下 mermaid 流程图表示:
graph LR
A[设备探测] --> B[分配 fb_info 结构]
B --> C[设置 fb_ops 结构]
C --> D[初始化硬件]
D --> E[注册帧缓冲]
E --> F[设备正常使用]
F --> G[设备移除]
G --> H[注销帧缓冲]
H --> I[释放 fb_info 结构]
5. 详细代码分析
5.1 电源调节器框架代码示例分析
以下是一个简单的电源调节器使用示例,展示了如何设置电压和获取电压:
#include <linux/regulator/consumer.h>
// 获取调节器
struct regulator *reg = regulator_get(dev, "my_regulator");
if (IS_ERR(reg)) {
// 处理错误
return PTR_ERR(reg);
}
// 设置电压
int ret = regulator_set_voltage(reg, 1800000, 1800000); // 设置为 1.8V
if (ret) {
// 处理错误
regulator_put(reg);
return ret;
}
// 获取电压
int voltage = regulator_get_voltage(reg);
printk(KERN_INFO "Regulator Voltage = %d\n", voltage);
// 释放调节器
regulator_put(reg);
5.2 帧缓冲驱动代码示例分析
以下是一个简化的帧缓冲驱动
probe()
和
remove()
函数示例:
#include <linux/fb.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
// 假设的检查变量函数
static int myfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) {
if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres;
if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres;
if ((var->bits_per_pixel != 32) &&
(var->bits_per_pixel != 24) &&
(var->bits_per_pixel != 16) &&
(var->bits_per_pixel != 12) &&
(var->bits_per_pixel != 8))
var->bits_per_pixel = 16;
return 0;
}
// 假设的设置参数函数
static int myfb_set_par(struct fb_info *info) {
// 设置参数的具体实现
return 0;
}
// 假设的设置颜色寄存器函数
static int myfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info) {
// 设置颜色寄存器的具体实现
return 0;
}
// 假设的空白显示函数
static int myfb_blank(int blank_mode, struct fb_info *info) {
// 空白显示的具体实现
return 0;
}
// 设置 fb_ops 结构
static struct fb_ops myfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = myfb_check_var,
.fb_set_par = myfb_set_par,
.fb_setcolreg = myfb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_blank = myfb_blank,
};
// probe 函数
static int myfb_probe(struct platform_device *pdev) {
struct fb_info *info;
struct resource *res;
struct regulator *pwr;
int ret;
dev_info(&pdev->dev, "My framebuffer driver\n");
// 查询资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
// 获取电源调节器
pwr = regulator_get(&pdev->dev, "lcd");
if (IS_ERR(pwr)) {
return PTR_ERR(pwr);
}
// 分配 fb_info 结构
info = framebuffer_alloc(sizeof(struct my_private_struct), &pdev->dev);
if (!info) {
regulator_put(pwr);
return -ENOMEM;
}
// 设备初始化和默认信息设置
info->fbops = &myfb_ops;
// 时钟设置
// ...
// DMA 设置
// ...
// 注册帧缓冲
ret = register_framebuffer(info);
if (ret) {
framebuffer_release(info);
regulator_put(pwr);
return ret;
}
// 启用硬件控制器
hardware_enable_controller(info);
return 0;
}
// remove 函数
static int myfb_remove(struct platform_device *pdev) {
struct fb_info *info = platform_get_drvdata(pdev);
struct regulator *pwr = regulator_get(&pdev->dev, "lcd");
// 禁用硬件控制器
hardware_disable_controller(info);
// 注销帧缓冲
unregister_framebuffer(info);
// 释放 fb_info 结构
framebuffer_release(info);
// 释放电源调节器
regulator_put(pwr);
return 0;
}
// 平台驱动结构
static struct platform_driver myfb_driver = {
.probe = myfb_probe,
.remove = myfb_remove,
.driver = {
.name = "myfb",
},
};
// 模块初始化
static int __init myfb_init(void) {
return platform_driver_register(&myfb_driver);
}
// 模块退出
static void __exit myfb_exit(void) {
platform_driver_unregister(&myfb_driver);
}
module_init(myfb_init);
module_exit(myfb_exit);
MODULE_LICENSE("GPL");
6. 总结与展望
通过本文的介绍,我们详细了解了电源调节器框架和帧缓冲驱动的相关知识。电源调节器框架为设备的电源管理提供了灵活的控制手段,而帧缓冲驱动则为图形显示提供了基础支持。
在实际开发中,我们可以根据具体的硬件需求和应用场景,灵活运用这些知识,开发出高效、稳定的硬件驱动程序。未来,随着硬件技术的不断发展,电源管理和图形显示的需求也会不断提高,我们需要不断学习和探索新的技术和方法,以满足这些需求。
列表总结
- 电源调节器框架提供了电压、电流限制和操作模式的控制功能,通过相应的函数可以方便地进行设置和查询。
-
帧缓冲驱动依赖于多个数据结构,通过
fb_ops结构实现对帧缓冲设备的操作,驱动方法包括probe()和remove()函数。 -
开发帧缓冲驱动时,需要注意动态分配和释放
fb_info结构,以及正确注册和注销帧缓冲设备。
表格补充
| 数据结构 | 作用 |
|---|---|
fb_var_screeninfo
| 保存视频卡的可变属性,如分辨率、像素时钟等 |
fb_fix_screeninfo
| 保存视频卡的固定属性,如帧缓冲内存起始地址等 |
fb_cmap
| 指定颜色映射,用于存储用户定义的颜色 |
fb_info
| 表示帧缓冲本身,是帧缓冲驱动的主要数据结构 |
流程图补充
graph LR
A[电源调节器操作] --> B[电压设置]
A --> C[电流限制设置]
A --> D[操作模式设置]
E[帧缓冲驱动操作] --> F[设备探测与初始化]
E --> G[设备操作(读写、显示等)]
E --> H[设备移除与清理]
以上内容进一步详细介绍了电源调节器框架和帧缓冲驱动的相关知识,包括操作总结、代码分析、总结与展望等,希望对读者有所帮助。
3330

被折叠的 条评论
为什么被折叠?



