s3c6410(arm11核)的LCD驱动了解一(probe)
s3c6410(arm11核)的LCD驱动理解一(probe)
static int __devinit s3c_fb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
//私有数据结构体
struct s3c_fb_platdata *pd;
struct s3c_fb *sfb;
struct resource *res;
int win;
int ret = 0;
pd = pdev->dev.platform_data;
if (!pd) {
dev_err(dev, "no platform data specified\n");
return -EINVAL;
}
//申请一段struct s3c_fb内存
sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);
if (!sfb) {
dev_err(dev, "no memory for framebuffers\n");
return -ENOMEM;
}
//下面一大段程序就是初始化struct s3c_fb类型结构体sfb
sfb->dev = dev;
sfb->pdata = pd;
//获取时钟结构体bus_clk
sfb->bus_clk = clk_get(dev, "lcd");
//判断该指针是否有效
if (IS_ERR(sfb->bus_clk)) {
dev_err(dev, "failed to get bus clock\n");
goto err_sfb;
}
//使能LCD时钟
clk_enable(sfb->bus_clk);
//IO映射
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "failed to find registers\n");
ret = -ENOENT;
goto err_clk;
}
sfb->regs_res = request_mem_region(res->start, resource_size(res),
dev_name(dev));
if (!sfb->regs_res) {
dev_err(dev, "failed to claim register region\n");
ret = -ENOENT;
goto err_clk;
}
sfb->regs = ioremap(res->start, resource_size(res));
if (!sfb->regs) {
dev_err(dev, "failed to map registers\n");
ret = -ENXIO;
goto err_req_region;
}
dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
/* setup gpio and output polarity controls */
//setup_gpio,这个函数需要在板级配置文件(smdk6410.c)中实现
pd->setup_gpio();
//vidcon1也是要在板级配置文件中配置,看数据手册可知,VIDCON1是LCD控制寄存器
writel(pd->vidcon1, sfb->regs + VIDCON1);
/* zero all windows before we do anything */
//初始化s3c6410的window寄存器
for (win = 0; win < S3C_FB_MAX_WIN; win++)
s3c_fb_clear_win(sfb, win);
/* we have the register setup, start allocating framebuffers */
for (win = 0; win < S3C_FB_MAX_WIN; win++) {
//判断这个win在板级配置文件中是否被配置,若未被配置,跳过此操作
//在我的板级配置文件中是配置成win[0]
if (!pd->win[win])
continue;
//probe最重要的函数,是关于framebuffer的操作
ret = s3c_fb_probe_win(sfb, win, &sfb->windows[win]);
if (ret < 0) {
dev_err(dev, "failed to create window %d\n", win);
for (; win >= 0; win--)
s3c_fb_release_win(sfb, sfb->windows[win]);
goto err_ioremap;
}
}
//把sfb保存为平台设备私有数据,在后面就可以调用platform_get_drvdata获取sfb
platform_set_drvdata(pdev, sfb);
return 0;
err_ioremap:
iounmap(sfb->regs);
err_req_region:
release_resource(sfb->regs_res);
kfree(sfb->regs_res);
err_clk:
clk_disable(sfb->bus_clk);
clk_put(sfb->bus_clk);
err_sfb:
kfree(sfb);
return ret;
}